misc_containers.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. from .node_container_common import *
  2. # The fact that I need this means that some of these classes should
  3. # probably be moved to link_containers.py
  4. from .xForm_containers import xFormRoot, xFormArmature, xFormBone
  5. def TellClasses():
  6. return [
  7. # utility
  8. InputFloat,
  9. InputVector,
  10. InputBoolean,
  11. InputBooleanThreeTuple,
  12. InputRotationOrder,
  13. InputTransformSpace,
  14. InputString,
  15. InputQuaternion,
  16. InputQuaternionAA,
  17. InputMatrix,
  18. InputLayerMask,
  19. # InputGeometry,
  20. InputExistingGeometryObject,
  21. InputExistingGeometryData,
  22. UtilityMetaRig,
  23. UtilityBoneProperties,
  24. UtilityDriverVariable,
  25. UtilityDriver,
  26. UtilityFCurve,
  27. UtilitySwitch,
  28. UtilityCombineThreeBool,
  29. UtilityCombineVector,
  30. UtilityCatStrings,
  31. ]
  32. #*#-------------------------------#++#-------------------------------#*#
  33. # G E N E R I C N O D E S
  34. #*#-------------------------------#++#-------------------------------#*#
  35. # in reality, none of these inputs have names
  36. # so I am using the socket name for now
  37. # I suppose I could use any name :3
  38. # TODO: the inputs that do not have names should have an empty string
  39. # TODO after that: make this work with identifiers instead, stupid.
  40. class InputFloat:
  41. '''A node representing float input'''
  42. def __init__(self, signature, base_tree):
  43. self.base_tree=base_tree
  44. self.signature = signature
  45. self.inputs = {}
  46. self.outputs = {"Float Input" : NodeSocket(name = "Float Input", node=self) }
  47. self.parameters = {"Float Input":None, "Mute":None}
  48. self.node_type = 'UTILITY'
  49. def evaluate_input(self, input_name):
  50. return self.parameters["Float Input"]
  51. def bExecute(self, bContext = None,):
  52. pass
  53. def __repr__(self):
  54. return self.signature.__repr__()
  55. def fill_parameters(self):
  56. fill_parameters(self)
  57. class InputVector:
  58. '''A node representing vector input'''
  59. def __init__(self, signature, base_tree):
  60. self.base_tree=base_tree
  61. self.signature = signature
  62. self.inputs = {}
  63. self.outputs = {"VectorSocket" : NodeSocket(name = 'VectorSocket', node=self) }
  64. self.parameters = {'VectorSocket':None, "Mute":None}
  65. self.node_type = 'UTILITY'
  66. def evaluate_input(self, input_name):
  67. return self.parameters["VectorSocket"]
  68. def bExecute(self, bContext = None,):
  69. pass
  70. def __repr__(self):
  71. return self.signature.__repr__()
  72. def fill_parameters(self):
  73. fill_parameters(self)
  74. class InputBoolean:
  75. '''A node representing boolean input'''
  76. def __init__(self, signature, base_tree):
  77. self.base_tree=base_tree
  78. self.signature = signature
  79. self.inputs = {}
  80. self.outputs = {"BooleanSocket" : NodeSocket(name = 'BooleanSocket', node=self) }
  81. self.parameters = {'BooleanSocket':None, "Mute":None}
  82. self.node_type = 'UTILITY'
  83. def evaluate_input(self, input_name):
  84. return self.parameters["BooleanSocket"]
  85. def bExecute(self, bContext = None,):
  86. pass
  87. def __repr__(self):
  88. return self.signature.__repr__()
  89. def fill_parameters(self):
  90. fill_parameters(self)
  91. class InputBooleanThreeTuple:
  92. '''A node representing inheritance'''
  93. def __init__(self, signature, base_tree):
  94. self.base_tree=base_tree
  95. self.signature = signature
  96. self.inputs = {}
  97. self.outputs = {"BooleanThreeTupleSocket" : NodeSocket(name = 'BooleanThreeTupleSocket', node=self) }
  98. self.parameters = {'BooleanThreeTupleSocket':None, "Mute":None}
  99. self.node_type = 'UTILITY'
  100. def evaluate_input(self, input_name):
  101. return self.parameters["BooleanThreeTupleSocket"]
  102. def bExecute(self, bContext = None,):
  103. pass
  104. def __repr__(self):
  105. return self.signature.__repr__()
  106. def fill_parameters(self):
  107. fill_parameters(self)
  108. class InputRotationOrder:
  109. '''A node representing string input for rotation order'''
  110. def __init__(self, signature, base_tree):
  111. self.base_tree=base_tree
  112. self.signature = signature
  113. self.inputs = {}
  114. self.outputs = {"RotationOrderSocket" : NodeSocket(name = 'RotationOrderSocket', node=self) }
  115. self.parameters = {'RotationOrderSocket':None, "Mute":None}
  116. self.node_type = 'UTILITY'
  117. def evaluate_input(self, input_name):
  118. return self.parameters["RotationOrderSocket"]
  119. def bExecute(self, bContext = None,):
  120. pass
  121. def __repr__(self):
  122. return self.signature.__repr__()
  123. def fill_parameters(self):
  124. fill_parameters(self)
  125. class InputTransformSpace:
  126. '''A node representing string input for transform space'''
  127. def __init__(self, signature, base_tree):
  128. self.base_tree=base_tree
  129. self.signature = signature
  130. self.inputs = {}
  131. self.outputs = {"TransformSpaceSocket" : NodeSocket(name = 'TransformSpaceSocket', node=self) }
  132. self.parameters = {'TransformSpaceSocket':None, "Mute":None}
  133. self.node_type = 'UTILITY'
  134. def evaluate_input(self, input_name):
  135. return self.parameters["TransformSpaceSocket"]
  136. def bExecute(self, bContext = None,):
  137. pass
  138. def __repr__(self):
  139. return self.signature.__repr__()
  140. def fill_parameters(self):
  141. fill_parameters(self)
  142. class InputString:
  143. '''A node representing string input'''
  144. def __init__(self, signature, base_tree):
  145. self.base_tree=base_tree
  146. self.signature = signature
  147. self.inputs = {}
  148. self.outputs = {"" : NodeSocket(name = '', node=self) }
  149. self.parameters = {'':None, "Mute":None}
  150. self.node_type = 'UTILITY'
  151. def evaluate_input(self, input_name):
  152. return self.parameters[""]
  153. def bExecute(self, bContext = None,):
  154. pass
  155. def __repr__(self):
  156. return self.signature.__repr__()
  157. def fill_parameters(self):
  158. fill_parameters(self)
  159. class InputQuaternion:
  160. '''A node representing quaternion input'''
  161. def __init__(self, signature, base_tree):
  162. self.base_tree=base_tree
  163. self.signature = signature
  164. self.inputs = {}
  165. self.outputs = {"QuaternionSocket" : NodeSocket(name = 'QuaternionSocket', node=self) }
  166. self.parameters = {'QuaternionSocket':None, "Mute":None}
  167. self.node_type = 'UTILITY'
  168. def evaluate_input(self, input_name):
  169. return self.parameters["QuaternionSocket"]
  170. def bExecute(self, bContext = None,):
  171. pass
  172. def __repr__(self):
  173. return self.signature.__repr__()
  174. def fill_parameters(self):
  175. fill_parameters(self)
  176. class InputQuaternionAA:
  177. '''A node representing axis-angle quaternion input'''
  178. def __init__(self, signature, base_tree):
  179. self.base_tree=base_tree
  180. self.signature = signature
  181. self.inputs = {}
  182. self.outputs = {"QuaternionSocketAA" : NodeSocket(name = 'QuaternionSocketAA', node=self) }
  183. self.parameters = {'QuaternionSocketAA':None, "Mute":None}
  184. self.node_type = 'UTILITY'
  185. def evaluate_input(self, input_name):
  186. return self.parameters["QuaternionSocketAA"]
  187. def bExecute(self, bContext = None,):
  188. pass
  189. def __repr__(self):
  190. return self.signature.__repr__()
  191. def fill_parameters(self):
  192. fill_parameters(self)
  193. class InputMatrix:
  194. '''A node representing axis-angle quaternion input'''
  195. def __init__(self, signature, base_tree):
  196. self.base_tree=base_tree
  197. self.signature = signature
  198. self.inputs = {}
  199. self.outputs = {"Matrix" : NodeSocket(name = 'Matrix', node=self) }
  200. self.parameters = {'Matrix':None, "Mute":None}
  201. self.node_type = 'UTILITY'
  202. def evaluate_input(self, input_name):
  203. return self.parameters["Matrix"]
  204. def bExecute(self, bContext = None,):
  205. pass
  206. def __repr__(self):
  207. return self.signature.__repr__()
  208. def fill_parameters(self, node_prototype):
  209. # this node is peculiar for how its data is input
  210. # It uses node properties that are not addressable as sockets.
  211. from mathutils import Matrix
  212. matrix = ( node_prototype.first_row[ 0], node_prototype.first_row[ 1], node_prototype.first_row[ 2], node_prototype.first_row[ 3],
  213. node_prototype.second_row[0], node_prototype.second_row[1], node_prototype.second_row[2], node_prototype.second_row[3],
  214. node_prototype.third_row[ 0], node_prototype.third_row[ 1], node_prototype.third_row[ 2], node_prototype.third_row[ 3],
  215. node_prototype.fourth_row[0], node_prototype.fourth_row[1], node_prototype.fourth_row[2], node_prototype.fourth_row[3], )
  216. self.parameters["Matrix"] = Matrix([matrix[0:4], matrix[4:8], matrix[8:12], matrix[12:16]])
  217. # print (self.parameters["Matrix"])
  218. # # NOT YET IMPLEMENTED:
  219. # class InputMatrixNode(Node, MantisNode):
  220. # '''A node representing matrix input'''
  221. # inputs =
  222. # # the node is implemented as a set of sixteen float inputs
  223. # # but I think I can boil it down to one matrix input
  224. # class ScaleBoneLengthNode(Node, MantisNode):
  225. # '''Scale Bone Length'''
  226. # pass
  227. class UtilityMetaRig:
  228. '''A node representing an armature object'''
  229. def __init__(self, signature, base_tree):
  230. self.base_tree=base_tree
  231. self.executed = False
  232. self.signature = signature
  233. self.inputs = {
  234. "Meta-Armature" : NodeSocket(is_input = True, name = "Meta-Armature", node=self),
  235. "Meta-Bone" : NodeSocket(is_input = True, name = "Meta-Bone", node=self),
  236. }
  237. self.outputs = {
  238. "Matrix" : NodeSocket(name = "Matrix", node=self),
  239. }
  240. self.parameters = {
  241. "Meta-Armature" : None,
  242. "Meta-Bone" : None,
  243. }
  244. self.node_type = "UTILITY"
  245. def evaluate_input(self, input_name):
  246. return evaluate_input(self, input_name)
  247. def bExecute(self, bContext = None,):
  248. #kinda clumsy, whatever
  249. import bpy
  250. from mathutils import Matrix
  251. m = Matrix.Identity(4)
  252. meta_rig = self.evaluate_input("Meta-Armature")
  253. meta_bone = self.evaluate_input("Meta-Bone")
  254. if meta_rig:
  255. if ( armOb := bpy.data.objects.get(meta_rig) ):
  256. m = armOb.matrix_world
  257. if ( b := armOb.data.bones.get(meta_bone)):
  258. # calculate the correct object-space matrix
  259. m = Matrix.Identity(3)
  260. bones = []
  261. while (b): bones.append(b); b = b.parent
  262. while (bones): b = bones.pop(); m = m @ b.matrix
  263. m = Matrix.Translation(b.head_local) @ m.to_4x4()
  264. m[3][3] = b.length # this is where I arbitrarily decided to store length
  265. self.parameters["Matrix"] = m
  266. def __repr__(self):
  267. return self.signature.__repr__()
  268. def fill_parameters(self):
  269. fill_parameters(self)
  270. self.parameters["Matrix"] = None
  271. class UtilityBoneProperties:
  272. '''A node representing an armature object'''
  273. def __init__(self, signature, base_tree):
  274. self.base_tree=base_tree
  275. self.executed = False
  276. self.signature = signature
  277. self.inputs = {}
  278. self.outputs = {
  279. "matrix" : NodeSocket(name = "matrix", node=self),
  280. "matrix_local" : NodeSocket(name = "matrix_local", node=self),
  281. "matrix_basis" : NodeSocket(name = "matrix_basis", node=self),
  282. "head" : NodeSocket(name = "head", node=self),
  283. "tail" : NodeSocket(name = "tail", node=self),
  284. "length" : NodeSocket(name = "length", node=self),
  285. "rotation" : NodeSocket(name = "rotation", node=self),
  286. "location" : NodeSocket(name = "location", node=self),
  287. "scale" : NodeSocket(name = "scale", node=self),
  288. }
  289. self.parameters = {
  290. "matrix":None,
  291. "matrix_local":None,
  292. "matrix_basis":None,
  293. "head":None,
  294. "tail":None,
  295. "length":None,
  296. "rotation":None,
  297. "location":None,
  298. "scale":None,
  299. }
  300. self.node_type = "UTILITY"
  301. def evaluate_input(self, input_name):
  302. return evaluate_input(self, input_name)
  303. def bExecute(self, bContext = None,):
  304. pass
  305. def __repr__(self):
  306. return self.signature.__repr__()
  307. def fill_parameters(self):
  308. pass#fill_parameters(self)
  309. class UtilityDriverVariable:
  310. '''A node representing an armature object'''
  311. def __init__(self, signature, base_tree):
  312. self.base_tree=base_tree
  313. self.executed = False
  314. self.signature = signature
  315. self.inputs = {
  316. "Variable Type" : NodeSocket(is_input = True, name = "Variable Type", node = self),
  317. "Property" : NodeSocket(is_input = True, name = "Property", node = self),
  318. "Property Index" : NodeSocket(is_input = True, name = "Property Index", node = self),
  319. "Evaluation Space" : NodeSocket(is_input = True, name = "Evaluation Space", node = self),
  320. "Rotation Mode" : NodeSocket(is_input = True, name = "Rotation Mode", node = self),
  321. "xForm 1" : NodeSocket(is_input = True, name = "xForm 1", node = self),
  322. "xForm 2" : NodeSocket(is_input = True, name = "xForm 2", node = self),
  323. }
  324. self.outputs = {
  325. "Driver Variable" : NodeSocket(name = "Driver Variable", node=self),
  326. }
  327. self.parameters = {
  328. "Variable Type":None,
  329. "Property":None,
  330. "Property Index":None,
  331. "Evaluation Space":None,
  332. "Rotation Mode":None,
  333. "xForm 1":None,
  334. "xForm 2":None,
  335. }
  336. self.node_type = "LINK" # MUST be run in Pose mode
  337. def evaluate_input(self, input_name):
  338. if input_name == 'Property':
  339. if self.inputs['Property'].is_linked:
  340. # get the name instead...
  341. trace = trace_single_line(self, input_name)
  342. return trace[1].name # the name of the socket
  343. return self.parameters["Property"]
  344. return evaluate_input(self, input_name)
  345. def GetxForm(self, index=1):
  346. trace = trace_single_line(self, "xForm 1" if index == 1 else "xForm 2")
  347. for node in trace[0]:
  348. if (node.__class__ in [xFormRoot, xFormArmature, xFormBone]):
  349. return node #this will fetch the first one, that's good!
  350. return None
  351. def bExecute(self, bContext = None,):
  352. prepare_parameters(self)
  353. #prPurple ("Executing Driver Variable Node")
  354. xForm1 = self.GetxForm()
  355. xForm2 = self.GetxForm(index=2)
  356. # kinda clumsy
  357. if xForm1 : xForm1 = xForm1.bGetObject()
  358. if xForm2 : xForm2 = xForm2.bGetObject()
  359. v_type = self.evaluate_input("Variable Type")
  360. i = self.evaluate_input("Property Index"); dVarChannel = ""
  361. if (i >= 0): #negative values will use the vector property.
  362. if self.evaluate_input("Property") == 'location':
  363. if i == 0: dVarChannel = "LOC_X"
  364. elif i == 1: dVarChannel = "LOC_Y"
  365. elif i == 2: dVarChannel = "LOC_Z"
  366. else: raise RuntimeError("Invalid property index for %s" % self)
  367. if self.evaluate_input("Property") == 'rotation':
  368. if i == 0: dVarChannel = "ROT_X"
  369. elif i == 1: dVarChannel = "ROT_Y"
  370. elif i == 2: dVarChannel = "ROT_Z"
  371. elif i == 3: dVarChannel = "ROT_W"
  372. else: raise RuntimeError("Invalid property index for %s" % self)
  373. if self.evaluate_input("Property") == 'scale':
  374. if i == 0: dVarChannel = "SCALE_X"
  375. elif i == 1: dVarChannel = "SCALE_Y"
  376. elif i == 2: dVarChannel = "SCALE_Z"
  377. elif i == 3: dVarChannel = "SCALE_AVG"
  378. else: raise RuntimeError("Invalid property index for %s" % self)
  379. if dVarChannel: v_type = "TRANSFORMS"
  380. my_var = {
  381. "owner" : xForm1, # will be filled in by Driver
  382. "prop" : self.evaluate_input("Property"), # will be filled in by Driver
  383. "type" : v_type,
  384. "space" : self.evaluate_input("Evaluation Space"),
  385. "rotation_mode" : self.evaluate_input("Rotation Mode"),
  386. "xForm 1" : self.GetxForm(index = 1),
  387. "xForm 2" : self.GetxForm(index = 2),
  388. "channel" : dVarChannel,}
  389. # Push parameter to downstream connected node.connected:
  390. if (out := self.outputs["Driver Variable"]).is_linked:
  391. self.parameters[out.name] = my_var
  392. for link in out.links:
  393. link.to_node.parameters[link.to_socket] = my_var
  394. def __repr__(self):
  395. return self.signature.__repr__()
  396. def fill_parameters(self):
  397. fill_parameters(self)
  398. class UtilityFCurve:
  399. '''A node representing an armature object'''
  400. def __init__(self, signature, base_tree):
  401. self.base_tree=base_tree
  402. self.executed = False
  403. self.signature = signature
  404. self.inputs = {}
  405. self.outputs = {
  406. "fCurve" : NodeSocket(name = "fCurve", node=self),
  407. }
  408. self.parameters = {
  409. "fCurve":None,
  410. }
  411. self.node_type = "UTILITY"
  412. setup_custom_props(self)
  413. def evaluate_input(self, input_name):
  414. return evaluate_input(self, input_name)
  415. def bExecute(self, bContext = None,):
  416. prepare_parameters(self)
  417. from .utilities import get_node_prototype
  418. np = get_node_prototype(self.signature, self.base_tree)
  419. keys = []
  420. #['amplitude', 'back', 'bl_rna', 'co', 'co_ui', 'easing', 'handle_left', 'handle_left_type', 'handle_right', 'handle_right_type',
  421. # 'interpolation', 'period', 'rna_type', 'select_control_point', 'select_left_handle', 'select_right_handle', 'type']
  422. if np.use_kf_nodes:
  423. pass # for now
  424. else:
  425. fc_ob = np.fake_fcurve_ob
  426. fc = fc_ob.animation_data.action.fcurves[0]
  427. for k in fc.keyframe_points:
  428. key = {}
  429. for prop in dir(k):
  430. if ("__" in prop) or ("bl_" in prop): continue
  431. #it's __name__ or bl_rna or something
  432. key[prop] = getattr(k, prop)
  433. keys.append(key)
  434. # Push parameter to downstream connected node.connected:
  435. # TODO: find out if this is necesary, even
  436. if (out := self.outputs["fCurve"]).is_linked:
  437. self.parameters[out.name] = keys
  438. for link in out.links:
  439. link.to_node.parameters[link.to_socket] = keys
  440. def __repr__(self):
  441. return self.signature.__repr__()
  442. def fill_parameters(self):
  443. fill_parameters(self)
  444. class UtilityDriver:
  445. '''A node representing an armature object'''
  446. def __init__(self, signature, base_tree):
  447. self.base_tree=base_tree
  448. self.executed = False
  449. self.signature = signature
  450. self.inputs = {
  451. "Driver Type" : NodeSocket(is_input = True, name = "Driver Type", node = self),
  452. "Expression" : NodeSocket(is_input = True, name = "Expression", node = self),
  453. "fCurve" : NodeSocket(is_input = True, name = "fCurve", node = self),
  454. }
  455. self.outputs = {
  456. "Driver" : NodeSocket(name = "Driver", node=self),
  457. }
  458. from .drivers import MantisDriver
  459. self.parameters = {
  460. "Driver Type":None,
  461. "Expression":None,
  462. "fCurve":None,
  463. "Driver":MantisDriver(),
  464. }
  465. self.node_type = "DRIVER" # MUST be run in Pose mode
  466. setup_custom_props(self)
  467. def evaluate_input(self, input_name):
  468. return evaluate_input(self, input_name)
  469. def bExecute(self, bContext = None,):
  470. prepare_parameters(self)
  471. from .drivers import MantisDriver
  472. #prPurple("Executing Driver Node")
  473. my_vars = []
  474. for inp in list(self.inputs.keys() )[3:]:
  475. if (new_var := self.evaluate_input(inp)):
  476. new_var["name"] = inp
  477. my_vars.append(new_var)
  478. else:
  479. raise RuntimeError("Failed to initialize Driver variable")
  480. my_driver ={ "owner" : None,
  481. "prop" : None, # will be filled out in the node that uses the driver
  482. "expression" : self.evaluate_input("Expression"),
  483. "ind" : -1, # same here
  484. "type" : self.evaluate_input("Driver Type"),
  485. "vars" : my_vars,
  486. "keys" : self.evaluate_input("fCurve"), }
  487. my_driver = MantisDriver(my_driver)
  488. self.parameters["Driver"].update(my_driver)
  489. print("Initializing driver %s " % (wrapPurple(self.__repr__())) )
  490. def __repr__(self):
  491. return self.signature.__repr__()
  492. def fill_parameters(self):
  493. fill_parameters(self)
  494. class UtilitySwitch:
  495. '''A node representing an armature object'''
  496. def __init__(self, signature, base_tree):
  497. self.base_tree=base_tree
  498. self.executed = False
  499. self.signature = signature
  500. self.inputs = {
  501. "xForm" : NodeSocket(is_input = True, name = "xForm", node = self),
  502. "Parameter" : NodeSocket(is_input = True, name = "Parameter", node = self),
  503. "Parameter Index" : NodeSocket(is_input = True, name = "Parameter Index", node = self),
  504. "Invert Switch" : NodeSocket(is_input = True, name = "Invert Switch", node = self),
  505. }
  506. self.outputs = {
  507. "Driver" : NodeSocket(name = "Driver", node=self),
  508. }
  509. from .drivers import MantisDriver
  510. self.parameters = {
  511. "xForm":None,
  512. "Parameter":None,
  513. "Parameter Index":None,
  514. "Invert Switch":None,
  515. "Driver":MantisDriver(), # empty for now
  516. }
  517. self.node_type = "DRIVER" # MUST be run in Pose mode
  518. def evaluate_input(self, input_name):
  519. if input_name == 'Parameter':
  520. if self.inputs['Parameter'].is_connected:
  521. trace = trace_single_line(self, input_name)
  522. return trace[1].name # the name of the socket
  523. return self.parameters["Parameter"]
  524. return evaluate_input(self, input_name)
  525. def GetxForm(self,):
  526. trace = trace_single_line(self, "xForm" )
  527. for node in trace[0]:
  528. if (node.__class__ in [xFormRoot, xFormArmature, xFormBone]):
  529. return node #this will fetch the first one, that's good!
  530. return None
  531. def bExecute(self, bContext = None,):
  532. #prepare_parameters(self)
  533. #prPurple ("Executing Switch Node")
  534. xForm = self.GetxForm()
  535. if xForm : xForm = xForm.bGetObject()
  536. if not xForm:
  537. raise RuntimeError("Could not evaluate xForm for %s" % self)
  538. from .drivers import MantisDriver
  539. my_driver ={ "owner" : None,
  540. "prop" : None, # will be filled out in the node that uses the driver
  541. "ind" : -1, # same here
  542. "type" : "SCRIPTED",
  543. "vars" : [ { "owner" : xForm,
  544. "prop" : self.evaluate_input("Parameter"),
  545. "name" : "a",
  546. "type" : "SINGLE_PROP", } ],
  547. "keys" : [ { "co":(0,0),
  548. "interpolation": "LINEAR",
  549. "type":"KEYFRAME",}, #display type
  550. { "co":(1,1),
  551. "interpolation": "LINEAR",
  552. "type":"KEYFRAME",},], }
  553. my_driver ["expression"] = "a"
  554. my_driver = MantisDriver(my_driver)
  555. # this makes it so I can check for type later!
  556. if self.evaluate_input("Invert Switch") == True:
  557. my_driver ["expression"] = "1 - a"
  558. # this way, regardless of what order things are handled, the
  559. # driver is sent to the next node.
  560. # In the case of some drivers, the parameter may be sent out
  561. # before it's filled in (because there is a circular dependency)
  562. # I want to support this behaviour because Blender supports it,
  563. # but I also do not want to support it because it makes things
  564. # more complex and IMO it's bad practice.
  565. # We do not make a copy. We update the driver, so that
  566. # the same instance is filled out.
  567. self.parameters["Driver"].update(my_driver)
  568. print("Initializing driver %s " % (wrapPurple(self.__repr__())) )
  569. def __repr__(self):
  570. return self.signature.__repr__()
  571. def fill_parameters(self):
  572. fill_parameters(self)
  573. class UtilityCombineThreeBool:
  574. '''A node for combining three booleans into a boolean three-tuple'''
  575. def __init__(self, signature, base_tree):
  576. self.base_tree=base_tree
  577. self.executed = False
  578. self.signature = signature
  579. self.inputs = {
  580. "X" : NodeSocket(is_input = True, name = "X", node = self),
  581. "Y" : NodeSocket(is_input = True, name = "Y", node = self),
  582. "Z" : NodeSocket(is_input = True, name = "Z", node = self),
  583. }
  584. self.outputs = {
  585. "Three-Bool" : NodeSocket(name = "Three-Bool", node=self),
  586. }
  587. self.parameters = {
  588. "X":None,
  589. "Y":None,
  590. "Z":None, }
  591. self.node_type = "UTILITY"
  592. def evaluate_input(self, input_name):
  593. return evaluate_input(self, input_name)
  594. def bExecute(self, bContext = None,):
  595. #prPurple("Executing CombineThreeBool Node")
  596. #prepare_parameters(self)
  597. self.parameters["Three-Bool"] = (
  598. self.evaluate_input("X"),
  599. self.evaluate_input("Y"),
  600. self.evaluate_input("Z"), )
  601. # DO:
  602. # figure out how to get the driver at execute-time
  603. # because Blender allows circular dependencies in drivers
  604. # (sort of), I need to adopt a more convoluted way of doing
  605. # things here or elsewhere.
  606. def __repr__(self):
  607. return self.signature.__repr__()
  608. def fill_parameters(self):
  609. fill_parameters(self)
  610. # Note this is a copy of the above. This needs to be de-duplicated into
  611. # a simpler CombineVector node_container.
  612. # TODO
  613. class UtilityCombineVector:
  614. '''A node for combining three floats into a vector'''
  615. def __init__(self, signature, base_tree):
  616. self.base_tree=base_tree
  617. self.executed = False
  618. self.signature = signature
  619. self.inputs = {
  620. "X" : NodeSocket(is_input = True, name = "X", node = self),
  621. "Y" : NodeSocket(is_input = True, name = "Y", node = self),
  622. "Z" : NodeSocket(is_input = True, name = "Z", node = self),
  623. }
  624. self.outputs = {
  625. "Vector" : NodeSocket(name = "Vector", node=self),
  626. }
  627. self.parameters = {
  628. "X":None,
  629. "Y":None,
  630. "Z":None, }
  631. self.node_type = "UTILITY"
  632. def evaluate_input(self, input_name):
  633. return evaluate_input(self, input_name)
  634. def bExecute(self, bContext = None,):
  635. #prPurple("Executing CombineVector Node")
  636. prepare_parameters(self)
  637. self.parameters["Vector"] = (
  638. self.evaluate_input("X"),
  639. self.evaluate_input("Y"),
  640. self.evaluate_input("Z"), )
  641. def __repr__(self):
  642. return self.signature.__repr__()
  643. def fill_parameters(self):
  644. fill_parameters(self)
  645. class UtilityCatStrings:
  646. '''A node representing an armature object'''
  647. def __init__(self, signature, base_tree):
  648. self.base_tree=base_tree
  649. self.executed = False
  650. self.signature = signature
  651. self.inputs = {
  652. "String_1" : NodeSocket(is_input = True, name = "String_1", node = self),
  653. "String_2" : NodeSocket(is_input = True, name = "String_2", node = self),
  654. }
  655. self.outputs = {
  656. "OutputString" : NodeSocket(name = "OutputString", node=self),
  657. }
  658. self.parameters = {
  659. "String_1":None,
  660. "String_2":None,
  661. }
  662. self.node_type = "UTILITY"
  663. def evaluate_input(self, input_name):
  664. return evaluate_input(self, input_name)
  665. def bExecute(self, bContext = None,):
  666. self.parameters["OutputString"] = self.evaluate_input("String_1")+self.evaluate_input("String_2")
  667. def __repr__(self):
  668. return self.signature.__repr__()
  669. def fill_parameters(self):
  670. fill_parameters(self)
  671. class InputLayerMask:
  672. '''A node representing an armature object'''
  673. def __init__(self, signature, base_tree):
  674. self.base_tree=base_tree
  675. self.executed = False
  676. self.signature = signature
  677. self.inputs = {
  678. }
  679. self.outputs = {
  680. "Layer Mask" : NodeSocket(is_input = True, name = "Layer Mask", node = self),
  681. }
  682. self.parameters = {
  683. "Layer Mask":None,
  684. }
  685. self.node_type = "UTILITY"
  686. def evaluate_input(self, input_name):
  687. return evaluate_input(self, input_name)
  688. def bExecute(self, bContext = None,):
  689. pass
  690. def __repr__(self):
  691. return self.signature.__repr__()
  692. def fill_parameters(self):
  693. fill_parameters(self)
  694. # class InputGeometry:
  695. # '''A node representing an armature object'''
  696. # def __init__(self, signature, base_tree):
  697. # self.base_tree=base_tree
  698. # self.executed = False
  699. # self.signature = signature
  700. # self.inputs = {
  701. # "Geometry Name" : NodeSocket(is_input = True, to_socket = "Geometry Name", to_node = self),
  702. # }
  703. # self.outputs = {
  704. # "Geometry" : NodeSocket(from_socket = "Geometry", from_node=self),
  705. # }
  706. # self.parameters = {
  707. # "Geometry Name":None,
  708. # "Geometry":None,
  709. # }
  710. # self.node_type = "UTILITY"
  711. # def evaluate_input(self, input_name):
  712. # return evaluate_input(self, input_name)
  713. # def bExecute(self, bContext = None,):
  714. # pass
  715. # def __repr__(self):
  716. # return self.signature.__repr__()
  717. # def fill_parameters(self, node_prototype):
  718. # fill_parameters(self, node_prototype)
  719. class InputExistingGeometryObject:
  720. '''A node representing an existing object'''
  721. def __init__(self, signature, base_tree):
  722. self.base_tree=base_tree
  723. self.executed = False
  724. self.signature = signature
  725. self.inputs = {
  726. "Name" : NodeSocket(is_input = True, name = "Name", node = self),
  727. }
  728. self.outputs = {
  729. "Object" : NodeSocket(is_input = False, name = "Object", node=self),
  730. }
  731. self.parameters = {
  732. "Name":None,
  733. "Object":None,
  734. }
  735. self.node_type = "UTILITY"
  736. def evaluate_input(self, input_name):
  737. return evaluate_input(self, input_name)
  738. def bGetObject(self):
  739. from bpy import data
  740. return data.objects.get( self.evaluate_input("Name") )
  741. def bExecute(self, bContext = None,):
  742. pass
  743. # DO: make this data, of course
  744. # try curve and then mesh
  745. # probably should print a warning on the node if it is ambiguous
  746. def __repr__(self):
  747. return self.signature.__repr__()
  748. def fill_parameters(self):
  749. fill_parameters(self)
  750. class InputExistingGeometryData:
  751. '''A node representing existing object data'''
  752. def __init__(self, signature, base_tree):
  753. self.base_tree=base_tree
  754. self.executed = False
  755. self.signature = signature
  756. self.inputs = {
  757. "Name" : NodeSocket(is_input = True, name = "Name", node = self),
  758. }
  759. self.outputs = {
  760. "Geometry" : NodeSocket(is_input = False, name = "Geometry", node=self),
  761. }
  762. self.parameters = {
  763. "Name":None,
  764. "Geometry":None,
  765. }
  766. self.node_type = "UTILITY"
  767. def evaluate_input(self, input_name):
  768. return evaluate_input(self, input_name)
  769. def bGetObject(self):
  770. from bpy import data
  771. # first try Curve, then try Mesh
  772. bObject = data.curves.get(self.evaluate_input("Name"))
  773. if not bObject:
  774. bObject = data.meshes.get(self.evaluate_input("Name"))
  775. return bObject
  776. def bExecute(self, bContext = None,):
  777. pass
  778. def __repr__(self):
  779. return self.signature.__repr__()
  780. def fill_parameters(self):
  781. fill_parameters(self)