__init__.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. from . import ( ops_nodegroup,
  2. base_definitions,
  3. socket_definitions,
  4. link_definitions,
  5. xForm_definitions,
  6. misc_nodes_ui,
  7. primitives_definitions,
  8. deformer_definitions,
  9. math_definitions,
  10. i_o,
  11. schema_definitions,
  12. )
  13. from .ops_generate_tree import GenerateMantisTree
  14. from .utilities import prRed
  15. MANTIS_VERSION_MAJOR=0
  16. MANTIS_VERSION_MINOR=10
  17. MANTIS_VERSION_SUB=11
  18. classLists = [module.TellClasses() for module in [
  19. link_definitions,
  20. xForm_definitions,
  21. misc_nodes_ui,
  22. socket_definitions,
  23. ops_nodegroup,
  24. primitives_definitions,
  25. deformer_definitions,
  26. math_definitions,
  27. i_o,
  28. schema_definitions,
  29. base_definitions,
  30. ]]
  31. classLists.append( [GenerateMantisTree] )
  32. #
  33. classes = []
  34. while (classLists):
  35. classes.extend(classLists.pop())
  36. interface_classes = []
  37. import nodeitems_utils
  38. from nodeitems_utils import NodeCategory, NodeItem
  39. class MantisNodeCategory(NodeCategory):
  40. @classmethod
  41. def poll(cls, context):
  42. return (context.space_data.tree_type in ['MantisTree', 'SchemaTree'])
  43. class SchemaNodeCategory(NodeCategory):
  44. @classmethod
  45. def poll(cls, context):
  46. return (context.space_data.path[len(context.space_data.path)-1].node_tree.bl_idname == 'SchemaTree')
  47. class MantisGroupCategory(NodeCategory):
  48. @classmethod
  49. def poll(cls, context):
  50. return (context.space_data.path[len(context.space_data.path)-1].node_tree.bl_idname in ['MantisTree'] and len(context.space_data.path)>1)
  51. input_category=[
  52. NodeItem("InputFloatNode"),
  53. NodeItem("InputVectorNode"),
  54. NodeItem("InputBooleanNode"),
  55. NodeItem("InputStringNode"),
  56. NodeItem("InputIntNode"),
  57. NodeItem("InputMatrixNode"),
  58. NodeItem("InputExistingGeometryObject"),
  59. NodeItem("InputExistingGeometryData"),
  60. ]
  61. link_transform_category = [
  62. NodeItem("LinkCopyLocation"),
  63. NodeItem("LinkCopyRotation"),
  64. NodeItem("LinkCopyScale"),
  65. NodeItem("LinkCopyTransforms"),
  66. NodeItem("LinkLimitLocation"),
  67. NodeItem("LinkLimitScale"),
  68. NodeItem("LinkLimitRotation"),
  69. NodeItem("LinkLimitDistance"),
  70. NodeItem("LinkTransformation"),
  71. ]
  72. link_tracking_category = [
  73. NodeItem("LinkInverseKinematics"),
  74. NodeItem("LinkSplineIK"),
  75. NodeItem("LinkStretchTo"),
  76. NodeItem("LinkDampedTrack"),
  77. NodeItem("LinkLockedTrack"),
  78. NodeItem("LinkTrackTo"),
  79. ]
  80. link_relationship_category = [
  81. NodeItem("linkInherit"),
  82. NodeItem("LinkInheritConstraint"),
  83. NodeItem("LinkArmature"),
  84. ]
  85. deformer_category=[NodeItem(cls.bl_idname) for cls in deformer_definitions.TellClasses()]
  86. xForm_category = [
  87. NodeItem("xFormGeometryObject"),
  88. NodeItem("xFormBoneNode"),
  89. NodeItem("xFormArmatureNode"),
  90. NodeItem("xFormObjectInstance"),
  91. NodeItem("xFormCurvePin"),
  92. ]
  93. driver_category = [
  94. NodeItem("LinkDrivenParameter"),
  95. NodeItem("UtilityFCurve"),
  96. NodeItem("UtilityBoneProperties"),
  97. NodeItem("UtilityDriverVariable"),
  98. NodeItem("UtilitySwitch"),
  99. NodeItem("UtilityDriver"),
  100. NodeItem("UtilityKeyframe"),
  101. ]
  102. geometry_category = [
  103. NodeItem("GeometryCirclePrimitive"),
  104. ]
  105. utility_category = [
  106. NodeItem("MathStaticInt"),
  107. NodeItem("MathStaticFloat"),
  108. NodeItem("MathStaticVector"),
  109. NodeItem("UtilityCatStrings"),
  110. NodeItem("UtilityGeometryOfXForm"),
  111. NodeItem("UtilityNameOfXForm"),
  112. NodeItem("UtilityCombineThreeBool"),
  113. NodeItem("UtilityCombineVector"),
  114. NodeItem("UtilityIntToString"),
  115. NodeItem("UtilityArrayGet"),
  116. NodeItem("UtilityArrayLength"),
  117. NodeItem("UtilityChoose"),
  118. NodeItem("UtilityCompare"),
  119. NodeItem("UtilityPrint"),
  120. NodeItem("UtilitySeparateVector"),
  121. NodeItem("UtilityGetNearestFactorOnCurve"),
  122. NodeItem("UtilityKDChoosePoint"),
  123. NodeItem("UtilityKDChooseXForm"),
  124. ]
  125. matrix_category = [
  126. NodeItem("UtilityMetaRig"),
  127. NodeItem("UtilityMatrixFromCurve"),
  128. NodeItem("UtilityMatricesFromCurve"),
  129. NodeItem("UtilityNumberOfCurveSegments"),
  130. NodeItem("UtilityMatrixFromCurveSegment"),
  131. NodeItem("UtilityPointFromCurve"),
  132. NodeItem("UtilityGetCurvePoint"),
  133. NodeItem("UtilityPointFromBoneMatrix"),
  134. NodeItem("UtilitySetBoneLength"),
  135. NodeItem("UtilityGetBoneLength"),
  136. NodeItem("UtilityBoneMatrixHeadTailFlip"),
  137. NodeItem("UtilityMatrixSetLocation"),
  138. NodeItem("UtilityMatrixFromXForm"),
  139. NodeItem("UtilityAxesFromMatrix"),
  140. NodeItem("UtilityMatrixTransform"),
  141. NodeItem("UtilityMatrixInvert"),
  142. NodeItem("UtilityMatrixCompose"),
  143. NodeItem("UtilityMatrixAlignRoll"),
  144. NodeItem("UtilityTransformationMatrix"),
  145. NodeItem("UtilitySetBoneMatrixTail"),
  146. ]
  147. groups_category = [
  148. NodeItem("MantisNodeGroup"),
  149. NodeItem("MantisSchemaGroup"),
  150. ]
  151. group_interface_category = [
  152. NodeItem("NodeGroupInput"),
  153. NodeItem("NodeGroupOutput"),
  154. ]
  155. node_categories = [
  156. # identifier, label, items list
  157. MantisNodeCategory('INPUT', "Input", items=input_category),
  158. MantisNodeCategory('LINK_TRANSFORM', "Link (Transform)", items=link_transform_category),
  159. MantisNodeCategory('LINK_TRACKING', "Link (Tracking)", items=link_tracking_category),
  160. MantisNodeCategory('LINK_RELATIONSHIP', "Link (Inheritance)", items=link_relationship_category),
  161. MantisNodeCategory('DEFORMER', "Deformer", items=deformer_category),
  162. MantisNodeCategory('XFORM', "Transform", items=xForm_category),
  163. MantisNodeCategory('DRIVER', "Driver", items=driver_category),
  164. MantisNodeCategory('GEOMETRY', "Geometry", items =geometry_category),
  165. MantisNodeCategory('UTILITIES', "Utility", items=utility_category),
  166. MantisNodeCategory('MATRIX', "Matrix", items=matrix_category),
  167. MantisNodeCategory('GROUPS', "Groups", items=groups_category),
  168. MantisGroupCategory('GROUP_INTERFACE', "Group In/Out", items=group_interface_category),
  169. ]
  170. schema_category=[NodeItem(cls.bl_idname) for cls in schema_definitions.TellClasses()]
  171. schema_categories = [
  172. SchemaNodeCategory('SCHEMA_SCHEMA', "Schema", items=schema_category),
  173. ]
  174. import bpy
  175. def init_keymaps():
  176. kc = bpy.context.window_manager.keyconfigs.addon
  177. km = kc.keymaps.new(name="Node Generic", space_type='NODE_EDITOR')
  178. kmi = [
  179. # Normal operation
  180. km.keymap_items.new("mantis.group_nodes", 'G', 'PRESS', ctrl=True),
  181. km.keymap_items.new("mantis.edit_group", 'TAB', 'PRESS'),
  182. km.keymap_items.new("mantis.execute_node_tree", 'E', 'PRESS'),
  183. km.keymap_items.new("mantis.mute_node", 'M', 'PRESS'),
  184. km.keymap_items.new("mantis.nodes_cleanup", "C", 'PRESS', shift=True,),
  185. # Testing
  186. km.keymap_items.new("mantis.query_sockets", 'Q', 'PRESS'),
  187. km.keymap_items.new("mantis.test_operator", 'T', 'PRESS'),
  188. km.keymap_items.new("mantis.visualize_output", 'V', 'PRESS'),
  189. # Saving, Loading, Reloading, etc.
  190. km.keymap_items.new("mantis.export_save_choose", "S", 'PRESS', alt=True,),
  191. km.keymap_items.new("mantis.export_save_as", "S", 'PRESS', alt=True, shift=True),
  192. km.keymap_items.new("mantis.reload_tree", "R", 'PRESS', alt=True,),
  193. km.keymap_items.new("mantis.import_tree", "O", 'PRESS', ctrl=True,),
  194. ]
  195. return km, kmi
  196. addon_keymaps = []
  197. # handlers! these have to be persistent
  198. from bpy.app.handlers import persistent
  199. @persistent
  200. def update_handler(scene):
  201. context=bpy.context
  202. if context.space_data:
  203. if not hasattr(context.space_data, "path"):
  204. return
  205. trees = [p.node_tree for p in context.space_data.path]
  206. if not trees: return
  207. if (node_tree := trees[0]).bl_idname in ['MantisTree']:
  208. if node_tree.is_exporting:
  209. return
  210. if node_tree.prevent_next_exec : pass
  211. elif node_tree.do_live_update and not (node_tree.is_executing):
  212. prev_links = node_tree.num_links
  213. node_tree.num_links = len(node_tree.links)
  214. if (prev_links == -1):
  215. return
  216. if prev_links != node_tree.num_links:
  217. node_tree.tree_valid = False
  218. if node_tree.tree_valid == False:
  219. scene.render.use_lock_interface = True
  220. node_tree.update_tree(context)
  221. scene.render.use_lock_interface = False
  222. @persistent
  223. def execute_handler(scene):
  224. context = bpy.context
  225. if context.space_data:
  226. if not hasattr(context.space_data, "path"):
  227. return
  228. trees = [p.node_tree for p in context.space_data.path]
  229. if not trees: return
  230. if (node_tree := trees[0]).bl_idname in ['MantisTree']:
  231. if node_tree.is_exporting:
  232. return
  233. if node_tree.prevent_next_exec : node_tree.prevent_next_exec = False
  234. elif node_tree.tree_valid and node_tree.do_live_update and not (node_tree.is_executing):
  235. scene.render.use_lock_interface = True
  236. node_tree.execute_tree(context)
  237. scene.render.use_lock_interface = False
  238. node_tree.tree_valid = False
  239. versioning_node_tasks = [
  240. #relevant bl_idnames # task
  241. #(['LinkTransformation'], transformation_constraint_radians_to_degrees)
  242. ]
  243. def do_version_update(node_tree):
  244. from .base_definitions import NODES_REMOVED, SOCKETS_REMOVED, SOCKETS_RENAMED, SOCKETS_ADDED
  245. for n in node_tree.nodes:
  246. rename_jobs = []
  247. if n.bl_idname in NODES_REMOVED:
  248. print(f"INFO: removing node {n.name} of type {n.bl_idname} because it has been deprecated.")
  249. n.inputs.remove(socket)
  250. continue
  251. for i, socket in enumerate(n.inputs.values()):
  252. if (n.bl_idname, socket.identifier) in SOCKETS_REMOVED:
  253. print(f"INFO: removing socket {socket.identifier} of node {n.name} of type {n.bl_idname} because it has been deprecated.")
  254. n.inputs.remove(socket)
  255. for old_class, old_bl_idname, old_name, new_bl_idname, new_name, multi in SOCKETS_RENAMED:
  256. if (n.bl_idname == old_class and socket.bl_idname == old_bl_idname and socket.name == old_name):
  257. rename_jobs.append((socket, i, new_bl_idname, new_name, multi))
  258. for i, socket in enumerate(n.outputs.values()):
  259. if (n.bl_idname, socket.identifier) in SOCKETS_REMOVED:
  260. print(f"INFO: removing socket {socket.identifier} of node {n.name} of type {n.bl_idname} because it has been deprecated.")
  261. n.outputs.remove(socket)
  262. for old_class, old_bl_idname, old_name, new_bl_idname, new_name, multi in SOCKETS_RENAMED:
  263. if (n.bl_idname == old_class and socket.bl_idname == old_bl_idname and socket.name == old_name):
  264. rename_jobs.append((socket, i, new_bl_idname, new_name, multi))
  265. for bl_idname, in_out, socket_type, socket_name, index, use_multi_input, default_val in SOCKETS_ADDED:
  266. if n.bl_idname != bl_idname:
  267. continue
  268. if in_out == 'INPUT' and n.inputs.get(socket_name) is None:
  269. print(f"INFO: adding socket \"{socket_name}\" of type {socket_type} to node {n.name} of type {n.bl_idname}.")
  270. s = n.inputs.new(socket_type, socket_name, use_multi_input=use_multi_input)
  271. s.default_value = default_val
  272. n.inputs.move(len(n.inputs)-1, index)
  273. socket_map = None
  274. if rename_jobs:
  275. from .utilities import get_socket_maps
  276. socket_maps = get_socket_maps(n)
  277. for socket, socket_index, new_bl_idname, new_name, multi in rename_jobs:
  278. old_id = socket.identifier
  279. print (f"Renaming socket {socket.identifier} to {new_name} in node {n.name}")
  280. from .utilities import do_relink
  281. if socket.is_output:
  282. index = 1
  283. in_out = "OUTPUT"
  284. n.outputs.remove(socket)
  285. s = n.outputs.new(new_bl_idname, new_name, identifier=new_name, use_multi_input=multi)
  286. n.outputs.move(len(n.outputs)-1, socket_index)
  287. socket_map = socket_maps[1]
  288. else:
  289. index = 0
  290. in_out = "INPUT"
  291. n.inputs.remove(socket)
  292. s = n.inputs.new(new_bl_idname, new_name, identifier=new_name, use_multi_input=multi)
  293. n.inputs.move(len(n.inputs)-1, socket_index)
  294. socket_map = socket_maps[0]
  295. socket_map[new_name] = socket_map[old_id]; del socket_map[old_id]
  296. do_relink(n, s, socket_map)
  297. for bl_idname, task in versioning_node_tasks:
  298. if n.bl_idname in bl_idname: task(n)
  299. # increment the version at the end
  300. node_tree.mantis_version[0] = MANTIS_VERSION_MAJOR
  301. node_tree.mantis_version[1] = MANTIS_VERSION_MINOR
  302. node_tree.mantis_version[2] = MANTIS_VERSION_SUB
  303. @persistent
  304. def version_update_handler(filename):
  305. for node_tree in bpy.data.node_groups: # ensure it can update again after file load.
  306. if node_tree.bl_idname in ["MantisTree", "SchemaTree"]:
  307. node_tree.is_exporting=False; node_tree.is_executing=False
  308. for node_tree in bpy.data.node_groups:
  309. if node_tree.bl_idname in ["MantisTree", "SchemaTree"]:
  310. if (node_tree.mantis_version[0] < MANTIS_VERSION_MAJOR) or \
  311. (node_tree.mantis_version[1] < MANTIS_VERSION_MINOR) or \
  312. (node_tree.mantis_version[2] < MANTIS_VERSION_SUB):
  313. print (f"Updating tree {node_tree.name} to {MANTIS_VERSION_MAJOR}.{MANTIS_VERSION_MINOR}.{MANTIS_VERSION_SUB}")
  314. do_version_update(node_tree)
  315. # I'll need to do some fiddling here when it comes time to try
  316. # and make rig definitions animatable.
  317. @persistent
  318. def on_animation_playback_pre_handler(scene,depsgraph):
  319. for t in bpy.data.node_groups:
  320. if t.bl_idname in ['MantisTree', 'SchemaTree']:
  321. t.is_executing = True
  322. @persistent
  323. def on_animation_playback_post_handler(scene,depsgraph):
  324. for t in bpy.data.node_groups:
  325. if t.bl_idname in ['MantisTree', 'SchemaTree']:
  326. t.is_executing = False
  327. @persistent
  328. def on_undo_pre_handler(scene): # the undo will trigger a depsgraph update
  329. for t in bpy.data.node_groups: # so we enable prevent_next_exec.
  330. if t.bl_idname in ['MantisTree', 'SchemaTree']:
  331. t.prevent_next_exec = True
  332. @persistent
  333. def on_undo_post_handler(scene): # the undo will trigger a depsgraph update
  334. for t in bpy.data.node_groups: # so we enable prevent_next_exec.
  335. if t.bl_idname in ['MantisTree', 'SchemaTree']:
  336. t.prevent_next_exec = True
  337. @persistent
  338. def on_save_pre_handler(scene): # save-as will trigger a depsgraph update
  339. for t in bpy.data.node_groups: # so we enable prevent_next_exec.
  340. if t.bl_idname in ['MantisTree', 'SchemaTree']:
  341. t.prevent_next_exec = True
  342. # annoyingly, regular save does not trigger a DG update so we also need this:
  343. @persistent
  344. def on_save_post_handler(scene): # The DG has already updated and we can disable this.
  345. for t in bpy.data.node_groups:
  346. if t.bl_idname in ['MantisTree', 'SchemaTree']:
  347. t.prevent_next_exec = False
  348. def register():
  349. from bpy.utils import register_class
  350. for cls in classes:
  351. try:
  352. register_class(cls)
  353. except RuntimeError as e:
  354. prRed(f"Registration error for class: {cls.__name__}")
  355. raise e
  356. nodeitems_utils.register_node_categories('MantisNodeCategories', node_categories)
  357. nodeitems_utils.register_node_categories('SchemaNodeCategories', schema_categories)
  358. km, kmi = init_keymaps()
  359. for k in kmi:
  360. k.active = True
  361. addon_keymaps.append((km, k))
  362. # add the handlers
  363. bpy.app.handlers.depsgraph_update_pre.insert(0, update_handler)
  364. bpy.app.handlers.depsgraph_update_post.insert(0, execute_handler)
  365. bpy.app.handlers.save_pre.insert(0, on_save_pre_handler)
  366. bpy.app.handlers.save_post.insert(0, on_save_post_handler)
  367. bpy.app.handlers.load_post.insert(0, version_update_handler)
  368. bpy.app.handlers.animation_playback_pre.insert(0, on_animation_playback_pre_handler)
  369. bpy.app.handlers.animation_playback_post.insert(0, on_animation_playback_post_handler)
  370. bpy.app.handlers.undo_pre.insert(0, on_undo_pre_handler)
  371. # I'm adding mine in first to ensure other addons don't mess up mine
  372. # but I am a good citizen! so my addon won't mess up yours! probably...
  373. def unregister():
  374. for tree in bpy.data.node_groups: # ensure it doesn't try to update while quitting.
  375. if tree.bl_idname in ['MantisTree, SchemaTree']:
  376. tree.is_exporting=True; tree.is_executing=True
  377. nodeitems_utils.unregister_node_categories('MantisNodeCategories')
  378. nodeitems_utils.unregister_node_categories('SchemaNodeCategories')
  379. from bpy.utils import unregister_class
  380. for cls in reversed(classes):
  381. unregister_class(cls)
  382. for km, kmi in addon_keymaps:
  383. km.keymap_items.remove(kmi)
  384. addon_keymaps.clear()