xForm_containers.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. from mantis.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. else:
  113. # Create the Object
  114. ob = bpy.data.objects.new(name, bpy.data.armatures.new(name)) #create ob
  115. if (ob.name != name):
  116. raise RuntimeError("Could not create xForm object", name)
  117. self.bObject = ob.name
  118. ob.matrix_world = matrix
  119. # # first, get the parent object
  120. # parent_node = get_parent(self)
  121. # if hasattr(parent_node, "bObject"):
  122. # # this won't work of course, TODO
  123. # ob.parent = parent_node.bObject
  124. # # print (self.bObject)
  125. if True:
  126. from bpy.types import EditBone
  127. parent_nc = get_parent(self, type='LINK')
  128. if parent_nc:
  129. parent = parent_nc.inputs['Parent'].links[0].from_node.bGetObject(mode = 'OBJECT')
  130. ob.parent = parent
  131. # Link to Scene:
  132. if (ob.name not in bContext.view_layer.active_layer_collection.collection.objects):
  133. bContext.view_layer.active_layer_collection.collection.objects.link(ob)
  134. #self.bParent(bContext)
  135. print( wrapGreen("Created Armature object: ")+ wrapWhite(ob.name))
  136. # Finalize the action
  137. # oddly, overriding context doesn't seem to work
  138. try:
  139. bpy.ops.object.select_all(action='DESELECT')
  140. except RuntimeError:
  141. pass # we're already in edit mode, should be OK to do this.
  142. bContext.view_layer.objects.active = ob
  143. selected=[]
  144. for other_ob in bpy.data.objects:
  145. if other_ob.mode == "EDIT":
  146. selected.append(other_ob)
  147. selected.append(ob)
  148. context_override = {"active_object":ob, "selected_objects":selected}
  149. print("Changing Armature Mode to " +wrapPurple("EDIT"))
  150. bpy.ops.object.mode_set(context_override, mode='EDIT')
  151. if ob.mode != "EDIT":
  152. prRed("eh?")
  153. # clear it
  154. while (len(ob.data.edit_bones) > 0):
  155. ob.data.edit_bones.remove(ob.data.edit_bones[0])
  156. # bContext.view_layer.objects.active = prevAct
  157. self.executed = True
  158. # # not used yet
  159. # #
  160. # def bFinalize(self, bContext = None):
  161. # import bpy
  162. # ob = self.bGetObject()
  163. # prevAct = bContext.view_layer.objects.active
  164. # bContext.view_layer.objects.active = ob
  165. # bpy.ops.object.mode_set(mode='OBJECT')
  166. # print ("Changing Armature Mode to OBJECT")
  167. # bContext.view_layer.objects.active = prevAct
  168. def bGetObject(self, mode = ''):
  169. import bpy; return bpy.data.objects[self.bObject]
  170. def __repr__(self):
  171. return self.signature.__repr__()
  172. def fill_parameters(self,):
  173. fill_parameters(self)
  174. class xFormBone:
  175. '''A node representing a bone in an armature'''
  176. # DO: make a way to identify which armature this belongs to
  177. def __init__(self, signature, base_tree):
  178. self.base_tree=base_tree
  179. self.executed = False
  180. self.signature = signature
  181. self.inputs = {
  182. "Name" : NodeSocket(is_input = True, name = "Name", node = self,),
  183. "Rotation Order" : NodeSocket(is_input = True, name = "Rotation Order", node = self,),
  184. "Matrix" : NodeSocket(is_input = True, name = "Matrix", node = self,),
  185. "Relationship" : NodeSocket(is_input = True, name = "Relationship", node = self,),
  186. # IK settings
  187. "IK Stretch" : NodeSocket(is_input = True, name = "IK Stretch", node = self,),
  188. "Lock IK" : NodeSocket(is_input = True, name = "Lock IK", node = self,),
  189. "IK Stiffness" : NodeSocket(is_input = True, name = "IK Stiffness", node = self,),
  190. "Limit IK" : NodeSocket(is_input = True, name = "Limit IK", node = self,),
  191. "X Min" : NodeSocket(is_input = True, name = "X Min", node = self,),
  192. "X Max" : NodeSocket(is_input = True, name = "X Max", node = self,),
  193. "Y Min" : NodeSocket(is_input = True, name = "Y Min", node = self,),
  194. "Y Max" : NodeSocket(is_input = True, name = "Y Max", node = self,),
  195. "Z Min" : NodeSocket(is_input = True, name = "Z Min", node = self,),
  196. "Z Max" : NodeSocket(is_input = True, name = "Z Max", node = self,),
  197. # Visual stuff
  198. "Layer Mask" : NodeSocket(is_input = True, name = "Layer Mask", node = self,),
  199. "Hide" : NodeSocket(is_input = True, name = "Hide", node = self,),
  200. "Custom Object" : NodeSocket(is_input = True, name = "Custom Object", node = self,),
  201. "Custom Object xForm Override" : NodeSocket(is_input = True, name = "Custom Object xForm Override", node = self,),
  202. "Custom Object Scale to Bone Length" : NodeSocket(is_input = True, name = "Custom Object Scale to Bone Length", node = self,),
  203. "Custom Object Wireframe" : NodeSocket(is_input = True, name = "Custom Object Wireframe", node = self,),
  204. "Custom Object Scale" : NodeSocket(is_input = True, name = "Custom Object Scale", node = self,),
  205. "Custom Object Translation" : NodeSocket(is_input = True, name = "Custom Object Translation", node = self,),
  206. "Custom Object Rotation" : NodeSocket(is_input = True, name = "Custom Object Rotation", node = self,),
  207. "Bone Group" : NodeSocket(is_input = True, name = "Bone Group", node = self,),
  208. # Deform Stuff
  209. "Deform" : NodeSocket(is_input = True, name = "Deform", node = self,),
  210. "Envelope Distance" : NodeSocket(is_input = True, name = "Envelope Distance", node = self,),
  211. "Envelope Weight" : NodeSocket(is_input = True, name = "Envelope Weight", node = self,),
  212. "Envelope Multiply" : NodeSocket(is_input = True, name = "Envelope Multiply", node = self,),
  213. "Envelope Head Radius" : NodeSocket(is_input = True, name = "Envelope Head Radius", node = self,),
  214. "Envelope Tail Radius" : NodeSocket(is_input = True, name = "Envelope Tail Radius", node = self,),
  215. }
  216. self.outputs = {
  217. "xForm Out" : NodeSocket(name = "xForm Out", node = self),
  218. }
  219. self.parameters = {
  220. "Name":None,
  221. "Rotation Order":None,
  222. "Matrix":None,
  223. "Relationship":None,
  224. # IK settings
  225. "IK Stretch":None,
  226. "Lock IK":None,
  227. "IK Stiffness":None,
  228. "Limit IK":None,
  229. "X Min":None,
  230. "X Max":None,
  231. "Y Min":None,
  232. "Y Max":None,
  233. "Z Min":None,
  234. "Z Max":None,
  235. "Layer Mask":None,
  236. "Hide":None,
  237. "Layer Mask":None,
  238. "Hide":None,
  239. "Custom Object":None,
  240. "Custom Object xForm Override":None,
  241. "Custom Object Scale to Bone Length":None,
  242. "Custom Object Wireframe":None,
  243. "Custom Object Scale":None,
  244. "Custom Object Translation":None,
  245. "Custom Object Rotation":None,
  246. "Bone Group" : None,
  247. "Deform" : None,
  248. "Envelope Distance" : None,
  249. "Envelope Weight" : None,
  250. "Envelope Multiply" : None,
  251. "Envelope Head Radius" : None,
  252. "Envelope Tail Radius" : None,
  253. }
  254. self.links = {} # leave this empty for now!
  255. # now set up the traverse target...
  256. self.inputs["Relationship"].set_traverse_target(self.outputs["xForm Out"])
  257. self.outputs["xForm Out"].set_traverse_target(self.inputs["Relationship"])
  258. self.node_type = 'XFORM'
  259. setup_custom_props(self)
  260. def evaluate_input(self, input_name):
  261. return evaluate_input(self, input_name)
  262. def __repr__(self):
  263. return self.signature.__repr__()
  264. def fill_parameters(self):
  265. fill_parameters(self)
  266. def bGetParentArmature(self):
  267. finished = False
  268. if (trace := trace_single_line(self, "Relationship")[0] ) :
  269. for i in range(len(trace)):
  270. # have to look in reverse, actually
  271. if ( isinstance(trace[ i ], xFormArmature ) ):
  272. return trace[ i ].bGetObject()
  273. return None
  274. #should do the trick...
  275. def bSetParent(self, eb):
  276. # print (self.bObject)
  277. from bpy.types import EditBone
  278. parent_nc = get_parent(self, type='LINK')
  279. # print (self, parent_nc.inputs['Parent'].from_node)
  280. parent = parent_nc.inputs['Parent'].links[0].from_node.bGetObject(mode = 'EDIT')
  281. if isinstance(parent, EditBone):
  282. eb.parent = parent
  283. #DUMMY
  284. # I NEED TO GET THE LINK NC
  285. # IDIOT
  286. eb.use_connect = parent_nc.evaluate_input("Connected")
  287. eb.use_inherit_rotation = parent_nc.evaluate_input("Inherit Rotation")
  288. eb.inherit_scale = parent_nc.evaluate_input("Inherit Scale")
  289. # otherwise, no need to do anything.
  290. def bExecute(self, bContext = None,): #possibly will need to pass context?
  291. import bpy
  292. from mathutils import Vector
  293. if (not isinstance(bContext, bpy.types.Context)):
  294. raise RuntimeError("Incorrect context")
  295. xF = self.bGetParentArmature()
  296. name = self.evaluate_input("Name")
  297. matrix = self.evaluate_input("Matrix")
  298. length = matrix[3][3]
  299. if (xF):
  300. if (xF.mode != "EDIT"):
  301. raise RuntimeError("Armature Object Not in Edit Mode, exiting...")
  302. else:
  303. raise RuntimeError("Could not create edit bone: ", name, " from node:", self.signature, " Reason: No armature object to add bone to.")
  304. #
  305. # Create the Object
  306. d = xF.data
  307. eb = d.edit_bones.new(name)
  308. if (eb.name != name):
  309. raise RuntimeError("Could not create bone ", name, "; Perhaps there is a duplicate bone name in the node tree?")
  310. eb.matrix = matrix.copy()
  311. tailoffset = Vector((0,length,0)) #Vector((0,self.tailoffset, 0))
  312. tailoffset = matrix.copy().to_3x3() @ tailoffset
  313. eb.tail = eb.head + tailoffset
  314. if (eb.name != name):
  315. raise RuntimeError("Could not create edit bone: ", name)
  316. assert (eb.name), "Bone must have a name."
  317. self.bObject = eb.name
  318. # The bone should have relationships going in at this point.
  319. assert (self.bObject), "eh? %s" % eb.name
  320. self.bSetParent(eb)
  321. eb.layers = self.evaluate_input("Layer Mask")
  322. # Setup Deform attributes...
  323. eb.use_deform = self.evaluate_input("Deform")
  324. eb.envelope_distance = self.evaluate_input("Envelope Distance")
  325. eb.envelope_weight = self.evaluate_input("Envelope Weight")
  326. eb.use_envelope_multiply = self.evaluate_input("Envelope Multiply")
  327. eb.head_radius = self.evaluate_input("Envelope Head Radius")
  328. eb.tail_radius = self.evaluate_input("Envelope Tail Radius")
  329. print( wrapGreen("Created Bone: ") + wrapOrange(eb.name) + wrapGreen(" in ") + wrapWhite(self.bGetParentArmature().name))
  330. self.executed = True
  331. def bFinalize(self, bContext = None):
  332. import bpy
  333. from mantis.drivers import MantisDriver
  334. # prevAct = bContext.view_layer.objects.active
  335. # bContext.view_layer.objects.active = ob
  336. # bpy.ops.object.mode_set(mode='OBJECT')
  337. # bContext.view_layer.objects.active = prevAct
  338. #
  339. #get relationship
  340. # ensure we have a pose bone...
  341. # set the ik parameters
  342. #
  343. #
  344. # Don't need to bother about whatever that was
  345. pb = self.bGetParentArmature().pose.bones[self.bObject]
  346. pb.id_properties_clear()
  347. # these are kept around unless explicitly deleted.
  348. from .utilities import get_node_prototype
  349. np = get_node_prototype(self.signature, self.base_tree)
  350. driver = None
  351. do_prints=False
  352. for i, inp in enumerate(np.inputs):
  353. if ('Parameter' in inp.bl_idname):
  354. name = inp.name
  355. # print(inp.name)
  356. try:
  357. value = self.evaluate_input(inp.name)
  358. except KeyError as e:
  359. trace = trace_single_line(self, inp.name)
  360. if do_prints: print(trace[0][-1], trace[1])
  361. if do_prints: print (trace[0][-1].parameters)
  362. #prop = trace[0][-1].parameters[trace[1].name]
  363. raise e
  364. # This may be driven, so let's do this:
  365. if do_prints: print (value)
  366. if (isinstance(value, tuple)):
  367. # it's either a CombineThreeBool or a CombineVector.
  368. prRed("COMITTING SUICIDE NOW!!")
  369. bpy.ops.wm.quit_blender()
  370. if (isinstance(value, MantisDriver)):
  371. # the value should be the default for its socket...
  372. if do_prints: print (type(inp.default_value))
  373. type_val_map = {
  374. str:"",
  375. bool:False,
  376. int:0,
  377. float:0.0,
  378. bpy.types.bpy_prop_array:(0,0,0),
  379. }
  380. driver = value
  381. value = type_val_map[type(inp.default_value)]
  382. if (value is None):
  383. prRed("This is probably not supposed to happen")
  384. value = 0
  385. raise RuntimeError("Could not set value of custom parameter")
  386. # it creates a more confusing error later sometimes, better to catch it here.
  387. # IMPORTANT: Is it possible for more than one driver to
  388. # come through here, and for the variable to be
  389. # overwritten?
  390. #TODO important
  391. #from rna_prop_ui import rna_idprop_ui_create
  392. # use this ^
  393. # add the custom properties to the **Pose Bone**
  394. pb[name] = value
  395. # This is much simpler now.
  396. ui_data = pb.id_properties_ui(name)
  397. ui_data.update(
  398. description=inp.description,
  399. default=value,)
  400. #if a number
  401. for num_type in ['Float']:
  402. if num_type in inp.bl_idname:
  403. ui_data.update(
  404. min = inp.min,
  405. max = inp.max,
  406. soft_min = inp.soft_min,
  407. soft_max = inp.soft_max,)
  408. for num_type in ['Int', 'Bool']:
  409. # for some reason the types don't cast implicitly
  410. if num_type in inp.bl_idname:
  411. ui_data.update(
  412. min = int(inp.min),
  413. max = int(inp.max),
  414. soft_min = int(inp.soft_min),
  415. soft_max = int(inp.soft_max),)
  416. # Doesn't seem to work?
  417. #pb.property_overridable_library_set("["+name+"]", True)
  418. # Set up IK settings, these belong to the pose bone.
  419. if (pb.is_in_ik_chain): # cool!
  420. pb. ik_stretch = self.evaluate_input("IK Stretch")
  421. lock = self.evaluate_input("Lock IK")
  422. stiffness = self.evaluate_input("IK Stiffness")
  423. limit = self.evaluate_input("Limit IK")
  424. pb.ik_min_x = self.evaluate_input("X Min")
  425. pb.ik_max_x = self.evaluate_input("X Max")
  426. pb.ik_min_y = self.evaluate_input("Y Min")
  427. pb.ik_max_y = self.evaluate_input("Y Max")
  428. pb.ik_min_z = self.evaluate_input("Z Min")
  429. pb.ik_max_z = self.evaluate_input("Z Max")
  430. pb.ik_stiffness_x = stiffness[0]
  431. pb.ik_stiffness_y = stiffness[1]
  432. pb.ik_stiffness_z = stiffness[2]
  433. pb.lock_ik_x = lock[0]
  434. pb.lock_ik_y = lock[1]
  435. pb.lock_ik_z = lock[2]
  436. pb. use_ik_limit_x = limit[0]
  437. pb.use_ik_limit_y = limit[1]
  438. pb.use_ik_limit_z = limit[2]
  439. # time to set up drivers!
  440. if (driver):
  441. pass
  442. #
  443. # OK, visual settings
  444. #
  445. # Get the override xform's bone:
  446. if len(self.inputs["Custom Object xForm Override"].links) > 0:
  447. trace = trace_single_line(self, "Custom Object xForm Override")
  448. try:
  449. pb.custom_shape_transform = trace[0][1].bGetObject()
  450. except AttributeError:
  451. pass
  452. if len(self.inputs["Custom Object"].links) > 0:
  453. trace = trace_single_line(self, "Custom Object")
  454. try:
  455. ob = trace[0][1].bGetObject()
  456. except AttributeError:
  457. ob=None
  458. if type(ob) in [bpy.types.Object]:
  459. pb.custom_shape = ob
  460. #
  461. pb.bone.hide = self.evaluate_input("Hide")
  462. pb.custom_shape_scale_xyz = self.evaluate_input("Custom Object Scale")
  463. pb.custom_shape_translation = self.evaluate_input("Custom Object Translation")
  464. pb.custom_shape_rotation_euler = self.evaluate_input("Custom Object Rotation")
  465. pb.use_custom_shape_bone_size = self.evaluate_input("Custom Object Scale to Bone Length")
  466. pb.bone.show_wire = self.evaluate_input("Custom Object Wireframe")
  467. #
  468. # Bone Groups
  469. if bg_name := self.evaluate_input("Bone Group"): # this is a string
  470. obArm = self.bGetParentArmature()
  471. # Temporary! Temporary! HACK
  472. color_set_items= [
  473. "DEFAULT",
  474. "THEME01",
  475. "THEME02",
  476. "THEME03",
  477. "THEME04",
  478. "THEME05",
  479. "THEME06",
  480. "THEME07",
  481. "THEME08",
  482. "THEME09",
  483. "THEME10",
  484. "THEME11",
  485. "THEME12",
  486. "THEME13",
  487. "THEME14",
  488. "THEME15",
  489. "THEME16",
  490. "THEME17",
  491. "THEME18",
  492. "THEME19",
  493. "THEME20",
  494. # "CUSTOM",
  495. ]
  496. try:
  497. bg = obArm.pose.bone_groups.get(bg_name)
  498. except SystemError:
  499. bg = None
  500. pass # no clue why this happens. uninitialzied?
  501. if not bg:
  502. bg = obArm.pose.bone_groups.new(name=bg_name)
  503. #HACK lol
  504. from random import randint
  505. bg.color_set = color_set_items[randint(0,14)]
  506. #15-20 are black by default, gross
  507. # this is good enough for now!
  508. pb.bone_group = bg
  509. def bGetObject(self, mode = 'POSE'):
  510. try:
  511. if (mode == 'EDIT'):
  512. return self.bGetParentArmature().data.edit_bones[self.bObject]
  513. elif (mode == 'OBJECT'):
  514. return self.bGetParentArmature().data.bones[self.bObject]
  515. elif (mode == 'POSE'):
  516. return self.bGetParentArmature().pose.bones[self.bObject]
  517. except Exception as e:
  518. prRed ("Cannot get bone for %s" % self)
  519. raise e
  520. class xFormGeometryObject:
  521. '''A node representing an armature object'''
  522. bObject = None
  523. def __init__(self, signature, base_tree):
  524. self.base_tree=base_tree
  525. self.executed = False
  526. self.signature = signature
  527. self.inputs = {
  528. "Name" : NodeSocket(is_input = True, name = "Name", node = self),
  529. "Geometry" : NodeSocket(is_input = True, name = "Geometry", node = self),
  530. "Matrix" : NodeSocket(is_input = True, name = "Matrix", node = self),
  531. "Relationship" : NodeSocket(is_input = True, name = "Relationship", node = self),
  532. }
  533. self.outputs = {
  534. "xForm Out" : NodeSocket(is_input = False, name="xForm Out", node = self), }
  535. self.parameters = {
  536. "Name":None,
  537. "Geometry":None,
  538. "Matrix":None,
  539. "Relationship":None,
  540. }
  541. self.links = {} # leave this empty for now!
  542. # now set up the traverse target...
  543. self.inputs["Relationship"].set_traverse_target(self.outputs["xForm Out"])
  544. self.outputs["xForm Out"].set_traverse_target(self.inputs["Relationship"])
  545. self.node_type = "XFORM"
  546. self.bObject = None
  547. def bSetParent(self, ob):
  548. from bpy.types import Object, Bone
  549. parent_nc = get_parent(self, type='LINK')
  550. if (parent_nc):
  551. parent = parent_nc.inputs['Parent'].links[0].from_node
  552. parent_bOb = parent.bGetObject(mode = 'EDIT')
  553. if isinstance(parent_bOb, Bone):
  554. armOb= parent.bGetParentArmature()
  555. ob.parent = armOb
  556. ob.parent_type = 'BONE'
  557. ob.parent_bone = parent_bOb.name
  558. elif isinstance(parent, Object):
  559. ob.parent = parent
  560. # blender will do the matrix math for me IF I set the world
  561. # matrix after setting the parent.
  562. #
  563. # deal with parenting settings here, if necesary
  564. def evaluate_input(self, input_name):
  565. return evaluate_input(self, input_name)
  566. def bExecute(self, bContext = None,):
  567. import bpy
  568. self.bObject = bpy.data.objects.get(self.evaluate_input("Name"))
  569. if not self.bObject:
  570. trace = trace_single_line(self, "Geometry")
  571. if trace[-1]:
  572. self.bObject = bpy.data.objects.new(self.evaluate_input("Name"), trace[-1].node.bGetObject())
  573. else: # clear it
  574. self.bObject.constraints.clear()
  575. # Don't clear this, we want to be able to reuse this
  576. # self.bObject.vertex_groups.clear()
  577. #
  578. # This is probably also not what we want - but for now it is OK
  579. self.bObject.modifiers.clear()
  580. try:
  581. bpy.context.collection.objects.link(self.bObject)
  582. except RuntimeError: #already in; but a dangerous thing to pass.
  583. pass
  584. self.bSetParent(self.bObject)
  585. self.bObject.matrix_world = self.evaluate_input("Matrix")
  586. def bFinalize(self, bContext = None):
  587. pass
  588. def bGetObject(self, mode = 'POSE'):
  589. return self.bObject
  590. def __repr__(self):
  591. return self.signature.__repr__()
  592. def fill_parameters(self):
  593. fill_parameters(self)