xForm_containers.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  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. # for whatever reason, the above isn't implemented yet in the node-tree
  40. # so I'm not implementing it here, either
  41. class xFormRoot:
  42. '''A node representing the root of the scene.'''
  43. def __init__(self, signature, base_tree):
  44. self.base_tree=base_tree
  45. self.signature = signature
  46. self.inputs = {}
  47. self.outputs = {"World Out":NodeSocket(name="World Out", node = self),}
  48. self.parameters = {}
  49. self.links = {} # leave this empty for now!
  50. self.node_type = 'XFORM'
  51. def evaluate_input(self, input_name):
  52. return "ROOT"
  53. def bExecute(self, bContext = None,):
  54. pass
  55. def bFinalize(self, bContext = None,):
  56. pass
  57. def __repr__(self):
  58. return self.signature.__repr__()
  59. def fill_parameters(self,):
  60. pass
  61. class xFormArmature:
  62. '''A node representing an armature object'''
  63. bObject = None
  64. def __init__(self, signature, base_tree):
  65. self.base_tree=base_tree
  66. self.executed = False
  67. self.signature = signature
  68. self.inputs = {
  69. "Name" : NodeSocket(is_input = True, name = "Name", node = self),
  70. "Rotation Order" : NodeSocket(is_input = True, name = "Rotation Order", node = self),
  71. "Matrix" : NodeSocket(is_input = True, name = "Matrix", node = self),
  72. "Relationship" : NodeSocket(is_input = True, name = "Relationship", node = self),
  73. }
  74. self.outputs = {
  75. "xForm Out" : NodeSocket(name="xForm Out", node = self),
  76. }
  77. self.parameters = {
  78. "Name":None,
  79. "Rotation Order":None,
  80. "Matrix":None,
  81. "Relationship":None,
  82. }
  83. self.links = {} # leave this empty for now!
  84. # now set up the traverse target...
  85. self.inputs["Relationship"].set_traverse_target(self.outputs["xForm Out"])
  86. self.outputs["xForm Out"].set_traverse_target(self.inputs["Relationship"])
  87. self.node_type = 'XFORM'
  88. def evaluate_input(self, input_name):
  89. return evaluate_input(self, input_name)
  90. def bExecute(self, bContext = None,):
  91. from .utilities import get_node_prototype
  92. import bpy
  93. if (not isinstance(bContext, bpy.types.Context)):
  94. raise RuntimeError("Incorrect context")
  95. name = self.evaluate_input("Name")
  96. matrix = self.evaluate_input('Matrix')
  97. #check if an object by the name exists
  98. if (name) and (ob := bpy.data.objects.get(name)):
  99. if (ob.animation_data):
  100. while (ob.animation_data.drivers):
  101. ob.animation_data.drivers.remove(ob.animation_data.drivers[-1])
  102. for pb in ob.pose.bones:
  103. # clear it, even after deleting the edit bones,
  104. # if we create them again the pose bones will be reused
  105. while (pb.constraints):
  106. pb.constraints.remove(pb.constraints[-1])
  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
  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. def __repr__(self):
  180. return self.signature.__repr__()
  181. def fill_parameters(self,):
  182. fill_parameters(self)
  183. class xFormBone:
  184. '''A node representing a bone in an armature'''
  185. # DO: make a way to identify which armature this belongs to
  186. def __init__(self, signature, base_tree):
  187. self.base_tree=base_tree
  188. self.executed = False
  189. self.signature = signature
  190. self.inputs = {
  191. "Name" : NodeSocket(is_input = True, name = "Name", node = self,),
  192. "Rotation Order" : NodeSocket(is_input = True, name = "Rotation Order", node = self,),
  193. "Matrix" : NodeSocket(is_input = True, name = "Matrix", node = self,),
  194. "Relationship" : NodeSocket(is_input = True, name = "Relationship", node = self,),
  195. # IK settings
  196. "IK Stretch" : NodeSocket(is_input = True, name = "IK Stretch", node = self,),
  197. "Lock IK" : NodeSocket(is_input = True, name = "Lock IK", node = self,),
  198. "IK Stiffness" : NodeSocket(is_input = True, name = "IK Stiffness", node = self,),
  199. "Limit IK" : NodeSocket(is_input = True, name = "Limit IK", node = self,),
  200. "X Min" : NodeSocket(is_input = True, name = "X Min", node = self,),
  201. "X Max" : NodeSocket(is_input = True, name = "X Max", node = self,),
  202. "Y Min" : NodeSocket(is_input = True, name = "Y Min", node = self,),
  203. "Y Max" : NodeSocket(is_input = True, name = "Y Max", node = self,),
  204. "Z Min" : NodeSocket(is_input = True, name = "Z Min", node = self,),
  205. "Z Max" : NodeSocket(is_input = True, name = "Z Max", node = self,),
  206. # Visual stuff
  207. "Bone Collection" : NodeSocket(is_input = True, name = "Bone Collection", node = self,),
  208. "Hide" : NodeSocket(is_input = True, name = "Hide", node = self,),
  209. "Custom Object" : NodeSocket(is_input = True, name = "Custom Object", node = self,),
  210. "Custom Object xForm Override" : NodeSocket(is_input = True, name = "Custom Object xForm Override", node = self,),
  211. "Custom Object Scale to Bone Length" : NodeSocket(is_input = True, name = "Custom Object Scale to Bone Length", node = self,),
  212. "Custom Object Wireframe" : NodeSocket(is_input = True, name = "Custom Object Wireframe", node = self,),
  213. "Custom Object Scale" : NodeSocket(is_input = True, name = "Custom Object Scale", node = self,),
  214. "Custom Object Translation" : NodeSocket(is_input = True, name = "Custom Object Translation", node = self,),
  215. "Custom Object Rotation" : NodeSocket(is_input = True, name = "Custom Object Rotation", node = self,),
  216. # Deform Stuff
  217. "Deform" : NodeSocket(is_input = True, name = "Deform", node = self,),
  218. "Envelope Distance" : NodeSocket(is_input = True, name = "Envelope Distance", node = self,),
  219. "Envelope Weight" : NodeSocket(is_input = True, name = "Envelope Weight", node = self,),
  220. "Envelope Multiply" : NodeSocket(is_input = True, name = "Envelope Multiply", node = self,),
  221. "Envelope Head Radius" : NodeSocket(is_input = True, name = "Envelope Head Radius", node = self,),
  222. "Envelope Tail Radius" : NodeSocket(is_input = True, name = "Envelope Tail Radius", node = self,),
  223. }
  224. self.outputs = {
  225. "xForm Out" : NodeSocket(name = "xForm Out", node = self),
  226. }
  227. self.parameters = {
  228. "Name":None,
  229. "Rotation Order":None,
  230. "Matrix":None,
  231. "Relationship":None,
  232. # IK settings
  233. "IK Stretch":None,
  234. "Lock IK":None,
  235. "IK Stiffness":None,
  236. "Limit IK":None,
  237. "X Min":None,
  238. "X Max":None,
  239. "Y Min":None,
  240. "Y Max":None,
  241. "Z Min":None,
  242. "Z Max":None,
  243. "Hide":None,
  244. "Bone Collection":None,
  245. "Hide":None,
  246. "Custom Object":None,
  247. "Custom Object xForm Override":None,
  248. "Custom Object Scale to Bone Length":None,
  249. "Custom Object Wireframe":None,
  250. "Custom Object Scale":None,
  251. "Custom Object Translation":None,
  252. "Custom Object Rotation":None,
  253. "Deform" : None,
  254. "Envelope Distance" : None,
  255. "Envelope Weight" : None,
  256. "Envelope Multiply" : None,
  257. "Envelope Head Radius" : None,
  258. "Envelope Tail Radius" : None,
  259. }
  260. self.links = {} # leave this empty for now!
  261. # now set up the traverse target...
  262. self.inputs["Relationship"].set_traverse_target(self.outputs["xForm Out"])
  263. self.outputs["xForm Out"].set_traverse_target(self.inputs["Relationship"])
  264. self.node_type = 'XFORM'
  265. setup_custom_props(self)
  266. def evaluate_input(self, input_name):
  267. return evaluate_input(self, input_name)
  268. def __repr__(self):
  269. return self.signature.__repr__()
  270. def fill_parameters(self):
  271. fill_parameters(self)
  272. def bGetParentArmature(self):
  273. finished = False
  274. if (trace := trace_single_line(self, "Relationship")[0] ) :
  275. for i in range(len(trace)):
  276. # have to look in reverse, actually
  277. if ( isinstance(trace[ i ], xFormArmature ) ):
  278. return trace[ i ].bGetObject()
  279. return None
  280. #should do the trick...
  281. def bSetParent(self, eb):
  282. # print (self.bObject)
  283. from bpy.types import EditBone
  284. parent_nc = get_parent(self, type='LINK')
  285. # print (self, parent_nc.inputs['Parent'].from_node)
  286. parent = parent_nc.inputs['Parent'].links[0].from_node.bGetObject(mode = 'EDIT')
  287. if isinstance(parent, EditBone):
  288. eb.parent = parent
  289. #DUMMY
  290. # I NEED TO GET THE LINK NC
  291. # IDIOT
  292. eb.use_connect = parent_nc.evaluate_input("Connected")
  293. eb.use_inherit_rotation = parent_nc.evaluate_input("Inherit Rotation")
  294. eb.inherit_scale = parent_nc.evaluate_input("Inherit Scale")
  295. # otherwise, no need to do anything.
  296. def bExecute(self, bContext = None,): #possibly will need to pass context?
  297. import bpy
  298. from mathutils import Vector
  299. if (not isinstance(bContext, bpy.types.Context)):
  300. raise RuntimeError("Incorrect context")
  301. xF = self.bGetParentArmature()
  302. name = self.evaluate_input("Name")
  303. matrix = self.evaluate_input("Matrix")
  304. length = matrix[3][3]
  305. if (xF):
  306. if (xF.mode != "EDIT"):
  307. raise RuntimeError("Armature Object Not in Edit Mode, exiting...")
  308. else:
  309. raise RuntimeError("Could not create edit bone: ", name, " from node:", self.signature, " Reason: No armature object to add bone to.")
  310. #
  311. # Create the Object
  312. d = xF.data
  313. eb = d.edit_bones.new(name)
  314. # Bone Collections:
  315. # We treat each separate string as a Bone Collection that this object belongs to
  316. # Bone Collections are fully qualified by their hierarchy.
  317. # Separate Strings with "|" and indicate hierarchy with ">". These are special characters.
  318. # NOTE: if the user names the collections differently at different times, this will take the FIRST definition and go with it
  319. sCols = self.evaluate_input("Bone Collection")
  320. bone_collections = sCols.split("|")
  321. for collection_list in bone_collections:
  322. hierarchy = collection_list.split(">")
  323. col_parent = None
  324. for i, sCol in enumerate(hierarchy):
  325. if ( col := d.collections.get(sCol) ) is None:
  326. col = d.collections.new(sCol)
  327. col.parent = col_parent
  328. col_parent = col
  329. col.assign(eb)
  330. if (eb.name != name):
  331. raise RuntimeError("Could not create bone ", name, "; Perhaps there is a duplicate bone name in the node tree?")
  332. eb.matrix = matrix.copy()
  333. tailoffset = Vector((0,length,0)) #Vector((0,self.tailoffset, 0))
  334. tailoffset = matrix.copy().to_3x3() @ tailoffset
  335. eb.tail = eb.head + tailoffset
  336. if (eb.name != name):
  337. raise RuntimeError("Could not create edit bone: ", name)
  338. assert (eb.name), "Bone must have a name."
  339. self.bObject = eb.name
  340. # The bone should have relationships going in at this point.
  341. assert (self.bObject), "eh? %s" % eb.name
  342. self.bSetParent(eb)
  343. # Setup Deform attributes...
  344. eb.use_deform = self.evaluate_input("Deform")
  345. eb.envelope_distance = self.evaluate_input("Envelope Distance")
  346. eb.envelope_weight = self.evaluate_input("Envelope Weight")
  347. eb.use_envelope_multiply = self.evaluate_input("Envelope Multiply")
  348. eb.head_radius = self.evaluate_input("Envelope Head Radius")
  349. eb.tail_radius = self.evaluate_input("Envelope Tail Radius")
  350. print( wrapGreen("Created Bone: ") + wrapOrange(eb.name) + wrapGreen(" in ") + wrapWhite(self.bGetParentArmature().name))
  351. self.executed = True
  352. def bFinalize(self, bContext = None):
  353. import bpy
  354. from .drivers import MantisDriver
  355. # prevAct = bContext.view_layer.objects.active
  356. # bContext.view_layer.objects.active = ob
  357. # bpy.ops.object.mode_set(mode='OBJECT')
  358. # bContext.view_layer.objects.active = prevAct
  359. #
  360. #get relationship
  361. # ensure we have a pose bone...
  362. # set the ik parameters
  363. #
  364. #
  365. # Don't need to bother about whatever that was
  366. pb = self.bGetParentArmature().pose.bones[self.bObject]
  367. pb.id_properties_clear()
  368. # these are kept around unless explicitly deleted.
  369. from .utilities import get_node_prototype
  370. np = get_node_prototype(self.signature, self.base_tree)
  371. driver = None
  372. do_prints=False
  373. for i, inp in enumerate(np.inputs):
  374. if ('Parameter' in inp.bl_idname):
  375. name = inp.name
  376. # print(inp.name)
  377. try:
  378. value = self.evaluate_input(inp.name)
  379. except KeyError as e:
  380. trace = trace_single_line(self, inp.name)
  381. if do_prints: print(trace[0][-1], trace[1])
  382. if do_prints: print (trace[0][-1].parameters)
  383. #prop = trace[0][-1].parameters[trace[1].name]
  384. raise e
  385. # This may be driven, so let's do this:
  386. if do_prints: print (value)
  387. if (isinstance(value, tuple)):
  388. # it's either a CombineThreeBool or a CombineVector.
  389. prRed("COMITTING SUICIDE NOW!!")
  390. bpy.ops.wm.quit_blender()
  391. if (isinstance(value, MantisDriver)):
  392. # the value should be the default for its socket...
  393. if do_prints: print (type(inp.default_value))
  394. type_val_map = {
  395. str:"",
  396. bool:False,
  397. int:0,
  398. float:0.0,
  399. bpy.types.bpy_prop_array:(0,0,0),
  400. }
  401. driver = value
  402. value = type_val_map[type(inp.default_value)]
  403. if (value is None):
  404. prRed("This is probably not supposed to happen")
  405. value = 0
  406. raise RuntimeError("Could not set value of custom parameter")
  407. # it creates a more confusing error later sometimes, better to catch it here.
  408. # IMPORTANT: Is it possible for more than one driver to
  409. # come through here, and for the variable to be
  410. # overwritten?
  411. #TODO important
  412. #from rna_prop_ui import rna_idprop_ui_create
  413. # use this ^
  414. # add the custom properties to the **Pose Bone**
  415. pb[name] = value
  416. # This is much simpler now.
  417. ui_data = pb.id_properties_ui(name)
  418. ui_data.update(
  419. description=inp.description,
  420. default=value,)
  421. #if a number
  422. for num_type in ['Float']:
  423. if num_type in inp.bl_idname:
  424. ui_data.update(
  425. min = inp.min,
  426. max = inp.max,
  427. soft_min = inp.soft_min,
  428. soft_max = inp.soft_max,)
  429. for num_type in ['Int']:
  430. # for some reason the types don't cast implicitly
  431. if num_type in inp.bl_idname:
  432. ui_data.update(
  433. min = int(inp.min),
  434. max = int(inp.max),
  435. soft_min = int(inp.soft_min),
  436. soft_max = int(inp.soft_max),)
  437. for bool_type in ['Bool']:
  438. # for some reason the types don't cast implicitly
  439. if bool_type in inp.bl_idname:
  440. # prPurple(ui_data.update.__text_signature__)
  441. # prPurple(ui_data.update.__doc__)
  442. ui_data.update() # TODO I can't figure out what the update function expects because it isn't documented
  443. # Doesn't seem to work?
  444. #pb.property_overridable_library_set("["+name+"]", True)
  445. # Set up IK settings, these belong to the pose bone.
  446. if (pb.is_in_ik_chain): # cool!
  447. pb. ik_stretch = self.evaluate_input("IK Stretch")
  448. lock = self.evaluate_input("Lock IK")
  449. stiffness = self.evaluate_input("IK Stiffness")
  450. limit = self.evaluate_input("Limit IK")
  451. pb.ik_min_x = self.evaluate_input("X Min")
  452. pb.ik_max_x = self.evaluate_input("X Max")
  453. pb.ik_min_y = self.evaluate_input("Y Min")
  454. pb.ik_max_y = self.evaluate_input("Y Max")
  455. pb.ik_min_z = self.evaluate_input("Z Min")
  456. pb.ik_max_z = self.evaluate_input("Z Max")
  457. pb.ik_stiffness_x = stiffness[0]
  458. pb.ik_stiffness_y = stiffness[1]
  459. pb.ik_stiffness_z = stiffness[2]
  460. pb.lock_ik_x = lock[0]
  461. pb.lock_ik_y = lock[1]
  462. pb.lock_ik_z = lock[2]
  463. pb. use_ik_limit_x = limit[0]
  464. pb.use_ik_limit_y = limit[1]
  465. pb.use_ik_limit_z = limit[2]
  466. # time to set up drivers!
  467. if (driver):
  468. pass
  469. #
  470. # OK, visual settings
  471. #
  472. # Get the override xform's bone:
  473. if len(self.inputs["Custom Object xForm Override"].links) > 0:
  474. trace = trace_single_line(self, "Custom Object xForm Override")
  475. try:
  476. pb.custom_shape_transform = trace[0][1].bGetObject()
  477. except AttributeError:
  478. pass
  479. if len(self.inputs["Custom Object"].links) > 0:
  480. trace = trace_single_line(self, "Custom Object")
  481. try:
  482. ob = trace[0][1].bGetObject()
  483. except AttributeError:
  484. ob=None
  485. if type(ob) in [bpy.types.Object]:
  486. pb.custom_shape = ob
  487. #
  488. pb.bone.hide = self.evaluate_input("Hide")
  489. pb.custom_shape_scale_xyz = self.evaluate_input("Custom Object Scale")
  490. pb.custom_shape_translation = self.evaluate_input("Custom Object Translation")
  491. pb.custom_shape_rotation_euler = self.evaluate_input("Custom Object Rotation")
  492. pb.use_custom_shape_bone_size = self.evaluate_input("Custom Object Scale to Bone Length")
  493. pb.bone.show_wire = self.evaluate_input("Custom Object Wireframe")
  494. # #
  495. # # D E P R E C A T E D
  496. # #
  497. # # Bone Groups
  498. # if bg_name := self.evaluate_input("Bone Group"): # this is a string
  499. # obArm = self.bGetParentArmature()
  500. # # Temporary! Temporary! HACK
  501. # color_set_items= [
  502. # "DEFAULT",
  503. # "THEME01",
  504. # "THEME02",
  505. # "THEME03",
  506. # "THEME04",
  507. # "THEME05",
  508. # "THEME06",
  509. # "THEME07",
  510. # "THEME08",
  511. # "THEME09",
  512. # "THEME10",
  513. # "THEME11",
  514. # "THEME12",
  515. # "THEME13",
  516. # "THEME14",
  517. # "THEME15",
  518. # "THEME16",
  519. # "THEME17",
  520. # "THEME18",
  521. # "THEME19",
  522. # "THEME20",
  523. # # "CUSTOM",
  524. # ]
  525. # try:
  526. # bg = obArm.pose.bone_groups.get(bg_name)
  527. # except SystemError:
  528. # bg = None
  529. # pass # no clue why this happens. uninitialzied?
  530. # if not bg:
  531. # bg = obArm.pose.bone_groups.new(name=bg_name)
  532. # #HACK lol
  533. # from random import randint
  534. # bg.color_set = color_set_items[randint(0,14)]
  535. # #15-20 are black by default, gross
  536. # # this is good enough for now!
  537. # pb.bone_group = bg
  538. def bGetObject(self, mode = 'POSE'):
  539. try:
  540. if (mode == 'EDIT'):
  541. return self.bGetParentArmature().data.edit_bones[self.bObject]
  542. elif (mode == 'OBJECT'):
  543. return self.bGetParentArmature().data.bones[self.bObject]
  544. elif (mode == 'POSE'):
  545. return self.bGetParentArmature().pose.bones[self.bObject]
  546. except Exception as e:
  547. prRed ("Cannot get bone for %s" % self)
  548. raise e
  549. class xFormGeometryObject:
  550. '''A node representing an armature object'''
  551. bObject = None
  552. def __init__(self, signature, base_tree):
  553. self.base_tree=base_tree
  554. self.executed = False
  555. self.signature = signature
  556. self.inputs = {
  557. "Name" : NodeSocket(is_input = True, name = "Name", node = self),
  558. "Geometry" : NodeSocket(is_input = True, name = "Geometry", node = self),
  559. "Matrix" : NodeSocket(is_input = True, name = "Matrix", node = self),
  560. "Relationship" : NodeSocket(is_input = True, name = "Relationship", node = self),
  561. }
  562. self.outputs = {
  563. "xForm Out" : NodeSocket(is_input = False, name="xForm Out", node = self), }
  564. self.parameters = {
  565. "Name":None,
  566. "Geometry":None,
  567. "Matrix":None,
  568. "Relationship":None,
  569. }
  570. self.links = {} # leave this empty for now!
  571. # now set up the traverse target...
  572. self.inputs["Relationship"].set_traverse_target(self.outputs["xForm Out"])
  573. self.outputs["xForm Out"].set_traverse_target(self.inputs["Relationship"])
  574. self.node_type = "XFORM"
  575. self.bObject = None
  576. def bSetParent(self, ob):
  577. from bpy.types import Object, Bone
  578. parent_nc = get_parent(self, type='LINK')
  579. if (parent_nc):
  580. parent = parent_nc.inputs['Parent'].links[0].from_node
  581. parent_bOb = parent.bGetObject(mode = 'EDIT')
  582. if isinstance(parent_bOb, Bone):
  583. armOb= parent.bGetParentArmature()
  584. ob.parent = armOb
  585. ob.parent_type = 'BONE'
  586. ob.parent_bone = parent_bOb.name
  587. elif isinstance(parent, Object):
  588. ob.parent = parent
  589. # blender will do the matrix math for me IF I set the world
  590. # matrix after setting the parent.
  591. #
  592. # deal with parenting settings here, if necesary
  593. def evaluate_input(self, input_name):
  594. return evaluate_input(self, input_name)
  595. def bExecute(self, bContext = None,):
  596. import bpy
  597. self.bObject = bpy.data.objects.get(self.evaluate_input("Name"))
  598. if not self.bObject:
  599. trace = trace_single_line(self, "Geometry")
  600. if trace[-1]:
  601. self.bObject = bpy.data.objects.new(self.evaluate_input("Name"), trace[-1].node.bGetObject())
  602. else: # clear it
  603. self.bObject.constraints.clear()
  604. # Don't clear this, we want to be able to reuse this
  605. # self.bObject.vertex_groups.clear()
  606. #
  607. # This is probably also not what we want - but for now it is OK
  608. self.bObject.modifiers.clear()
  609. try:
  610. bpy.context.collection.objects.link(self.bObject)
  611. except RuntimeError: #already in; but a dangerous thing to pass.
  612. pass
  613. self.bSetParent(self.bObject)
  614. self.bObject.matrix_world = self.evaluate_input("Matrix")
  615. def bFinalize(self, bContext = None):
  616. pass
  617. def bGetObject(self, mode = 'POSE'):
  618. return self.bObject
  619. def __repr__(self):
  620. return self.signature.__repr__()
  621. def fill_parameters(self):
  622. fill_parameters(self)