xForm_containers.py 45 KB

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