| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- #fool: should be wrColor like prColor... dumb
- def wrapRed(skk): return "\033[91m{}\033[00m".format(skk)
- def wrapGreen(skk): return "\033[92m{}\033[00m".format(skk)
- def wrapPurple(skk): return "\033[95m{}\033[00m".format(skk)
- def wrapWhite(skk): return "\033[97m{}\033[00m".format(skk)
- def wrapOrange(skk): return "\033[0;33m{}\033[00m".format(skk)
- # these should reimplement the print interface..
- def prRed(*args): print (*[wrapRed(arg) for arg in args])
- def prGreen(*args): print (*[wrapGreen(arg) for arg in args])
- def prPurple(*args): print (*[wrapPurple(arg) for arg in args])
- def prWhite(*args): print (*[wrapWhite(arg) for arg in args])
- def prOrange(*args): print (*[wrapOrange(arg) for arg in args])
- # add THIS to the top of a file for easy access:
- # from mantis.utilities import (prRed, prGreen, prPurple, prWhite,
- # prOrange,
- # wrapRed, wrapGreen, wrapPurple, wrapWhite,
- # wrapOrange,)
- # uncomment to turn them off.
- # def prRed(*args): return; print (*[wrapRed(arg) for arg in args])
- # def prGreen(*args): return; print (*[wrapGreen(arg) for arg in args])
- # def prPurple(*args): return; print (*[wrapPurple(arg) for arg in args])
- # def prWhite(*args): return; print (*[wrapWhite(arg) for arg in args])
- # def prOrange(*args): return; print (*[wrapOrange(arg) for arg in args])
- #DO! Figure out what the hell this does
- # then re-write it in a simpler, cleaner way
- # that ignores groups because it gets lines from a parsed tree
- # ideally I can use the seeking-lines instead of the socket/tree lines
- # since those allow the function to travel through the tree.
- # not sure if the above comment still has any place here....
- def print_lines(lines):
- printstring, string = "", ""
- cur_g = 0
- for line in lines:
- string += wrapRed("%i: " % len(line))
- for s, g in line:
- new_g = len(g) -1
- difference = new_g - cur_g
- if difference > 0:
- string = string[:-1] # get rid of leading space
- for i in range(difference):
- string += " [ "
- elif difference < 0:
- string = string[:-4]# get rid of arrow
- for i in range(abs(difference)):
- string += " ] "
- string += "-> "
- cur_g = new_g
- wrap=wrapWhite
- if (s.node.bl_idname in ['UtilitySwitch', 'UtilityDriver', 'UtilityDriverVariable']):
- wrap = wrapPurple
- elif (s.node.bl_idname in ['xFormArmatureNode', 'xFormBoneNode']):
- wrap = wrapOrange
- elif (s.node.bl_idname in ['LinkStretchTo']):
- wrap = wrapRed
- elif ('Link' in s.node.bl_idname):
- wrap = wrapGreen
- string += wrap(s.node.name + ":" + s.name) + " -> "
- string = string[:-4]
- while cur_g > 0:
- cur_g -= 1
- string += " ] "
- cur_g, difference = 0,0
- printstring +=string + "\n\n"; string = ""
- return printstring
- # why is this not printing groups in brackets?
- def print_socket_signature(sig):
- string = ""
- for i, e in enumerate(sig):
- if (e == "NONE"):
- continue
- wrap = wrapWhite
- if (i == len(sig)-2):
- wrap = wrapRed
- elif (i == len(sig) - 1):
- wrap = wrapGreen
- string+= wrap(e) + ":"
- return string[:-1]
-
- def print_node_signature(sig,):
- string = ""
- for i, e in enumerate(sig):
- if (e == "NONE"):
- continue
- wrap = wrapWhite
- if (i == len(sig)-2):
- wrap = wrapRed
- elif (i == len(sig) - 1):
- continue
- string+= wrap(e) + ":"
- return string[:-1]
- def print_parsed_node(parsed_node):
- # do: make this consistent with the above
- string = ""
- for k, v in parsed_node.items():
- if isinstance(v, dict):
- string += "%s:\n" % (k)
- for k1, v1 in v.items():
- string += " %s: %s\n" % (k1, v1)
- else:
- string += "%s: %s\n" % (k, v )
- return string
- def get_socket_signature(line_element):
- """
- This function creates a convenient, hashable signature for
- identifying a node path.
- """
- if not line_element:
- return None
- signature, socket, tree_path = [], line_element[0], line_element[1]
- for n in tree_path:
- if hasattr(n, "name"):
- signature.append(n.name)
- else:
- signature.append("NONE")
- signature.append(socket.node.name); signature.append(socket.identifier)
- return tuple(signature)
-
-
- def tuple_of_line(line):
- # For creating a set of lines
- return tuple(tuple_of_line_element(e) for e in line)
- def tuple_of_line_element(line_element):
- return (line_element[0], tuple(line_element[1]))
- # This has a lot of branches and is kinda slow.
- def socket_seek(socket, trees):
- from bpy.types import NodeReroute, NodeGroupOutput
- if (hasattr( socket.node, "traverse")):
- if (socket.node.bl_idname == "MantisNodeGroup"):
- trees.append(socket.node)
- socket = socket.node.traverse(socket, "IN")
- else:
- socket = socket.node.traverse(socket)
- elif (isinstance(socket.node, NodeReroute)):
- socket = socket.node.outputs[0]
- elif (isinstance(socket.node, NodeGroupOutput)):
- group_node = trees.pop()
- if group_node:
- socket = group_node.traverse(socket, "OUT")
- else:
- raise RuntimeError("Error parsing Group Nodes")
- else:
- raise RuntimeError("Error: node tree cannot be navigated")
- return socket, trees
- #This is a little slow.
- def lines_from_socket(sock, tree_path = [None]):
- done = False
- sPath =[0,]
- lines = []
- while (not done):
- seek = sock
- trees = tree_path.copy() # make sure to copy, lists are not immutable
- for curheight, ind in enumerate(sPath):
- if not seek: #this will cause the loop to complete normally
- continue # which will return an error
- if (ind <= (len(seek.links) -1)):
- seek = seek.links[ind].to_socket
- nextseek, trees = socket_seek(seek, trees.copy())
- if (not nextseek): # The node has no no traverse function.
- # note, kind of duplicated code, TODO,
- lines.append(sPath[:curheight+1])
- if (curheight > 0):
- sPath[curheight] += 1
- else:
- done = True
- break
- if (nextseek.is_linked): #otherwise this is a leaf
- seek = nextseek
- if (curheight == len(sPath)-1): #go up
- sPath.append(0)
- elif not (nextseek.is_linked):
- lines.append(sPath[:curheight+1])
- sPath[curheight]+=1
- # this makes sure we're progressing through the tree.
- break
- else:
- if (curheight > 0):
- sPath.pop() #go back...
- sPath[curheight-1] += 1
-
- else:
- done = True
- break
- else:
- raise RuntimeError("There has been an error parsing the tree")
- return lines
- # only using this once, should this even be a function?
- def create_socket_lists(sock, tree_path, lines):
- out_lines = []
- for line in lines:
- s = sock
- trees = tree_path.copy()
- out_line = [(s, trees)]
- for i, ind in enumerate(line):
- if i < len(line):
- s_next = s.links[ind].to_socket
- s_final, trees = socket_seek(s_next, trees.copy())
- if s_final:
- s = s_final
- else: # The node has no no traverse function.
- # this needs special check, if it's the first node,
- # it's already in the tree.
- if (i > 0):
- out_line.append( (s, trees) )
- out_line.append( (s_next, trees) )
- break
- # nodes to skip...
- if (s.node.bl_idname in [
- "NodeReroute",
- "MantisNodeGroupOutput",
- "NodeGroupOutput",
- "MantisNodeGroupInput",
- "NodeGroupInput"
- ]):
- continue
-
- out_line.append( (s, trees) )
- out_lines.append(out_line)
- return out_lines
- #NOTE: this may not work at all lol
- # TODO BUG HACK rename and remove this before publishing
- def find_root_nodes(tree, tree_path = [None]):
- root_nodes = []
- for node in tree.nodes:
- addMe = True
- for s in node.inputs:
- if (s.is_linked == True):
- addMe = False
- # for now, don't try to sovle this, it will need
- # a backwards search
- for link in s.links:
- # we need to check if this is a "false" connection;
- # that is, a Group In from an unconnected Group
- if (link.from_socket.node.bl_idname in ["NodeGroupInput", "MantisNodeGroupInput"]):
- identifier = link.from_socket.identifier
- for grp in tree_path[1:][::-1]:
- for inp in grp.inputs:
- if inp.identifier == identifier and not inp.is_linked:
- addMe=True
- break
- else:
- addMe=False
- if (hasattr(node, "node_tree")):
- # we use the node itself here for the node path, will use it for node signature later.
- root_nodes.extend( find_root_nodes(node.node_tree, tree_path+[node]) )
-
- if (node.bl_idname in [
- "NodeReroute",
- "MantisNodeGroupOutput",
- "NodeGroupOutput",
- "MantisNodeGroupInput",
- "NodeGroupInput",
- "NodeFrame",
- ]):
- addMe = False
- continue
-
- if (addMe):
- root_nodes.append( (tree_path, node) )
- return root_nodes
- def parse_node_tree(tree):
- root_nodes = find_root_nodes(tree)
- # this seems to produce garbage results. Check this!
- input_lines = []
-
- for path, node in root_nodes:
- # print (path, node)
- for s in node.outputs:
- socket_lists = create_socket_lists(s, path, lines_from_socket(s, path))
- for line in socket_lists:
- in_line = line.copy()
- input_lines.append(in_line)
- # NOT SURE if any of this stuff below is necesary at all
- return (input_lines) # let's find out if it is
- #
-
- # I think the unreachable code here is bad. TODO: figure out if there's
- # any reason at all to revive this old code.
- #
- # I certainly *like* the idea of removing redundant data.
- #
- # note: it seems like the Execute Tree function is completing
- # in 80% of the previous time after removing the below
- # meanign that this was wasting 1/5 of the total time
- no_dupes_sigs = set()
- no_dupes_lines = set()
- for in_line in input_lines:
- sig = get_socket_signature(in_line[-1])
- sig = list(sig)
- sig.append(in_line[-1][0].name) # socket
- sig = tuple(sig)
- before = len(no_dupes_sigs)
- no_dupes_sigs.add(sig)
- after = len(no_dupes_sigs)
- # make a tuple of the node path, too.
- # in_line = tuple(in_line[0]), in_line[1]
-
- if (before < after): # new item
- no_dupes_lines.add(tuple_of_line(in_line))
- #MAYBE
- # maybe i can get a list of all nodes
- # including nodes in nodegroups and nested node groups
- # then I can assign a uuid to each one
- # and associate the uuids with the node lines
- # perhaps I should do that before running this function
-
- # for line in no_dupes_lines:
- # print (list(line))
-
- return (list(no_dupes_lines))
- # don't deal with lines no mo. Do stuff with line elements
- # DO THIS!
- # make lines_from_socket attach a tree path to each node-socket, instead of just a tree
- # that way, if the tree-path is longer than the socket-path, the tree path won't be truncated.
- # for use with node signatures
- def tree_from_nc(sig, base_tree):
- if (sig[0] == 'MANTIS_AUTOGENERATED'):
- sig = sig[:-2] # cut off the input part of the signature.
- tree = base_tree
- for i, path_item in enumerate(sig):
- if (i == 0) or (i == len(sig) - 1):
- continue
- tree = tree.nodes.get(path_item).node_tree
- return tree
-
- def get_node_prototype(sig, base_tree):
- return tree_from_nc(sig, base_tree).nodes.get( sig[-1] )
-
-
- ##################################################################################################
- # misc
- ##################################################################################################
- # This will not work with float properties. Use them directly.
- # this is an extremely idiotic way to do this
- # it's also slow!
- # TODO fix this
- #using isinstance is the most lizard-brained way to do this, utter idiocy.
- def to_mathutils_value(socket):
- if (hasattr(socket, "default_value")):
- val = socket.default_value
- from mathutils import Matrix, Euler, Quaternion, Vector
- from bpy.types import (NodeSocketVector, NodeSocketVectorAcceleration,
- NodeSocketVectorDirection, NodeSocketVectorEuler,
- NodeSocketVectorTranslation, NodeSocketVectorVelocity,
- NodeSocketVectorXYZ,)
- from . import socket_definitions
- if ((isinstance(socket, NodeSocketVector)) or
- (isinstance(socket, NodeSocketVectorAcceleration)) or
- (isinstance(socket, NodeSocketVectorDirection)) or
- (isinstance(socket, NodeSocketVectorTranslation)) or
- (isinstance(socket, NodeSocketVectorXYZ)) or
- (isinstance(socket, NodeSocketVectorVelocity)) or
- (isinstance(socket, socket_definitions.VectorSocket)) or
- (isinstance(socket, socket_definitions.VectorEulerSocket)) or
- (isinstance(socket, socket_definitions.VectorTranslationSocket)) or
- (isinstance(socket, socket_definitions.VectorScaleSocket)) or
- (isinstance(socket, socket_definitions.ParameterVectorSocket))):
- return (Vector(( val[0], val[1], val[2], )))
- if (isinstance(socket, NodeSocketVectorEuler)):
- return (Euler(( val[0], val[1], val[2])), 'XYZ',) #TODO make choice
- if (isinstance(socket, socket_definitions.MatrixSocket)):
- # return val #Blender makes it a Matrix for me <3
- # nevermind... BLENDER HAS BETRAYED ME
- return socket.TellValue()
- if (isinstance(socket,socket_definitions.QuaternionSocket)):
- return (Quaternion( (val[0], val[1], val[2], val[3],)) )
- if (isinstance(socket,socket_definitions.QuaternionSocketAA)):
- return (Quaternion( (val[1], val[2], val[3],), val[0], ) )
- if ((isinstance(socket, socket_definitions.FloatSocket)) or
- (isinstance(socket, socket_definitions.ParameterIntSocket)) or
- (isinstance(socket, socket_definitions.ParameterFloatSocket))):
- return val
- if (isinstance(socket, socket_definitions.BooleanThreeTupleSocket)):
- return (val[0], val[1], val[2]) # we'll send a tuple out
- # if ((isinstance(socket, socket_definitions.LayerMaskSocket)) or
- # (isinstance(socket, socket_definitions.LayerMaskInputSocket))):
- # return tuple(val) # should werk
- else:
- return None
|