| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641 |
- from .utilities import prRed, prGreen, prPurple, prWhite, prOrange, \
- wrapRed, wrapGreen, wrapPurple, wrapWhite, wrapOrange
- # what in the cuss is this horrible abomination??
- def class_for_mantis_prototype_node(prototype_node):
- """ This is a class which returns a class to instantiate for
- the given prototype node."""
- #from .node_container_classes import TellClasses
- from mantis import xForm_containers, link_containers, misc_containers, primitives_containers, deformer_containers
- classes = {}
- for module in [xForm_containers, link_containers, misc_containers, primitives_containers, deformer_containers]:
- for cls in module.TellClasses():
- classes[cls.__name__] = cls
- # I could probably do a string.replace() here
- # But I actually think this is a bad idea since I might not
- # want to use this name convention in the future
- # this is easy enough for now, may refactor.
- #
- # kek, turns out it was completely friggin' inconsistent already
- if prototype_node.bl_idname == 'xFormRootNode':
- return classes["xFormRoot"]
- elif prototype_node.bl_idname == 'xFormArmatureNode':
- return classes["xFormArmature"]
- elif prototype_node.bl_idname == 'xFormBoneNode':
- return classes["xFormBone"]
- elif prototype_node.bl_idname == 'xFormGeometryObject':
- return classes["xFormGeometryObject"]
- elif prototype_node.bl_idname == 'linkInherit':
- return classes["LinkInherit"]
- # BAD need to fix the above, bl_idname is not consistent
- # Copy's
- elif prototype_node.bl_idname == 'LinkCopyLocation':
- return classes["LinkCopyLocation"] # also bad
- elif prototype_node.bl_idname == 'LinkCopyRotation':
- return classes["LinkCopyRotation"]
- elif prototype_node.bl_idname == 'LinkCopyScale':
- return classes["LinkCopyScale"]
- elif prototype_node.bl_idname == 'LinkCopyTransforms':
- return classes["LinkCopyTransforms"]
- # Limits
- elif prototype_node.bl_idname == 'LinkLimitLocation':
- return classes["LinkLimitLocation"]
- elif prototype_node.bl_idname == 'LinkLimitRotation':
- return classes["LinkLimitRotation"]
- elif prototype_node.bl_idname == 'LinkLimitScale':
- return classes["LinkLimitScale"]
- elif prototype_node.bl_idname == 'LinkLimitDistance':
- return classes["LinkLimitDistance"]
- # tracking
- elif prototype_node.bl_idname == 'LinkStretchTo':
- return classes["LinkStretchTo"]
- elif prototype_node.bl_idname == 'LinkDampedTrack':
- return classes["LinkDampedTrack"]
- elif prototype_node.bl_idname == 'LinkLockedTrack':
- return classes["LinkLockedTrack"]
- elif prototype_node.bl_idname == 'LinkTrackTo':
- return classes["LinkTrackTo"]
- # misc
- elif prototype_node.bl_idname == 'LinkInheritConstraint':
- return classes["LinkInheritConstraint"]
- # IK
- elif prototype_node.bl_idname == 'LinkInverseKinematics':
- return classes["LinkInverseKinematics"]
- elif prototype_node.bl_idname == 'LinkSplineIK':
- return classes["LinkSplineIK"]
- # utilities
- elif prototype_node.bl_idname == 'InputFloatNode':
- return classes["InputFloat"]
- elif prototype_node.bl_idname == 'InputVectorNode':
- return classes["InputVector"]
- elif prototype_node.bl_idname == 'InputBooleanNode':
- return classes["InputBoolean"]
- elif prototype_node.bl_idname == 'InputBooleanThreeTupleNode':
- return classes["InputBooleanThreeTuple"]
- elif prototype_node.bl_idname == 'InputRotationOrderNode':
- return classes["InputRotationOrder"]
- elif prototype_node.bl_idname == 'InputTransformSpaceNode':
- return classes["InputTransformSpace"]
- elif prototype_node.bl_idname == 'InputStringNode':
- return classes["InputString"]
- elif prototype_node.bl_idname == 'InputQuaternionNode':
- return classes["InputQuaternion"]
- elif prototype_node.bl_idname == 'InputQuaternionNodeAA':
- return classes["InputQuaternionAA"]
- elif prototype_node.bl_idname == 'InputMatrixNode':
- return classes["InputMatrix"]
- elif prototype_node.bl_idname == 'MetaRigMatrixNode':
- return classes["InputMatrix"]
- elif prototype_node.bl_idname == 'InputLayerMaskNode':
- return classes["InputLayerMask"]
- # geometry
- elif prototype_node.bl_idname == 'GeometryCirclePrimitive':
- return classes["CirclePrimitive"]
- # Deformers:
- elif prototype_node.bl_idname == 'DeformerArmature':
- return classes["DeformerArmature"]
-
- # every node before this point is not guarenteed to follow the pattern
- # but every node not checked above does follow the pattern.
-
- try:
- return classes[ prototype_node.bl_idname ]
- except KeyError:
- pass
-
- if prototype_node.bl_idname in [
- "NodeReroute",
- "NodeGroupInput",
- "NodeGroupOutput",
- "MantisNodeGroup",
- "NodeFrame",
- ]:
- return None
-
- prRed(prototype_node.bl_idname)
- raise RuntimeError("Failed to create node container for: %s" % prototype_node.bl_idname)
- return None
- # This is really, really stupid HACK
- def gen_nc_input_for_data(socket):
- # Class List #TODO deduplicate
- from mantis import xForm_containers, link_containers, misc_containers, primitives_containers, deformer_containers
- classes = {}
- for module in [xForm_containers, link_containers, misc_containers, primitives_containers, deformer_containers]:
- for cls in module.TellClasses():
- classes[cls.__name__] = cls
- #
- socket_class_map = {
- "MatrixSocket" : classes["InputMatrix"],
- "xFormSocket" : None,
- "xFormMultiSocket" : None,
- "RelationshipSocket" : classes["xFormRoot"], # world in
- "DeformerSocket" : classes["xFormRoot"], # world in
- "GeometrySocket" : classes["InputExistingGeometryData"],
- "EnableSocket" : classes["InputBoolean"],
- "HideSocket" : classes["InputBoolean"],
- #
- "DriverSocket" : None,
- "DriverVariableSocket" : None,
- "FCurveSocket" : None,
- "KeyframeSocket" : None,
- "LayerMaskInputSocket" : classes["InputLayerMask"],
- "LayerMaskSocket" : classes["InputLayerMask"],
- #
- "xFormParameterSocket" : None,
- "ParameterBoolSocket" : classes["InputBoolean"],
- "ParameterIntSocket" : classes["InputFloat"], #TODO: make an Int node for this
- "ParameterFloatSocket" : classes["InputFloat"],
- "ParameterVectorSocket" : classes["InputVector"],
- "ParameterStringSocket" : classes["InputString"],
- #
- "TransformSpaceSocket" : classes["InputTransformSpace"],
- "BooleanSocket" : classes["InputBoolean"],
- "BooleanThreeTupleSocket" : classes["InputBooleanThreeTuple"],
- "RotationOrderSocket" : classes["InputRotationOrder"],
- "QuaternionSocket" : classes["InputQuaternion"],
- "QuaternionSocketAA" : classes["InputQuaternionAA"],
- "IntSocket" : classes["InputFloat"],
- "StringSocket" : classes["InputString"],
- #
- "BoolUpdateParentNode" : classes["InputBoolean"],
- "IKChainLengthSocket" : classes["InputFloat"],
- "EnumInheritScale" : classes["InputString"],
- "EnumRotationMix" : classes["InputString"],
- "EnumRotationMixCopyTransforms" : classes["InputString"],
- "EnumMaintainVolumeStretchTo" : classes["InputString"],
- "EnumRotationStretchTo" : classes["InputString"],
- "EnumTrackAxis" : classes["InputString"],
- "EnumUpAxis" : classes["InputString"],
- "EnumLockAxis" : classes["InputString"],
- "EnumLimitMode" : classes["InputString"],
- "EnumYScaleMode" : classes["InputString"],
- "EnumXZScaleMode" : classes["InputString"],
- # Deformers
- "EnumSkinning" : classes["InputString"],
- #
- "FloatSocket" : classes["InputFloat"],
- "FloatFactorSocket" : classes["InputFloat"],
- "FloatPositiveSocket" : classes["InputFloat"],
- "FloatAngleSocket" : classes["InputFloat"],
- "VectorSocket" : classes["InputVector"],
- "VectorEulerSocket" : classes["InputVector"],
- "VectorTranslationSocket" : classes["InputVector"],
- "VectorScaleSocket" : classes["InputVector"],
- # Drivers
- "EnumDriverVariableType" : classes["InputString"],
- "EnumDriverVariableEvaluationSpace" : classes["InputString"],
- "EnumDriverRotationMode" : classes["InputString"],
- "EnumDriverType" : classes["InputString"],
- }
- return socket_class_map.get(socket.bl_idname, None)
- class DummyLink:
- #gonna use this for faking links to keep the interface consistent
- def __init__(self, from_socket, to_socket, nc_from=None, nc_to=None, original_from=None):
- self.from_socket = from_socket
- self.to_socket = to_socket
- self.nc_from = nc_from
- self.nc_to = nc_to
- if (original_from):
- self.original_from = original_from
- else:
- self.original_from = self.from_socket
- def __repr__(self):
- return(self.nc_from.__repr__()+":"+self.from_socket.name + " -> " + self.nc_to.__repr__()+":"+self.to_socket.name)
- # We'll treat this as a "dangling" link if either socket is unset...
- # # May or may not use this for my Dummy Links to help me connect things
- # # I think I can avoid it tho
- # class DummyNode:
- # def __init__(self, signature, base_tree, prototype):
- # self.signature = signature
- # self.base_tree = base_tree
- # self.prototype = prototype
- # This really might be useful in sorting the tree, too.
- def socket_seek(start_link, links):
- link = start_link
- while(link.from_socket):
- for newlink in links:
- if link.from_socket.node.inputs:
- if newlink.to_socket == link.from_socket.node.inputs[0]:
- link=newlink; break
- else:
- break
- return link.from_socket
-
- def clear_reroutes(links):
- kept_links, rerouted_starts = [], []
- rerouted = []
- all_links = links.copy()
- while(all_links):
- link = all_links.pop()
- to_cls = link.to_socket.node.bl_idname
- from_cls = link.from_socket.node.bl_idname
- reroute_classes = ["NodeReroute"]
- if (to_cls in reroute_classes and
- from_cls in reroute_classes):
- rerouted.append(link)
- elif (to_cls in reroute_classes and not
- from_cls in reroute_classes):
- rerouted.append(link)
- elif (from_cls in reroute_classes and not
- to_cls in reroute_classes):
- rerouted_starts.append(link)
- else:
- kept_links.append(link)
- for start in rerouted_starts:
- from_socket = socket_seek(start, rerouted)
- new_link = DummyLink(from_socket=from_socket, to_socket=start.to_socket, nc_from=None, nc_to=None)
- kept_links.append(new_link)
- return kept_links
- def data_from_tree(base_tree, tree_path = [None], held_links = {}, all_nc = {}):
- # prGreen("Starting! Base Tree: %s, held nodes: %d, held links: %d, nc's: %d" % (base_tree.name, len(held_nodes), len(held_links), len(all_nc)))
- # prPurple(tree_path)
- nc_dict = {}
- tree_path_names = [tree.name for tree in tree_path if hasattr(tree, "name")]
- all_child_ng = []
- tree = base_tree
- if tree_path[-1]:
- tree = tree_path[-1].node_tree
-
- # Start by looking through the nodes and making nc's where possible
- # store the groups, we'll pricess them soon.
- for np in tree.nodes:
- if (nc_cls := class_for_mantis_prototype_node(np)):
- nc = nc_cls( sig := tuple([None] + tree_path_names + [np.name]) , base_tree)
- nc_dict[sig] = nc; all_nc[sig] = nc
- if hasattr(np, "node_tree"):
- all_child_ng.append(np)
- # Then deal with the links in the current tree and the held_links.
- kept_links, incoming, outgoing = [], [], []
- all_links = clear_reroutes(list(tree.links))
- while(all_links):
- link = all_links.pop()
- to_cls = link.to_socket.node.bl_idname
- from_cls = link.from_socket.node.bl_idname
- if (from_cls in ["NodeGroupInput"]):
- incoming.append(link)
- elif (to_cls in ["NodeGroupOutput"]):
- nc_from = nc_dict.get( tuple([None]+tree_path_names+[link.from_socket.node.name]) )
- to_s = link.to_socket.identifier
- # Let's try and connect it now; go UP:
- nc_to, new_link = None, None
-
- if len(tree_path)==1:
- prRed("Warning: There is a GroupOutput node in the Base Tree.")
- kept_links.append(link)
- continue
- elif tree_path[-2] is None:
- up_tree=base_tree
- else:
- up_tree=tree_path[-2].node_tree
-
- for up_node in up_tree.nodes:
- for out in up_node.outputs:
- if not hasattr(up_node, "node_tree"):
- continue
- if not out.is_linked:
- continue
- for up_link in out.links:
- if up_link.from_socket.identifier == to_s:
- new_link = DummyLink(from_socket=up_link.from_socket, to_socket=up_link.to_socket, nc_from=nc_from, nc_to=None)
- link_sig = tuple([None]+tree_path_names[:-1]+[up_link.to_socket.node.name, link.from_socket.name])
- held_links[link_sig] = new_link
- nc_from, nc_to = None, None # clear them
- elif (from_cls in ["MantisNodeGroup"]):
- outgoing.append(link)
- else:
- kept_links.append(link)
- # Make the connections:
- for link in kept_links:
- nc_from = nc_dict.get( tuple([None] + tree_path_names + [link.from_socket.node.name]) )
- nc_to = nc_dict.get( tuple([None] + tree_path_names + [link.to_socket.node.name]) )
- if (nc_from and nc_to):
- from_s, to_s = link.from_socket.name, link.to_socket.name
- connection = nc_from.outputs[from_s].connect(node=nc_to, socket=to_s)
- nc_from = None; nc_to = None #clear them, since we use the same variable names again
-
- # At this point we're also gonna deal with held links and held nodes
- hold_further = {}
- del_me = set() # I donno why but there can be dupes.
- for link_sig, held in held_links.items():
- found, connected = False, False
- nc_from, from_s = held.nc_from, held.original_from.name
- watch = (nc_from.signature[-1] == 'Parent') and (tree_path_names[-1] in ["right", "left"])
- for link in incoming:
- if watch:
- prWhite(link_sig)
- if ((link.from_socket.identifier != link_sig[-1]) or
- (link.from_socket.name != link_sig[-2])):
- continue # This ain't it
- if (link.from_socket.identifier == link_sig[-1]):
- if (link.to_socket.node.bl_idname in [ "MantisNodeGroup" ]):
- del_me.add(link_sig)
- link_sig = tuple(list(link_sig[:-2]) + [link.to_socket.name, link.to_socket.identifier])
- hold_further[link_sig] = DummyLink(from_socket = held.from_socket, to_socket = link.to_socket, nc_from=nc_from, nc_to = None, original_from=held.original_from)
- prGreen("Holding further %s" % held.original_from.name)
- continue # just continue to hold it
- found = True
- # TO-Node:
- to_s = link.to_socket.name
- sig_to = tuple([None] + tree_path_names + [link.to_socket.node.name])
- nc_to = nc_dict.get( sig_to )
- if (nc_to and nc_from):
- if watch:
- prGreen("Connecting: %s%s -> %s%s" % (nc_from, from_s, nc_to, to_s) )
- connection = nc_from.outputs[from_s].connect(node=nc_to, socket=to_s)
- connected = True
- elif watch:
- prRed("Not Connecting: %s%s -> %s%s" % (nc_from, from_s, nc_to, to_s) )
- if (connected) != found:
- print(wrapRed("Not Connected: ") ,link_sig, held)
-
- # it's fairly annoying that I can't do this while I go.
- # for k in del_me:
- # del held_links[k]
- for k,v in hold_further.items():
- held_links[k] = v
-
-
- for ng in all_child_ng:
- for inp in ng.inputs:
- if not inp.is_linked:
- nc_cls = gen_nc_input_for_data(inp)
- if (nc_cls):
- sig = ("MANTIS_AUTOGENERATED", *tree_path_names, inp.node.name, inp.identifier)
- nc = nc_cls(sig, tree)
- # HACK HACK HACK
- for k, v in nc.outputs.items():
- v.name = inp.name; break
- from mantis.node_container_common import NodeSocket
- nc.outputs[inp.name] = NodeSocket(name = inp.name, node=nc)
- # del nc.outputs[k]; del nc.parameters[k]
- nc.parameters[inp.name]=inp.default_value
- # HACK HACK HACK
-
- nc_dict[sig] = nc; all_nc[sig] = nc
-
- dummy = DummyLink(from_socket = inp, to_socket = inp, nc_from=nc, nc_to=None)
- link_sig = tuple([None] + tree_path_names +[ng.name, inp.name, inp.identifier])
- held_links[link_sig]=dummy
- else: # We need to hold the incoming connections
- for link in inp.links: #Usually there will only be 1
- from_socket = link.from_socket
- if (link.from_socket.node.bl_idname == "NodeGroupInput"):
- # shouldn't there be a held link for this?
- continue
-
- if (link.from_socket.node.bl_idname == "NodeReroute"):
- from_socket = socket_seek(link, list(tree.links))
- sig = tuple( [None] + tree_path_names +[from_socket.node.name])
- # print(sig)
- nc_from = nc_dict.get(sig)
- # This is kind of stupid
- if from_socket.node.bl_idname in "NodeGroupInput":
- nc_from = held_links.get( tuple([None] + tree_path_names + [link.from_socket.name, inp.identifier]) )
- if not (nc_from):
- prRed( [None] + tree_path_names + [link.from_socket.name, inp.identifier])
- for signature, link in held_links.items():
- print ( wrapGreen(signature), wrapWhite(link))
- nc_from = nc_from.nc_from
-
- if (nc_from):
- dummy = DummyLink(from_socket = from_socket, to_socket = inp, nc_from=nc_from, nc_to=None, original_from=from_socket )
- # The link sig should take us back to the group node.
- link_sig = tuple( [None] + tree_path_names + [ng.name, inp.name, inp.identifier])
- held_links[link_sig]=dummy
- prGreen("Adding %s" % from_socket)
- else:
- prRed("no nc?")
- prOrange(sig)
- # Recurse!
- # data_from_tree(base_tree, tree_path+[ng], grps, solved_trees, solved_tree_links, held_nodes, held_links, all_nc)
-
-
- data_from_tree(base_tree, tree_path+[ng], held_links, all_nc)
-
- for link_sig, held in held_links.items():
- from_cls = held.from_socket.node.bl_idname
- to_cls = held.to_socket.node.bl_idname
- if (from_cls in ["MantisNodeGroup"] and not
- to_cls in ["MantisNodeGroup"]):
- nc_from = held.nc_from
- for link in outgoing:
- if link.from_socket.node.name == nc_from.signature[-2]:
- to_sig = tuple([None] + tree_path_names + [held.to_socket.node.name])
- nc_to = nc_dict.get( to_sig )
- if (nc_from and nc_to):
- from_s, to_s = link_sig[-1], held.to_socket.name
- connection = nc_from.outputs[from_s].connect(node=nc_to, socket=to_s)
-
- held_nodes = {}; held_links = {} # NO IDEA why I have to do this
-
-
-
- # return None, grps, all_links, solved_trees, solved_tree_links, all_nc
- return all_nc
-
-
- from itertools import chain
- def parse_tree(base_tree):
- all_nc = data_from_tree(base_tree, tree_path = [None], held_links = {}, all_nc = {})
- all_nc = list(all_nc.values()).copy()
- kept_nc = {}
- while (all_nc):
- nc = all_nc.pop()
- # total_links=0
- # for sock in chain( nc.inputs.values(), nc.outputs.values()):
- # total_links+=len(sock.links)
- # if total_links > 0:
- nc.fill_parameters()
- # ugly, but it solves the problem easily:
- establish_node_connections(nc)
- kept_nc[nc.signature]=nc
- return kept_nc
- from_name_filter = ["Driver", ]
- to_name_filter = [
- "Custom Object xForm Override",
- "Custom Object",
- "Deform Bones"
- ]
- def establish_node_connections(nc):
- # This is ugly bc it adds parameters to an object
- # but it's kinda necesary to do it after the fact; and it
- # wouldn't be ugly if I just initialized the parameter elsewhere
- connections, hierarchy_connections = [], []
- for socket in nc.outputs.values():
- for link in socket.links:
- connections.append(link.to_node)
- # this may catch custom properties... too bad.
- if link.from_socket in from_name_filter:
- continue
- if link.to_socket in to_name_filter:
- continue
- hierarchy_connections.append(link.to_node)
- nc.connected_to = connections
- nc.hierarchy_connections = hierarchy_connections
- def sort_tree_into_layers(nodes, context):
- from time import time
- from mantis.node_container_common import (get_depth_lines,
- node_depth)
- from mantis.utilities import prGreen, prOrange, prRed, prPurple
- # All this function needs to do is sort out the hierarchy and
- # get things working in order of their dependencies.
-
- prPurple ("Number of nodes: ", len(nodes))
- roots, drivers = [], []
- start = time()
-
- for n in nodes.values():
- if n.node_type == 'DRIVER': drivers.append(n)
- # ugly but necesary to ensure that drivers are always connected.
- if not (hasattr(n, 'inputs')) or ( len(n.inputs) == 0):
- roots.append(n)
- elif (hasattr(n, 'inputs')):
- none_connected = True
- for inp in n.inputs.values():
- if inp.is_linked: none_connected = False
- if none_connected: roots.append(n)
-
- layers, nodes_heights = {}, {}
-
-
-
- for root in roots:
- nodes_heights[root.signature] = 0
-
- #Possible improvement: unify roots if they represent the same data
- all_sorted_nodes = []
- for root in roots:
-
- # if len(root.hierarchy_connections) == 0:
- # if (len(root.connected_to) == 0):
- # prRed("No connections: ", root)
- # continue
-
- depth_lines = get_depth_lines(root)[0]
-
- for n in nodes.values():
- if n.signature not in (depth_lines.keys()):
- continue #belongs to a different root
- d = nodes_heights.get(n.signature, 0)
- if (new_d := node_depth(depth_lines[n.signature])) > d:
- d = new_d
- nodes_heights[n.signature] = d
-
- for k, v in nodes_heights.items():
- if (layer := layers.get(v, None)):
- layer.append(nodes[k]) # add it to the existing layer
- else: layers[v] = [nodes[k]] # or make a new layer with the node
- all_sorted_nodes.append(nodes[k]) # add it to the sorted list
-
- for n in nodes.values():
- if n not in all_sorted_nodes:
- for drv in drivers:
- if n in drv.connected_to:
- depth = nodes_heights[drv.signature] + 1
- nodes_heights[n.signature] = depth
- # don't try to push downstream deps up bc this
- # is a driver and it will be done in the
- # finalize pass anyway
- if (layer := layers.get(depth, None)):
- layer.append(n)
- else: layers[v] = [n]
- else:
- prRed(n)
- for inp in n.inputs.values():
- print (len(inp.links))
- raise RuntimeError(wrapRed("Failed to depth-sort nodes (because of a driver-combine node?)"))
- #
- prGreen("Sorting depth for %d nodes finished in %s seconds" %
- (len(nodes), time() - start))
-
- if (False): # True to print the layers
- for i in range(len(layers)):
- try:
- print(i, layers[i])
- except KeyError: # empty layer?
- print (i)
- return layers
- def execute_tree(nodes, base_tree, context):
- import bpy
- from time import time
- from mantis.node_container_common import GraphError
- start_time = time()
-
- # input_from_grp_nodes(parsed_tree, base_tree, nodes)
- # bpy.ops.wm.quit_blender()
-
- layers = sort_tree_into_layers(nodes, context)
- start_execution_time = time()
-
- # Execute the first pass (xForm, Utility) #
- for i in range(len(layers)):
- for node in layers[i]:
- if (node.node_type in ['XFORM', 'UTILITY']):
- try:
- node.bExecute(context)
- except Exception as e:
- prRed("Execution failed at %s" % node); raise e
- # Switch to Pose Mode #
- active = None
- switch_me = []
- for n in nodes.values():
- # if it is a armature, switch modes
- # total hack #kinda dumb
- if ((hasattr(n, "bGetObject")) and (n.__class__.__name__ == "xFormArmature" )):
- try:
- ob = n.bGetObject()
- except KeyError: # for bones
- ob = None
- # TODO this will be a problem if and when I add mesh/curve stuff
- if (hasattr(ob, 'mode') and ob.mode == 'EDIT'):
- switch_me.append(ob)
- active = ob # need to have an active ob, not None, to switch modes.
- # we override selected_objects to prevent anyone else from mode-switching
- # TODO it's possible but unlikely that the user will try to run a
- # graph with no armature nodes in it.
- if (active):
- bpy.ops.object.mode_set({'active_object':active, 'selected_objects':switch_me}, mode='POSE')
-
- # Execute second pass (Link, Driver) #
- for i in range(len(layers)):
- for n in layers[i]:
- # Now do the Link & Driver nodes during the second pass.
- if (n.node_type in ['LINK', 'DRIVER']):
- try:
- n.bExecute(context)
- except GraphError:
- pass
- except Exception as e:
- print (n); raise e
-
- # Finalize #
- for i in range(len(layers)):
- for node in layers[i]:
- if (hasattr(node, "bFinalize")):
- node.bFinalize(context)
-
- prGreen("Executed Tree in %s seconds" % (time() - start_execution_time))
- prGreen("Finished executing tree in %f seconds" % (time() - start_time))
-
|