xForm_containers.py 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. from .node_container_common import *
  2. from bpy.types import Node
  3. from .base_definitions import MantisNode
  4. def TellClasses():
  5. return [
  6. # xForm
  7. xFormRoot,
  8. xFormArmature,
  9. xFormBone,
  10. xFormGeometryObject,
  11. ]
  12. #*#-------------------------------#++#-------------------------------#*#
  13. # X - F O R M N O D E S
  14. #*#-------------------------------#++#-------------------------------#*#
  15. # class xFormNull:
  16. # '''A node representing an Empty object'''
  17. # inputs =
  18. # {
  19. # "Name":None,
  20. # "Rotation Order":None,
  21. # "Matrix":None,
  22. # "Relationship":None,
  23. # }
  24. # outputs =
  25. # {
  26. # "xFormOut":None,
  27. # }
  28. # parameters =
  29. # {
  30. # "Name":None,
  31. # "Rotation Order":None,
  32. # "Matrix":None,
  33. # "Relationship":None,
  34. # }
  35. # def evaluate_input(self, input):
  36. # pass
  37. # def instantiate_blender_object(self):
  38. # pass
  39. class xFormRoot:
  40. '''A node representing the root of the scene.'''
  41. def __init__(self, signature, base_tree):
  42. self.base_tree=base_tree
  43. self.signature = signature
  44. self.inputs = {}
  45. self.outputs = {"World Out":NodeSocket(name="World Out", node = self),}
  46. self.parameters = {}
  47. self.node_type = 'XFORM'
  48. self.hierarchy_connections = []
  49. self.connections = []
  50. self.hierarchy_dependencies = []
  51. self.dependencies = []
  52. self.prepared = True
  53. self.executed = True
  54. class xFormArmature:
  55. '''A node representing an armature object'''
  56. bObject = None
  57. def __init__(self, signature, base_tree):
  58. self.base_tree=base_tree
  59. self.signature = signature
  60. self.inputs = {
  61. "Name" : NodeSocket(is_input = True, name = "Name", node = self),
  62. "Rotation Order" : NodeSocket(is_input = True, name = "Rotation Order", node = self),
  63. "Matrix" : NodeSocket(is_input = True, name = "Matrix", node = self),
  64. "Relationship" : NodeSocket(is_input = True, name = "Relationship", node = self),
  65. }
  66. self.outputs = {
  67. "xForm Out" : NodeSocket(name="xForm Out", node = self),
  68. }
  69. self.parameters = {
  70. "Name":None,
  71. "Rotation Order":None,
  72. "Matrix":None,
  73. "Relationship":None,
  74. }
  75. self.links = {} # leave this empty for now!
  76. # now set up the traverse target...
  77. self.inputs["Relationship"].set_traverse_target(self.outputs["xForm Out"])
  78. self.outputs["xForm Out"].set_traverse_target(self.inputs["Relationship"])
  79. self.node_type = 'XFORM'
  80. self.hierarchy_connections = []
  81. self.connections = []
  82. self.hierarchy_dependencies = []
  83. self.dependencies = []
  84. self.prepared = True
  85. self.executed = False
  86. def bExecute(self, bContext = None,):
  87. # from .utilities import get_node_prototype
  88. import bpy
  89. if (not isinstance(bContext, bpy.types.Context)):
  90. raise RuntimeError("Incorrect context")
  91. name = self.evaluate_input("Name")
  92. if not ( matrix := self.evaluate_input('Matrix')):
  93. raise RuntimeError(wrapRed(f"No matrix found for Armature {self}"))
  94. self.parameters['Matrix'] = matrix
  95. reset_transforms = False
  96. #check if an object by the name exists
  97. if (name) and (ob := bpy.data.objects.get(name)):
  98. if (ob.animation_data):
  99. while (ob.animation_data.drivers):
  100. ob.animation_data.drivers.remove(ob.animation_data.drivers[-1])
  101. for pb in ob.pose.bones:
  102. # clear it, even after deleting the edit bones,
  103. # if we create them again the pose bones will be reused
  104. while (pb.constraints):
  105. pb.constraints.remove(pb.constraints[-1])
  106. if reset_transforms:
  107. pb.location = (0,0,0)
  108. pb.rotation_euler = (0,0,0)
  109. pb.rotation_quaternion = (1.0,0,0,0)
  110. pb.rotation_axis_angle = (0,0,1.0,0)
  111. pb.scale = (1.0,1.0,1.0)
  112. # feels ugly and bad, whatever
  113. collections = []
  114. for bc in ob.data.collections:
  115. collections.append(bc)
  116. for bc in collections:
  117. ob.data.collections.remove(bc)
  118. del collections
  119. # end ugly/bad
  120. else:
  121. # Create the Object
  122. ob = bpy.data.objects.new(name, bpy.data.armatures.new(name)) #create ob
  123. if (ob.name != name):
  124. raise RuntimeError("Could not create xForm object", name)
  125. self.bObject = ob.name
  126. ob.matrix_world = matrix.copy()
  127. # # first, get the parent object
  128. # parent_node = get_parent(self)
  129. # if hasattr(parent_node, "bObject"):
  130. # # this won't work of course, TODO
  131. # ob.parent = parent_node.bObject
  132. # # print (self.bObject)
  133. if True:
  134. from bpy.types import EditBone
  135. parent_nc = get_parent(self, type='LINK')
  136. if parent_nc:
  137. parent = parent_nc.inputs['Parent'].links[0].from_node.bGetObject(mode = 'OBJECT')
  138. ob.parent = parent
  139. # Link to Scene:
  140. if (ob.name not in bContext.view_layer.active_layer_collection.collection.objects):
  141. bContext.view_layer.active_layer_collection.collection.objects.link(ob)
  142. #self.bParent(bContext)
  143. print( wrapGreen("Created Armature object: ")+ wrapWhite(ob.name))
  144. # Finalize the action
  145. # oddly, overriding context doesn't seem to work
  146. try:
  147. bpy.ops.object.select_all(action='DESELECT')
  148. except RuntimeError:
  149. pass # we're already in edit mode, should be OK to do this.
  150. bContext.view_layer.objects.active = ob
  151. selected=[]
  152. for other_ob in bpy.data.objects:
  153. if other_ob.mode == "EDIT":
  154. selected.append(other_ob)
  155. selected.append(ob)
  156. context_override = {"active_object":ob, "selected_objects":selected}
  157. print("Changing Armature Mode to " +wrapPurple("EDIT"))
  158. with bContext.temp_override(**context_override):
  159. bpy.ops.object.mode_set(mode='EDIT')
  160. if ob.mode != "EDIT":
  161. prRed("eh?")
  162. # clear it
  163. while (len(ob.data.edit_bones) > 0):
  164. ob.data.edit_bones.remove(ob.data.edit_bones[0])
  165. # bContext.view_layer.objects.active = prevAct
  166. self.executed = True
  167. # # not used yet
  168. # #
  169. # def bFinalize(self, bContext = None):
  170. # import bpy
  171. # ob = self.bGetObject()
  172. # prevAct = bContext.view_layer.objects.active
  173. # bContext.view_layer.objects.active = ob
  174. # bpy.ops.object.mode_set(mode='OBJECT')
  175. # print ("Changing Armature Mode to OBJECT")
  176. # bContext.view_layer.objects.active = prevAct
  177. def bGetObject(self, mode = ''):
  178. import bpy; return bpy.data.objects[self.bObject]
  179. bone_inputs= [
  180. "Name",
  181. "Rotation Order",
  182. "Matrix",
  183. "Relationship",
  184. # IK settings
  185. "IK Stretch",
  186. "Lock IK",
  187. "IK Stiffness",
  188. "Limit IK",
  189. "X Min",
  190. "X Max",
  191. "Y Min",
  192. "Y Max",
  193. "Z Min",
  194. "Z Max",
  195. # Visual stuff
  196. "Bone Collection",
  197. "Hide",
  198. "Custom Object",
  199. "Custom Object xForm Override",
  200. "Custom Object Scale to Bone Length",
  201. "Custom Object Wireframe",
  202. "Custom Object Scale",
  203. "Custom Object Translation",
  204. "Custom Object Rotation",
  205. # Deform Stuff
  206. "Deform",
  207. "Envelope Distance",
  208. "Envelope Weight",
  209. "Envelope Multiply",
  210. "Envelope Head Radius",
  211. "Envelope Tail Radius",
  212. # BBone stuff:
  213. "BBone Segments",
  214. "BBone X Size",
  215. "BBone Z Size",
  216. "BBone HQ Deformation",
  217. "BBone X Curve-In",
  218. "BBone Z Curve-In",
  219. "BBone X Curve-Out",
  220. "BBone Z Curve-Out",
  221. "BBone Roll-In",
  222. "BBone Roll-Out",
  223. "BBone Inherit End Roll",
  224. "BBone Scale-In",
  225. "BBone Scale-Out",
  226. "BBone Ease-In",
  227. "BBone Ease-Out",
  228. "BBone Easing",
  229. "BBone Start Handle Type",
  230. "BBone Custom Start Handle",
  231. "BBone Start Handle Scale",
  232. "BBone Start Handle Ease",
  233. "BBone End Handle Type",
  234. "BBone Custom End Handle",
  235. "BBone End Handle Scale",
  236. "BBone End Handle Ease",
  237. # locks
  238. "Lock Location",
  239. "Lock Rotation",
  240. "Lock Scale",
  241. ]
  242. class xFormBone:
  243. '''A node representing a bone in an armature'''
  244. # DO: make a way to identify which armature this belongs to
  245. def __init__(self, signature, base_tree):
  246. self.base_tree=base_tree
  247. self.signature = signature
  248. self.inputs = {
  249. "Name" : NodeSocket(is_input = True, name = "Name", node = self,),
  250. "Rotation Order" : NodeSocket(is_input = True, name = "Rotation Order", node = self,),
  251. "Matrix" : NodeSocket(is_input = True, name = "Matrix", node = self,),
  252. "Relationship" : NodeSocket(is_input = True, name = "Relationship", node = self,),
  253. # IK settings
  254. "IK Stretch" : NodeSocket(is_input = True, name = "IK Stretch", node = self,),
  255. "Lock IK" : NodeSocket(is_input = True, name = "Lock IK", node = self,),
  256. "IK Stiffness" : NodeSocket(is_input = True, name = "IK Stiffness", node = self,),
  257. "Limit IK" : NodeSocket(is_input = True, name = "Limit IK", node = self,),
  258. "X Min" : NodeSocket(is_input = True, name = "X Min", node = self,),
  259. "X Max" : NodeSocket(is_input = True, name = "X Max", node = self,),
  260. "Y Min" : NodeSocket(is_input = True, name = "Y Min", node = self,),
  261. "Y Max" : NodeSocket(is_input = True, name = "Y Max", node = self,),
  262. "Z Min" : NodeSocket(is_input = True, name = "Z Min", node = self,),
  263. "Z Max" : NodeSocket(is_input = True, name = "Z Max", node = self,),
  264. # Visual stuff
  265. "Bone Collection" : NodeSocket(is_input = True, name = "Bone Collection", node = self,),
  266. "Hide" : NodeSocket(is_input = True, name = "Hide", node = self,),
  267. "Custom Object" : NodeSocket(is_input = True, name = "Custom Object", node = self,),
  268. "Custom Object xForm Override" : NodeSocket(is_input = True, name = "Custom Object xForm Override", node = self,),
  269. "Custom Object Scale to Bone Length" : NodeSocket(is_input = True, name = "Custom Object Scale to Bone Length", node = self,),
  270. "Custom Object Wireframe" : NodeSocket(is_input = True, name = "Custom Object Wireframe", node = self,),
  271. "Custom Object Scale" : NodeSocket(is_input = True, name = "Custom Object Scale", node = self,),
  272. "Custom Object Translation" : NodeSocket(is_input = True, name = "Custom Object Translation", node = self,),
  273. "Custom Object Rotation" : NodeSocket(is_input = True, name = "Custom Object Rotation", node = self,),
  274. # Deform Stuff
  275. "Deform" : NodeSocket(is_input = True, name = "Deform", node = self,),
  276. "Envelope Distance" : NodeSocket(is_input = True, name = "Envelope Distance", node = self,),
  277. "Envelope Weight" : NodeSocket(is_input = True, name = "Envelope Weight", node = self,),
  278. "Envelope Multiply" : NodeSocket(is_input = True, name = "Envelope Multiply", node = self,),
  279. "Envelope Head Radius" : NodeSocket(is_input = True, name = "Envelope Head Radius", node = self,),
  280. "Envelope Tail Radius" : NodeSocket(is_input = True, name = "Envelope Tail Radius", node = self,),
  281. # BBone stuff:
  282. "BBone Segments" : NodeSocket(is_input = True, name = "BBone Segments", node=self,),
  283. "BBone X Size" : NodeSocket(is_input = True, name = "BBone X Size", node=self,),
  284. "BBone Z Size" : NodeSocket(is_input = True, name = "BBone Z Size", node=self,),
  285. "BBone HQ Deformation" : NodeSocket(is_input = True, name = "BBone HQ Deformation", node=self,),
  286. "BBone X Curve-In" : NodeSocket(is_input = True, name = "BBone X Curve-In", node=self,),
  287. "BBone Z Curve-In" : NodeSocket(is_input = True, name = "BBone Z Curve-In", node=self,),
  288. "BBone X Curve-Out" : NodeSocket(is_input = True, name = "BBone X Curve-Out", node=self,),
  289. "BBone Z Curve-Out" : NodeSocket(is_input = True, name = "BBone Z Curve-Out", node=self,),
  290. "BBone Roll-In" : NodeSocket(is_input = True, name = "BBone Roll-In", node=self,),
  291. "BBone Roll-Out" : NodeSocket(is_input = True, name = "BBone Roll-Out", node=self,),
  292. "BBone Inherit End Roll" : NodeSocket(is_input = True, name = "BBone Inherit End Roll", node=self,),
  293. "BBone Scale-In" : NodeSocket(is_input = True, name = "BBone Scale-In", node=self,),
  294. "BBone Scale-Out" : NodeSocket(is_input = True, name = "BBone Scale-Out", node=self,),
  295. "BBone Ease-In" : NodeSocket(is_input = True, name = "BBone Ease-In", node=self,),
  296. "BBone Ease-Out" : NodeSocket(is_input = True, name = "BBone Ease-Out", node=self,),
  297. "BBone Easing" : NodeSocket(is_input = True, name = "BBone Easing", node=self,),
  298. "BBone Start Handle Type" : NodeSocket(is_input = True, name = "BBone Start Handle Type", node=self,),
  299. "BBone Custom Start Handle" : NodeSocket(is_input = True, name = "BBone Custom Start Handle", node=self,),
  300. "BBone Start Handle Scale" : NodeSocket(is_input = True, name = "BBone Start Handle Scale", node=self,),
  301. "BBone Start Handle Ease" : NodeSocket(is_input = True, name = "BBone Start Handle Ease", node=self,),
  302. "BBone End Handle Type" : NodeSocket(is_input = True, name = "BBone End Handle Type", node=self,),
  303. "BBone Custom End Handle" : NodeSocket(is_input = True, name = "BBone Custom End Handle", node=self,),
  304. "BBone End Handle Scale" : NodeSocket(is_input = True, name = "BBone End Handle Scale", node=self,),
  305. "BBone End Handle Ease" : NodeSocket(is_input = True, name = "BBone End Handle Ease", node=self,),
  306. # locks
  307. "Lock Location" : NodeSocket(is_input = True, name = "Lock Location", node = self,),
  308. "Lock Rotation" : NodeSocket(is_input = True, name = "Lock Rotation", node = self,),
  309. "Lock Scale" : NodeSocket(is_input = True, name = "Lock Scale", node = self,),
  310. }
  311. self.outputs = {
  312. "xForm Out" : NodeSocket(name = "xForm Out", node = self),
  313. }
  314. self.parameters = {
  315. "Name":None,
  316. "Rotation Order":None,
  317. "Matrix":None,
  318. "Relationship":None,
  319. # IK settings
  320. "IK Stretch":None,
  321. "Lock IK":None,
  322. "IK Stiffness":None,
  323. "Limit IK":None,
  324. "X Min":None,
  325. "X Max":None,
  326. "Y Min":None,
  327. "Y Max":None,
  328. "Z Min":None,
  329. "Z Max":None,
  330. "Hide":None,
  331. "Bone Collection":None,
  332. "Hide":None,
  333. "Custom Object":None,
  334. "Custom Object xForm Override":None,
  335. "Custom Object Scale to Bone Length":None,
  336. "Custom Object Wireframe":None,
  337. "Custom Object Scale":None,
  338. "Custom Object Translation":None,
  339. "Custom Object Rotation":None,
  340. "Deform" : None,
  341. "Envelope Distance" : None,
  342. "Envelope Weight" : None,
  343. "Envelope Multiply" : None,
  344. "Envelope Head Radius" : None,
  345. "Envelope Tail Radius" : None,
  346. #
  347. "BBone Segments" : None,
  348. "BBone X Size" : None,
  349. "BBone Z Size" : None,
  350. "BBone HQ Deformation" : None,
  351. "BBone X Curve-In" : None,
  352. "BBone Z Curve-In" : None,
  353. "BBone X Curve-Out" : None,
  354. "BBone Z Curve-Out" : None,
  355. "BBone Roll-In" : None,
  356. "BBone Roll-Out" : None,
  357. "BBone Inherit End Roll" : None,
  358. "BBone Scale-In" : None,
  359. "BBone Scale-Out" : None,
  360. "BBone Ease-In" : None,
  361. "BBone Ease-Out" : None,
  362. "BBone Easing" : None,
  363. "BBone Start Handle Type" : None,
  364. "BBone Custom Start Handle" : None,
  365. "BBone Start Handle Scale" : None,
  366. "BBone Start Handle Ease" : None,
  367. "BBone End Handle Type" : None,
  368. "BBone Custom End Handle" : None,
  369. "BBone End Handle Scale" : None,
  370. "BBone End Handle Ease" : None,
  371. #
  372. "Lock Location" : None,
  373. "Lock Rotation" : None,
  374. "Lock Scale" : None,
  375. }
  376. self.links = {} # leave this empty for now!
  377. # now set up the traverse target...
  378. self.inputs["Relationship"].set_traverse_target(self.outputs["xForm Out"])
  379. self.outputs["xForm Out"].set_traverse_target(self.inputs["Relationship"])
  380. self.node_type = 'XFORM'
  381. self.hierarchy_connections = []
  382. self.connections = []
  383. self.hierarchy_dependencies = []
  384. self.dependencies = []
  385. self.prepared = True
  386. self.executed = False
  387. self.input_length = len(self.inputs) # HACK HACK HACK
  388. def bGetParentArmature(self):
  389. finished = False
  390. if (trace := trace_single_line(self, "Relationship")[0] ) :
  391. for i in range(len(trace)):
  392. # have to look in reverse, actually
  393. if ( isinstance(trace[ i ], xFormArmature ) ):
  394. return trace[ i ].bGetObject()
  395. return None
  396. #should do the trick...
  397. def bSetParent(self, eb):
  398. # print (self.bObject)
  399. from bpy.types import EditBone
  400. parent_nc = get_parent(self, type='LINK')
  401. # print (self, parent_nc.inputs['Parent'].from_node)
  402. parent=None
  403. if parent_nc.inputs['Parent'].links[0].from_node.node_type == 'XFORM':
  404. parent = parent_nc.inputs['Parent'].links[0].from_node.bGetObject(mode = 'EDIT')
  405. else:
  406. raise RuntimeError(wrapRed(f"Cannot set parent for node {self}"))
  407. if isinstance(parent, EditBone):
  408. eb.parent = parent
  409. #DUMMY
  410. # I NEED TO GET THE LINK NC
  411. # IDIOT
  412. eb.use_connect = parent_nc.evaluate_input("Connected")
  413. eb.use_inherit_rotation = parent_nc.evaluate_input("Inherit Rotation")
  414. eb.inherit_scale = parent_nc.evaluate_input("Inherit Scale")
  415. # otherwise, no need to do anything.
  416. def bExecute(self, bContext = None,): #possibly will need to pass context?
  417. import bpy
  418. from mathutils import Vector
  419. if not (name := self.evaluate_input("Name")):
  420. raise RuntimeError(wrapRed(f"Could not set name for bone in {self}"))
  421. if (not isinstance(bContext, bpy.types.Context)):
  422. raise RuntimeError("Incorrect context")
  423. if not (xF := self.bGetParentArmature()):
  424. raise RuntimeError("Could not create edit bone: ", name, " from node:", self.signature, " Reason: No armature object to add bone to.")
  425. if not ( matrix := self.evaluate_input('Matrix')):
  426. # print(self.inputs['Matrix'].links[0].from_node.parameters)
  427. raise RuntimeError(wrapRed(f"No matrix found for Bone {self}"))
  428. self.parameters['Matrix'] = matrix
  429. length = matrix[3][3]
  430. if (xF):
  431. if (xF.mode != "EDIT"):
  432. raise RuntimeError("Armature Object Not in Edit Mode, exiting...")
  433. #
  434. # Create the Object
  435. d = xF.data
  436. eb = d.edit_bones.new(name)
  437. # Bone Collections:
  438. # We treat each separate string as a Bone Collection that this object belongs to
  439. # Bone Collections are fully qualified by their hierarchy.
  440. # Separate Strings with "|" and indicate hierarchy with ">". These are special characters.
  441. # NOTE: if the user names the collections differently at different times, this will take the FIRST definition and go with it
  442. sCols = self.evaluate_input("Bone Collection")
  443. bone_collections = sCols.split("|")
  444. for collection_list in bone_collections:
  445. hierarchy = collection_list.split(">")
  446. col_parent = None
  447. for sCol in hierarchy:
  448. if ( col := d.collections.get(sCol) ) is None:
  449. col = d.collections.new(sCol)
  450. col.parent = col_parent
  451. col_parent = col
  452. col.assign(eb)
  453. if (eb.name != name):
  454. prRed(f"Expected bone of name: {name}, got {eb.name} instead.")
  455. raise RuntimeError("Could not create bone ", name, "; Perhaps there is a duplicate bone name in the node tree?")
  456. eb.matrix = matrix.copy()
  457. tailoffset = Vector((0,length,0)) #Vector((0,self.tailoffset, 0))
  458. tailoffset = matrix.copy().to_3x3() @ tailoffset
  459. eb.tail = eb.head + tailoffset
  460. if eb.head == eb.tail:
  461. raise RuntimeError(wrapRed(f"Could not create edit bone: {name} because bone head was located in the same place as bone tail."))
  462. if (eb.name != name):
  463. raise RuntimeError("Could not create edit bone: ", name)
  464. assert (eb.name), "Bone must have a name."
  465. self.bObject = eb.name
  466. # The bone should have relationships going in at this point.
  467. assert (self.bObject), "eh? %s" % eb.name
  468. self.bSetParent(eb)
  469. # Setup Deform attributes...
  470. eb.use_deform = self.evaluate_input("Deform")
  471. eb.envelope_distance = self.evaluate_input("Envelope Distance")
  472. eb.envelope_weight = self.evaluate_input("Envelope Weight")
  473. eb.use_envelope_multiply = self.evaluate_input("Envelope Multiply")
  474. eb.head_radius = self.evaluate_input("Envelope Head Radius")
  475. eb.tail_radius = self.evaluate_input("Envelope Tail Radius")
  476. print( wrapGreen("Created Bone: ") + wrapOrange(eb.name) + wrapGreen(" in ") + wrapWhite(self.bGetParentArmature().name))
  477. self.executed = True
  478. def bFinalize(self, bContext = None):
  479. do_bb=False
  480. b = self.bGetParentArmature().data.bones[self.bObject]
  481. b.bbone_x = self.evaluate_input("BBone X Size"); b.bbone_x = max(b.bbone_x, 0.0002)
  482. b.bbone_z = self.evaluate_input("BBone Z Size"); b.bbone_z = max(b.bbone_z, 0.0002)
  483. if (segs := self.evaluate_input("BBone Segments")) > 1:
  484. do_bb=True
  485. b.bbone_segments = segs
  486. b.bbone_x = self.evaluate_input("BBone X Size")
  487. b.bbone_z = self.evaluate_input("BBone Z Size")
  488. if self.evaluate_input("BBone HQ Deformation"):
  489. b.bbone_mapping_mode = "CURVED"
  490. # 'bbone_handle_type_start' : ("BBone Start Handle Type", "AUTO"),
  491. # 'bbone_handle_type_end' : ("BBone End Handle Type", "AUTO"),
  492. # 'bbone_custom_handle_start' : ("BBone Custom Start Handle", "AUTO"),
  493. # 'bbone_custom_handle_end' : ("BBone Custom End Handle", "AUTO"),
  494. if handle_type := self.evaluate_input("BBone Start Handle Type"):
  495. b.bbone_handle_type_start = handle_type
  496. if handle_type := self.evaluate_input("BBone End Handle Type"):
  497. b.bbone_handle_type_end = handle_type
  498. try:
  499. if (custom_handle := self.evaluate_input("BBone Custom Start Handle")):
  500. b.bbone_custom_handle_start = self.bGetParentArmature().data.bones[custom_handle]
  501. # hypothetically we should support xForm inputs.... but we won't do that for now
  502. # elif custom_handle is None:
  503. # b.bbone_custom_handle_start = self.inputs["BBone Custom Start Handle"].links[0].from_node.bGetObject().name
  504. if (custom_handle := self.evaluate_input("BBone Custom End Handle")):
  505. b.bbone_custom_handle_end = self.bGetParentArmature().data.bones[custom_handle]
  506. except KeyError:
  507. prRed("Warning: BBone start or end handle not set because of missing bone in armature.")
  508. b.bbone_curveinx = self.evaluate_input("BBone X Curve-In")
  509. b.bbone_curveinz = self.evaluate_input("BBone Z Curve-In")
  510. b.bbone_curveoutx = self.evaluate_input("BBone X Curve-Out")
  511. b.bbone_curveoutz = self.evaluate_input("BBone Z Curve-Out")
  512. # 'bbone_curveinx' : ("BBone X Curve-In", pb.bone.bbone_curveinx),
  513. # 'bbone_curveinz' : ("BBone Z Curve-In", pb.bone.bbone_curveinz),
  514. # 'bbone_curveoutx' : ("BBone X Curve-Out", pb.bone.bbone_curveoutx),
  515. # 'bbone_curveoutz' : ("BBone Z Curve-Out", pb.bone.bbone_curveoutz),
  516. import bpy
  517. from .drivers import MantisDriver
  518. # prevAct = bContext.view_layer.objects.active
  519. # bContext.view_layer.objects.active = ob
  520. # bpy.ops.object.mode_set(mode='OBJECT')
  521. # bContext.view_layer.objects.active = prevAct
  522. #
  523. #get relationship
  524. # ensure we have a pose bone...
  525. # set the ik parameters
  526. #
  527. #
  528. # Don't need to bother about whatever that was
  529. pb = self.bGetParentArmature().pose.bones[self.bObject]
  530. rotation_mode = self.evaluate_input("Rotation Order")
  531. if rotation_mode == "AUTO": rotation_mode = "XYZ"
  532. pb.rotation_mode = rotation_mode
  533. pb.id_properties_clear()
  534. # these are kept around unless explicitly deleted.
  535. # from .utilities import get_node_prototype
  536. # np = get_node_prototype(self.signature, self.base_tree)
  537. driver = None
  538. do_prints=False
  539. # print (self.input_length)
  540. # even worse hack coming
  541. for i, inp in enumerate(self.inputs.values()):
  542. if inp.name in bone_inputs:
  543. continue
  544. name = inp.name
  545. try:
  546. value = self.evaluate_input(inp.name)
  547. except KeyError as e:
  548. trace = trace_single_line(self, inp.name)
  549. if do_prints: print(trace[0][-1], trace[1])
  550. if do_prints: print (trace[0][-1].parameters)
  551. raise e
  552. # This may be driven, so let's do this:
  553. if do_prints: print (value)
  554. if (isinstance(value, tuple)):
  555. # it's either a CombineThreeBool or a CombineVector.
  556. prRed("COMITTING SUICIDE NOW!!")
  557. bpy.ops.wm.quit_blender()
  558. if (isinstance(value, MantisDriver)):
  559. # the value should be the default for its socket...
  560. if do_prints: print (type(self.parameters[inp.name]))
  561. type_val_map = {
  562. str:"",
  563. bool:False,
  564. int:0,
  565. float:0.0,
  566. bpy.types.bpy_prop_array:(0,0,0),
  567. }
  568. driver = value
  569. value = type_val_map[type(self.parameters[inp.name])]
  570. if (value is None):
  571. prRed("This is probably not supposed to happen")
  572. value = 0
  573. raise RuntimeError("Could not set value of custom parameter")
  574. # it creates a more confusing error later sometimes, better to catch it here.
  575. # IMPORTANT: Is it possible for more than one driver to
  576. # come through here, and for the variable to be
  577. # overwritten?
  578. #TODO important
  579. #from rna_prop_ui import rna_idprop_ui_create
  580. # use this ^
  581. # add the custom properties to the **Pose Bone**
  582. pb[name] = value
  583. # This is much simpler now.
  584. ui_data = pb.id_properties_ui(name)
  585. description=''
  586. ui_data.update(
  587. description=description,#inp.description,
  588. default=value,)
  589. #if a number
  590. if type(value) == float:
  591. ui_data.update(
  592. min = inp.min,
  593. max = inp.max,
  594. soft_min = inp.soft_min,
  595. soft_max = inp.soft_max,)
  596. elif type(value) == int:
  597. ui_data.update(
  598. min = int(inp.min),
  599. max = int(inp.max),
  600. soft_min = int(inp.soft_min),
  601. soft_max = int(inp.soft_max),)
  602. elif type(value) == bool:
  603. ui_data.update() # TODO I can't figure out what the update function expects because it isn't documented
  604. if (pb.is_in_ik_chain):
  605. # this props_socket thing wasn't really meant to work here but it does, neat
  606. props_sockets = {
  607. 'ik_stretch' : ("IK Stretch", 0),
  608. 'lock_ik_x' : (("Lock IK", 0), False),
  609. 'lock_ik_y' : (("Lock IK", 1), False),
  610. 'lock_ik_z' : (("Lock IK", 2), False),
  611. 'ik_stiffness_x' : (("IK Stiffness", 0), 0.0),
  612. 'ik_stiffness_y' : (("IK Stiffness", 1), 0.0),
  613. 'ik_stiffness_z' : (("IK Stiffness", 2), 0.0),
  614. 'use_ik_limit_x' : (("Limit IK", 0), False),
  615. 'use_ik_limit_y' : (("Limit IK", 1), False),
  616. 'use_ik_limit_z' : (("Limit IK", 2), False),
  617. 'ik_min_x' : ("X Min", 0),
  618. 'ik_max_x' : ("X Max", 0),
  619. 'ik_min_y' : ("Y Min", 0),
  620. 'ik_max_y' : ("Y Max", 0),
  621. 'ik_min_z' : ("Z Min", 0),
  622. 'ik_max_z' : ("Z Max", 0),
  623. }
  624. evaluate_sockets(self, pb, props_sockets)
  625. if do_bb:
  626. props_sockets = {
  627. 'bbone_curveinx' : ("BBone X Curve-In", pb.bone.bbone_curveinx),
  628. 'bbone_curveinz' : ("BBone Z Curve-In", pb.bone.bbone_curveinz),
  629. 'bbone_curveoutx' : ("BBone X Curve-Out", pb.bone.bbone_curveoutx),
  630. 'bbone_curveoutz' : ("BBone Z Curve-Out", pb.bone.bbone_curveoutz),
  631. 'bbone_easein' : ("BBone Ease-In", 0),
  632. 'bbone_easeout' : ("BBone Ease-Out", 0),
  633. 'bbone_rollin' : ("BBone Roll-In", 0),
  634. 'bbone_rollout' : ("BBone Roll-Out", 0),
  635. 'bbone_scalein' : ("BBone Scale-In", (1,1,1)),
  636. 'bbone_scaleout' : ("BBone Scale-Out", (1,1,1)),
  637. }
  638. prRed("BBone Implementation is not complete, expect errors and missing features for now")
  639. evaluate_sockets(self, pb, props_sockets)
  640. # we need to clear this stuff since our only real goal was to get some drivers from the above
  641. for attr_name in props_sockets.keys():
  642. try:
  643. setattr(pb, attr_name, 0) # just clear it
  644. except ValueError:
  645. setattr(pb, attr_name, (1.0,1.0,1.0)) # scale needs to be set to 1
  646. # important TODO... all of the drivers and stuff should be handled this way, right?
  647. # time to set up drivers!
  648. # just gonna add this to the end and build off it I guess
  649. props_sockets = {
  650. "lock_location" : ("Lock Location", [False, False, False]),
  651. "lock_rotation" : ("Lock Rotation", [False, False, False]),
  652. "lock_scale" : ("Lock Scale", [False, False, False]),
  653. 'custom_shape_scale_xyz' : ("Custom Object Scale", (0.0,0.0,0.0) ),
  654. 'custom_shape_translation' : ("Custom Object Translation", (0.0,0.0,0.0) ),
  655. 'custom_shape_rotation_euler' : ("Custom Object Rotation", (0.0,0.0,0.0) ),
  656. 'use_custom_shape_bone_size' : ("Custom Object Scale to Bone Length", True,)
  657. }
  658. evaluate_sockets(self, pb, props_sockets)
  659. # this could probably be moved to bExecute
  660. props_sockets = {
  661. 'hide' : ("Hide", False),
  662. 'show_wire' : ("Custom Object Wireframe", False),
  663. }
  664. evaluate_sockets(self, pb.bone, props_sockets)
  665. if (driver):
  666. pass
  667. # whatever I was doing there.... was stupid. CLEAN UP TODO
  668. # this is the right thing to do.
  669. finish_drivers(self)
  670. #
  671. # OK, visual settings
  672. #
  673. # Get the override xform's bone:
  674. if len(self.inputs["Custom Object xForm Override"].links) > 0:
  675. trace = trace_single_line(self, "Custom Object xForm Override")
  676. try:
  677. pb.custom_shape_transform = trace[0][1].bGetObject()
  678. except AttributeError:
  679. pass
  680. if len(self.inputs["Custom Object"].links) > 0:
  681. trace = trace_single_line(self, "Custom Object")
  682. try:
  683. ob = trace[0][1].bGetObject()
  684. except AttributeError:
  685. ob=None
  686. if type(ob) in [bpy.types.Object]:
  687. pb.custom_shape = ob
  688. #
  689. # pb.bone.hide = self.evaluate_input("Hide")
  690. # pb.custom_shape_scale_xyz = self.evaluate_input("Custom Object Scale")
  691. # pb.custom_shape_translation = self.evaluate_input("Custom Object Translation")
  692. # pb.custom_shape_rotation_euler = self.evaluate_input("Custom Object Rotation")
  693. # pb.use_custom_shape_bone_size = self.evaluate_input("Custom Object Scale to Bone Length")
  694. # pb.bone.show_wire = self.evaluate_input("Custom Object Wireframe")
  695. # #
  696. # # D E P R E C A T E D
  697. # #
  698. # # Bone Groups
  699. # if bg_name := self.evaluate_input("Bone Group"): # this is a string
  700. # obArm = self.bGetParentArmature()
  701. # # Temporary! Temporary! HACK
  702. # color_set_items= [
  703. # "DEFAULT",
  704. # "THEME01",
  705. # "THEME02",
  706. # "THEME03",
  707. # "THEME04",
  708. # "THEME05",
  709. # "THEME06",
  710. # "THEME07",
  711. # "THEME08",
  712. # "THEME09",
  713. # "THEME10",
  714. # "THEME11",
  715. # "THEME12",
  716. # "THEME13",
  717. # "THEME14",
  718. # "THEME15",
  719. # "THEME16",
  720. # "THEME17",
  721. # "THEME18",
  722. # "THEME19",
  723. # "THEME20",
  724. # # "CUSTOM",
  725. # ]
  726. # try:
  727. # bg = obArm.pose.bone_groups.get(bg_name)
  728. # except SystemError:
  729. # bg = None
  730. # pass # no clue why this happens. uninitialzied?
  731. # if not bg:
  732. # bg = obArm.pose.bone_groups.new(name=bg_name)
  733. # #HACK lol
  734. # from random import randint
  735. # bg.color_set = color_set_items[randint(0,14)]
  736. # #15-20 are black by default, gross
  737. # # this is good enough for now!
  738. # pb.bone_group = bg
  739. def bGetObject(self, mode = 'POSE'):
  740. try:
  741. if (mode == 'EDIT'):
  742. return self.bGetParentArmature().data.edit_bones[self.bObject]
  743. elif (mode == 'OBJECT'):
  744. return self.bGetParentArmature().data.bones[self.bObject]
  745. elif (mode == 'POSE'):
  746. return self.bGetParentArmature().pose.bones[self.bObject]
  747. except Exception as e:
  748. prRed ("Cannot get bone for %s" % self)
  749. raise e
  750. def fill_parameters(self):
  751. # this is the fill_parameters that is run if it isn't a schema
  752. setup_custom_props(self)
  753. fill_parameters(self)
  754. # otherwise we will do this from the schema
  755. class xFormGeometryObject:
  756. '''A node representing an armature object'''
  757. bObject = None
  758. def __init__(self, signature, base_tree):
  759. self.base_tree=base_tree
  760. self.signature = signature
  761. self.inputs = {
  762. "Name" : NodeSocket(is_input = True, name = "Name", node = self),
  763. "Geometry" : NodeSocket(is_input = True, name = "Geometry", node = self),
  764. "Matrix" : NodeSocket(is_input = True, name = "Matrix", node = self),
  765. "Relationship" : NodeSocket(is_input = True, name = "Relationship", node = self),
  766. "Deformer" : NodeSocket(is_input = True, name = "Relationship", node = self),
  767. }
  768. self.outputs = {
  769. "xForm Out" : NodeSocket(is_input = False, name="xForm Out", node = self), }
  770. self.parameters = {
  771. "Name":None,
  772. "Geometry":None,
  773. "Matrix":None,
  774. "Relationship":None,
  775. "Deformer":None,
  776. }
  777. self.links = {} # leave this empty for now!
  778. # now set up the traverse target...
  779. self.inputs["Relationship"].set_traverse_target(self.outputs["xForm Out"])
  780. self.outputs["xForm Out"].set_traverse_target(self.inputs["Relationship"])
  781. self.node_type = "XFORM"
  782. self.bObject = None
  783. self.prepared = True
  784. self.executed = False
  785. def bSetParent(self, ob):
  786. from bpy.types import Object, Bone
  787. parent_nc = get_parent(self, type='LINK')
  788. if (parent_nc):
  789. parent = parent_nc.inputs['Parent'].links[0].from_node
  790. parent_bOb = parent.bGetObject(mode = 'EDIT')
  791. if isinstance(parent_bOb, Bone):
  792. armOb= parent.bGetParentArmature()
  793. ob.parent = armOb
  794. ob.parent_type = 'BONE'
  795. ob.parent_bone = parent_bOb.name
  796. elif isinstance(parent, Object):
  797. ob.parent = parent
  798. # blender will do the matrix math for me IF I set the world
  799. # matrix after setting the parent.
  800. #
  801. # deal with parenting settings here, if necesary
  802. def bPrepare(self, bContext = None,):
  803. import bpy
  804. self.bObject = bpy.data.objects.get(self.evaluate_input("Name"))
  805. if (not self.bObject) or (self.inputs["Geometry"].is_linked and self.bObject.type == "EMPTY"):
  806. trace = trace_single_line(self, "Geometry")
  807. if trace[-1]:
  808. self.bObject = bpy.data.objects.new(self.evaluate_input("Name"), trace[-1].node.bGetObject())
  809. else: # clear it
  810. self.bObject.constraints.clear()
  811. self.bObject.animation_data_clear() # this is a little dangerous.
  812. self.bObject.modifiers.clear()
  813. try:
  814. bpy.context.collection.objects.link(self.bObject)
  815. except RuntimeError: #already in; but a dangerous thing to pass.
  816. pass
  817. self.bSetParent(self.bObject)
  818. matrix = self.evaluate_input("Matrix")
  819. self.parameters['Matrix'] = matrix
  820. self.bObject.matrix_world = matrix
  821. self.executed = True
  822. def bGetObject(self, mode = 'POSE'):
  823. return self.bObject
  824. for c in TellClasses():
  825. setup_container(c)