|
@@ -13,6 +13,7 @@ from .utilities import (prRed, prGreen, prPurple, prWhite,
|
|
|
from .utilities import get_socket_maps, relink_socket_map, do_relink
|
|
from .utilities import get_socket_maps, relink_socket_map, do_relink
|
|
|
|
|
|
|
|
FLOAT_EPSILON=0.0001 # used to check against floating point inaccuracy
|
|
FLOAT_EPSILON=0.0001 # used to check against floating point inaccuracy
|
|
|
|
|
+links_sort_key= lambda a : (-a.multi_input_sort_id, -a.sub_sort_id)
|
|
|
|
|
|
|
|
def TellClasses():
|
|
def TellClasses():
|
|
|
#Why use a function to do this? Because I don't need every class to register.
|
|
#Why use a function to do this? Because I don't need every class to register.
|
|
@@ -79,12 +80,16 @@ def hash_tree(tree):
|
|
|
links.sort(); hash_data+=''.join(links)
|
|
links.sort(); hash_data+=''.join(links)
|
|
|
return hash(hash_data)
|
|
return hash(hash_data)
|
|
|
|
|
|
|
|
|
|
+MANTIS_VERSION_MAJOR=0
|
|
|
|
|
+MANTIS_VERSION_MINOR=12
|
|
|
|
|
+MANTIS_VERSION_SUB=27
|
|
|
|
|
+
|
|
|
class MantisTree(NodeTree):
|
|
class MantisTree(NodeTree):
|
|
|
'''A custom node tree type that will show up in the editor type list'''
|
|
'''A custom node tree type that will show up in the editor type list'''
|
|
|
bl_idname = 'MantisTree'
|
|
bl_idname = 'MantisTree'
|
|
|
bl_label = "Rigging Nodes"
|
|
bl_label = "Rigging Nodes"
|
|
|
bl_icon = 'OUTLINER_OB_ARMATURE'
|
|
bl_icon = 'OUTLINER_OB_ARMATURE'
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
tree_valid:BoolProperty(default=False)
|
|
tree_valid:BoolProperty(default=False)
|
|
|
hash:StringProperty(default='')
|
|
hash:StringProperty(default='')
|
|
|
do_live_update:BoolProperty(default=True) # use this to disable updates for e.g. scripts
|
|
do_live_update:BoolProperty(default=True) # use this to disable updates for e.g. scripts
|
|
@@ -97,21 +102,22 @@ class MantisTree(NodeTree):
|
|
|
is_exporting:BoolProperty(default=False)
|
|
is_exporting:BoolProperty(default=False)
|
|
|
execution_id:StringProperty(default='')
|
|
execution_id:StringProperty(default='')
|
|
|
# prev_execution_id:StringProperty(default='')
|
|
# prev_execution_id:StringProperty(default='')
|
|
|
- mantis_version:IntVectorProperty(default=[0,9,2])
|
|
|
|
|
|
|
+ mantis_version:IntVectorProperty(default=[
|
|
|
|
|
+ MANTIS_VERSION_MAJOR, MANTIS_VERSION_MINOR, MANTIS_VERSION_SUB])
|
|
|
# this prevents the node group from executing on the next depsgraph update
|
|
# this prevents the node group from executing on the next depsgraph update
|
|
|
# because I don't always have control over when the dg upadte happens.
|
|
# because I don't always have control over when the dg upadte happens.
|
|
|
prevent_next_exec:BoolProperty(default=False)
|
|
prevent_next_exec:BoolProperty(default=False)
|
|
|
|
|
|
|
|
#added to work around a bug in 4.5.0 LTS
|
|
#added to work around a bug in 4.5.0 LTS
|
|
|
interface_helper : StringProperty(default='')
|
|
interface_helper : StringProperty(default='')
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
parsed_tree={}
|
|
parsed_tree={}
|
|
|
|
|
|
|
|
if (bpy.app.version < (4, 4, 0) or bpy.app.version >= (4,5,0)): # in 4.4 this leads to a crash
|
|
if (bpy.app.version < (4, 4, 0) or bpy.app.version >= (4,5,0)): # in 4.4 this leads to a crash
|
|
|
@classmethod
|
|
@classmethod
|
|
|
def valid_socket_type(cls : NodeTree, socket_idname: str):
|
|
def valid_socket_type(cls : NodeTree, socket_idname: str):
|
|
|
return valid_interface_types(cls, socket_idname)
|
|
return valid_interface_types(cls, socket_idname)
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def update(self): # set the reroute colors
|
|
def update(self): # set the reroute colors
|
|
|
if (bpy.app.version >= (4,4,0)):
|
|
if (bpy.app.version >= (4,4,0)):
|
|
|
fix_reroute_colors(self)
|
|
fix_reroute_colors(self)
|
|
@@ -155,7 +161,7 @@ class MantisTree(NodeTree):
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
print("Node \"%s\" failed to update display with error: %s" %(wrapGreen(node.name), wrapRed(e)))
|
|
print("Node \"%s\" failed to update display with error: %s" %(wrapGreen(node.name), wrapRed(e)))
|
|
|
self.is_executing = False
|
|
self.is_executing = False
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
# TODO: deal with invalid links properly.
|
|
# TODO: deal with invalid links properly.
|
|
|
# - Non-hierarchy links should be ignored in the circle-check and so the links should be marked valid in such a circle
|
|
# - Non-hierarchy links should be ignored in the circle-check and so the links should be marked valid in such a circle
|
|
|
# - hierarchy-links should be marked invalid and prevent the tree from executing.
|
|
# - hierarchy-links should be marked invalid and prevent the tree from executing.
|
|
@@ -189,7 +195,8 @@ class SchemaTree(NodeTree):
|
|
|
is_executing:BoolProperty(default=False)
|
|
is_executing:BoolProperty(default=False)
|
|
|
is_exporting:BoolProperty(default=False)
|
|
is_exporting:BoolProperty(default=False)
|
|
|
|
|
|
|
|
- mantis_version:IntVectorProperty(default=[0,9,2])
|
|
|
|
|
|
|
+ mantis_version:IntVectorProperty(default=[
|
|
|
|
|
+ MANTIS_VERSION_MAJOR, MANTIS_VERSION_MINOR, MANTIS_VERSION_SUB])
|
|
|
# see the note in MantisTree
|
|
# see the note in MantisTree
|
|
|
interface_helper : StringProperty(default='')
|
|
interface_helper : StringProperty(default='')
|
|
|
|
|
|
|
@@ -219,7 +226,7 @@ class MantisSocketTemplate():
|
|
|
hide : bool = field(default=False)
|
|
hide : bool = field(default=False)
|
|
|
use_multi_input : bool = field(default=False)
|
|
use_multi_input : bool = field(default=False)
|
|
|
default_value : Any = field(default=None)
|
|
default_value : Any = field(default=None)
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
|
|
#TODO: do a better job explaining how MantisNode and MantisUINode relate.
|
|
#TODO: do a better job explaining how MantisNode and MantisUINode relate.
|
|
@@ -236,7 +243,7 @@ class MantisUINode:
|
|
|
@classmethod
|
|
@classmethod
|
|
|
def poll(cls, ntree):
|
|
def poll(cls, ntree):
|
|
|
return (ntree.bl_idname in ['MantisTree', 'SchemaTree'])
|
|
return (ntree.bl_idname in ['MantisTree', 'SchemaTree'])
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
@classmethod
|
|
@classmethod
|
|
|
def set_mantis_class(self):
|
|
def set_mantis_class(self):
|
|
|
from importlib import import_module
|
|
from importlib import import_module
|
|
@@ -260,7 +267,7 @@ class MantisUINode:
|
|
|
node_tree.num_links+=1
|
|
node_tree.num_links+=1
|
|
|
elif (link.to_socket.is_multi_input):
|
|
elif (link.to_socket.is_multi_input):
|
|
|
node_tree.num_links+=1
|
|
node_tree.num_links+=1
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def init_sockets(self, socket_templates : tuple[MantisSocketTemplate]):
|
|
def init_sockets(self, socket_templates : tuple[MantisSocketTemplate]):
|
|
|
for template in socket_templates:
|
|
for template in socket_templates:
|
|
|
collection = self.outputs
|
|
collection = self.outputs
|
|
@@ -286,7 +293,7 @@ class MantisUINode:
|
|
|
# responsibility to send the right type.
|
|
# responsibility to send the right type.
|
|
|
if template.use_multi_input: # this is an array
|
|
if template.use_multi_input: # this is an array
|
|
|
socket.display_shape = 'SQUARE_DOT'
|
|
socket.display_shape = 'SQUARE_DOT'
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
class SchemaUINode(MantisUINode):
|
|
class SchemaUINode(MantisUINode):
|
|
|
mantis_node_library='.schema_nodes'
|
|
mantis_node_library='.schema_nodes'
|
|
|
is_updating:BoolProperty(default=False)
|
|
is_updating:BoolProperty(default=False)
|
|
@@ -299,7 +306,7 @@ class LinkNode(MantisUINode):
|
|
|
@classmethod
|
|
@classmethod
|
|
|
def poll(cls, ntree):
|
|
def poll(cls, ntree):
|
|
|
return (ntree.bl_idname in ['MantisTree', 'SchemaTree'])
|
|
return (ntree.bl_idname in ['MantisTree', 'SchemaTree'])
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
class xFormNode(MantisUINode):
|
|
class xFormNode(MantisUINode):
|
|
|
mantis_node_library='.xForm_nodes'
|
|
mantis_node_library='.xForm_nodes'
|
|
|
@classmethod
|
|
@classmethod
|
|
@@ -388,11 +395,11 @@ def node_group_update(node, force = False):
|
|
|
if update_input: continue # done here
|
|
if update_input: continue # done here
|
|
|
if s.bl_idname != item.bl_socket_idname: update_input = True; continue
|
|
if s.bl_idname != item.bl_socket_idname: update_input = True; continue
|
|
|
else: update_input = True; continue
|
|
else: update_input = True; continue
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
# Schema has an extra input for Length and for Extend.
|
|
# Schema has an extra input for Length and for Extend.
|
|
|
if node.bl_idname == 'MantisSchemaGroup':
|
|
if node.bl_idname == 'MantisSchemaGroup':
|
|
|
found_in.extend(['Schema Length', ''])
|
|
found_in.extend(['Schema Length', ''])
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
# get the socket maps before modifying stuff
|
|
# get the socket maps before modifying stuff
|
|
|
if update_input or update_output:
|
|
if update_input or update_output:
|
|
|
socket_maps = get_socket_maps(node,)
|
|
socket_maps = get_socket_maps(node,)
|
|
@@ -405,7 +412,7 @@ def node_group_update(node, force = False):
|
|
|
# We have to initialize the node because it only has its base inputs.
|
|
# We have to initialize the node because it only has its base inputs.
|
|
|
elif socket_maps is None:
|
|
elif socket_maps is None:
|
|
|
node.id_data.do_live_update = toggle_update
|
|
node.id_data.do_live_update = toggle_update
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
# if we have too many elements, just get rid of the ones we don't need
|
|
# if we have too many elements, just get rid of the ones we don't need
|
|
|
if len(node.inputs) > len(found_in):#
|
|
if len(node.inputs) > len(found_in):#
|
|
|
for inp in node.inputs:
|
|
for inp in node.inputs:
|
|
@@ -441,7 +448,7 @@ def node_group_update(node, force = False):
|
|
|
remove_me.append(socket)
|
|
remove_me.append(socket)
|
|
|
while remove_me:
|
|
while remove_me:
|
|
|
node.inputs.remove(remove_me.pop())
|
|
node.inputs.remove(remove_me.pop())
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if update_output:
|
|
if update_output:
|
|
|
remove_me=[]
|
|
remove_me=[]
|
|
|
for socket in node.outputs:
|
|
for socket in node.outputs:
|
|
@@ -465,18 +472,18 @@ def node_group_update(node, force = False):
|
|
|
reorder_collection = reorder_me_input if is_input else reorder_me_output
|
|
reorder_collection = reorder_me_input if is_input else reorder_me_output
|
|
|
if socket_map:
|
|
if socket_map:
|
|
|
if item.identifier in socket_map.keys():
|
|
if item.identifier in socket_map.keys():
|
|
|
- socket = relink_socket_map_add_socket(node, socket_collection, item)
|
|
|
|
|
|
|
+ socket = relink_socket_map_add_socket(node, socket_collection, item, item.in_out)
|
|
|
do_relink(node, socket, socket_map, item.in_out)
|
|
do_relink(node, socket, socket_map, item.in_out)
|
|
|
else:
|
|
else:
|
|
|
for has_socket in socket_collection:
|
|
for has_socket in socket_collection:
|
|
|
if has_socket.bl_idname == item.bl_socket_idname and \
|
|
if has_socket.bl_idname == item.bl_socket_idname and \
|
|
|
- has_socket.name == item.name:
|
|
|
|
|
|
|
+ has_socket.name == item.name:
|
|
|
reorder_collection.append((has_socket, counter))
|
|
reorder_collection.append((has_socket, counter))
|
|
|
break
|
|
break
|
|
|
else:
|
|
else:
|
|
|
- socket = relink_socket_map_add_socket(node, socket_collection, item)
|
|
|
|
|
|
|
+ socket = relink_socket_map_add_socket(node, socket_collection, item, item.in_out)
|
|
|
else:
|
|
else:
|
|
|
- socket = relink_socket_map_add_socket(node, socket_collection, item)
|
|
|
|
|
|
|
+ socket = relink_socket_map_add_socket(node, socket_collection, item, item.in_out)
|
|
|
counter += 1
|
|
counter += 1
|
|
|
|
|
|
|
|
# TODO: de-duplicate this hideous stuff
|
|
# TODO: de-duplicate this hideous stuff
|
|
@@ -502,7 +509,7 @@ def node_group_update(node, force = False):
|
|
|
if exists.identifier == item.identifier:
|
|
if exists.identifier == item.identifier:
|
|
|
break
|
|
break
|
|
|
else:
|
|
else:
|
|
|
- update_group_sockets(item, True)
|
|
|
|
|
|
|
+ update_group_sockets(item, False)
|
|
|
else:
|
|
else:
|
|
|
update_group_sockets(item, False)
|
|
update_group_sockets(item, False)
|
|
|
output_index += 1
|
|
output_index += 1
|
|
@@ -565,10 +572,10 @@ class MantisNodeGroup(Node, MantisUINode):
|
|
|
return "Node Group"
|
|
return "Node Group"
|
|
|
else:
|
|
else:
|
|
|
return self.node_tree.name
|
|
return self.node_tree.name
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def draw_buttons(self, context, layout):
|
|
def draw_buttons(self, context, layout):
|
|
|
group_draw_buttons(self, context, layout)
|
|
group_draw_buttons(self, context, layout)
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def update(self):
|
|
def update(self):
|
|
|
if self.node_tree is None:
|
|
if self.node_tree is None:
|
|
|
return
|
|
return
|
|
@@ -603,7 +610,7 @@ def poll_node_tree_schema(self, object):
|
|
|
class SchemaGroup(Node, MantisUINode):
|
|
class SchemaGroup(Node, MantisUINode):
|
|
|
bl_idname = "MantisSchemaGroup"
|
|
bl_idname = "MantisSchemaGroup"
|
|
|
bl_label = "Node Schema"
|
|
bl_label = "Node Schema"
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
node_tree:PointerProperty(type=NodeTree, poll=poll_node_tree_schema, update=node_tree_prop_update,)
|
|
node_tree:PointerProperty(type=NodeTree, poll=poll_node_tree_schema, update=node_tree_prop_update,)
|
|
|
is_updating:BoolProperty(default=False)
|
|
is_updating:BoolProperty(default=False)
|
|
|
|
|
|
|
@@ -615,7 +622,7 @@ class SchemaGroup(Node, MantisUINode):
|
|
|
return "Schema Group"
|
|
return "Schema Group"
|
|
|
else:
|
|
else:
|
|
|
return self.node_tree.name
|
|
return self.node_tree.name
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def update(self):
|
|
def update(self):
|
|
|
if self.is_updating: # update() can be called from update() and that leads to an infinite loop.
|
|
if self.is_updating: # update() can be called from update() and that leads to an infinite loop.
|
|
|
return # so we check if an update is currently running.
|
|
return # so we check if an update is currently running.
|
|
@@ -734,12 +741,12 @@ class MantisNode:
|
|
|
@property
|
|
@property
|
|
|
def name(self):
|
|
def name(self):
|
|
|
return self.ui_signature[-1]
|
|
return self.ui_signature[-1]
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
@property
|
|
@property
|
|
|
def bl_idname(self): # this and the above exist solely to maintain interface w/bpy.types.Node
|
|
def bl_idname(self): # this and the above exist solely to maintain interface w/bpy.types.Node
|
|
|
from .utilities import get_node_prototype
|
|
from .utilities import get_node_prototype
|
|
|
return get_node_prototype(self.ui_signature, self.base_tree).bl_idname
|
|
return get_node_prototype(self.ui_signature, self.base_tree).bl_idname
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def reset_execution(self) -> None:
|
|
def reset_execution(self) -> None:
|
|
|
""" Reset the node for additional execution without re-building the tree."""
|
|
""" Reset the node for additional execution without re-building the tree."""
|
|
|
self.drivers={}; self.bObject=None
|
|
self.drivers={}; self.bObject=None
|
|
@@ -757,7 +764,7 @@ class MantisNode:
|
|
|
self.parameters[socket.name] = None
|
|
self.parameters[socket.name] = None
|
|
|
for key, value in additional_parameters.items():
|
|
for key, value in additional_parameters.items():
|
|
|
self.parameters[key]=value
|
|
self.parameters[key]=value
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def gen_property_socket_map(self) -> dict:
|
|
def gen_property_socket_map(self) -> dict:
|
|
|
props_sockets = {}
|
|
props_sockets = {}
|
|
|
for s_template in self.socket_templates:
|
|
for s_template in self.socket_templates:
|
|
@@ -769,7 +776,7 @@ class MantisNode:
|
|
|
for index, sub_prop in enumerate(s_template.blender_property):
|
|
for index, sub_prop in enumerate(s_template.blender_property):
|
|
|
props_sockets[sub_prop]=( (s_template.name, index),s_template.default_value[index] )
|
|
props_sockets[sub_prop]=( (s_template.name, index),s_template.default_value[index] )
|
|
|
return props_sockets
|
|
return props_sockets
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def set_traverse(self, traversal_pairs = [(str, str)]) -> None:
|
|
def set_traverse(self, traversal_pairs = [(str, str)]) -> None:
|
|
|
for (a, b) in traversal_pairs:
|
|
for (a, b) in traversal_pairs:
|
|
|
self.inputs[a].set_traverse_target(self.outputs[b])
|
|
self.inputs[a].set_traverse_target(self.outputs[b])
|
|
@@ -780,12 +787,12 @@ class MantisNode:
|
|
|
inp.flush_links()
|
|
inp.flush_links()
|
|
|
for out in self.outputs.values():
|
|
for out in self.outputs.values():
|
|
|
out.flush_links()
|
|
out.flush_links()
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def update_socket_value(self, blender_property, value) -> bool:
|
|
def update_socket_value(self, blender_property, value) -> bool:
|
|
|
change_handled=False
|
|
change_handled=False
|
|
|
if self.node_type == 'LINK':
|
|
if self.node_type == 'LINK':
|
|
|
if len(self.bObject) == 0: # - there are no downstream xForms
|
|
if len(self.bObject) == 0: # - there are no downstream xForms
|
|
|
- return True # so there is nothing to do here
|
|
|
|
|
|
|
+ return True # so there is nothing to do here
|
|
|
for b_ob in self.bObject:
|
|
for b_ob in self.bObject:
|
|
|
try:
|
|
try:
|
|
|
setattr(b_ob, blender_property, value)
|
|
setattr(b_ob, blender_property, value)
|
|
@@ -835,7 +842,7 @@ class MantisNode:
|
|
|
change_handled=False
|
|
change_handled=False
|
|
|
break # we don't have to look through any more socket templates
|
|
break # we don't have to look through any more socket templates
|
|
|
return change_handled
|
|
return change_handled
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
# the goal here is to tag the node as unprepared
|
|
# the goal here is to tag the node as unprepared
|
|
|
# but some nodes are always prepared, so we have to kick it forward.
|
|
# but some nodes are always prepared, so we have to kick it forward.
|
|
|
def reset_execution_recursive(self):
|
|
def reset_execution_recursive(self):
|
|
@@ -843,7 +850,7 @@ class MantisNode:
|
|
|
if self.prepared==False: return # all good from here
|
|
if self.prepared==False: return # all good from here
|
|
|
for conn in self.hierarchy_connections:
|
|
for conn in self.hierarchy_connections:
|
|
|
conn.reset_execution_recursive()
|
|
conn.reset_execution_recursive()
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def evaluate_input(self, input_name, index=0) -> Any:
|
|
def evaluate_input(self, input_name, index=0) -> Any:
|
|
|
from .node_container_common import trace_single_line
|
|
from .node_container_common import trace_single_line
|
|
|
if not (self.inputs.get(input_name)): # get the named parameter if there is no input
|
|
if not (self.inputs.get(input_name)): # get the named parameter if there is no input
|
|
@@ -853,12 +860,12 @@ class MantisNode:
|
|
|
trace = trace_single_line(self, input_name, index)
|
|
trace = trace_single_line(self, input_name, index)
|
|
|
prop = trace[0][-1].parameters[trace[1].name] #trace[0] = the list of traced nodes; read its parameters
|
|
prop = trace[0][-1].parameters[trace[1].name] #trace[0] = the list of traced nodes; read its parameters
|
|
|
return prop
|
|
return prop
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def fill_parameters(self, ui_node=None) -> None:
|
|
def fill_parameters(self, ui_node=None) -> None:
|
|
|
from .utilities import get_node_prototype
|
|
from .utilities import get_node_prototype
|
|
|
from .node_container_common import get_socket_value
|
|
from .node_container_common import get_socket_value
|
|
|
if not ui_node:
|
|
if not ui_node:
|
|
|
- if ( (self.signature[0] in ["MANTIS_AUTOGENERATED", "SCHEMA_AUTOGENERATED" ]) or
|
|
|
|
|
|
|
+ if ( (self.signature[0] in ["MANTIS_AUTOGENERATED", "SCHEMA_AUTOGENERATED" ]) or
|
|
|
(self.signature[-1] in ["NodeGroupOutput", "NodeGroupInput"]) ): # I think this is harmless
|
|
(self.signature[-1] in ["NodeGroupOutput", "NodeGroupInput"]) ): # I think this is harmless
|
|
|
return None
|
|
return None
|
|
|
else: # BUG shouldn't this use ui_signature??
|
|
else: # BUG shouldn't this use ui_signature??
|
|
@@ -894,7 +901,6 @@ class MantisNode:
|
|
|
nodes are discovered, the method is called by each node in dependency order.
|
|
nodes are discovered, the method is called by each node in dependency order.
|
|
|
The first argument MUST be the name of the method as a string.
|
|
The first argument MUST be the name of the method as a string.
|
|
|
"""
|
|
"""
|
|
|
- prGreen(self)
|
|
|
|
|
if args[0] == 'call_on_all_ancestors': raise RuntimeError("Very funny!")
|
|
if args[0] == 'call_on_all_ancestors': raise RuntimeError("Very funny!")
|
|
|
from .utilities import get_all_dependencies
|
|
from .utilities import get_all_dependencies
|
|
|
from collections import deque
|
|
from collections import deque
|
|
@@ -905,7 +911,6 @@ class MantisNode:
|
|
|
solved = set()
|
|
solved = set()
|
|
|
while can_solve:
|
|
while can_solve:
|
|
|
node = can_solve.pop()
|
|
node = can_solve.pop()
|
|
|
- print(node)
|
|
|
|
|
method = getattr(node, args[0])
|
|
method = getattr(node, args[0])
|
|
|
method(*args[0:], **kwargs)
|
|
method(*args[0:], **kwargs)
|
|
|
solved.add(node)
|
|
solved.add(node)
|
|
@@ -913,7 +918,7 @@ class MantisNode:
|
|
|
if self in solved:
|
|
if self in solved:
|
|
|
break
|
|
break
|
|
|
return
|
|
return
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
# gets targets for constraints and deformers and should handle all cases
|
|
# gets targets for constraints and deformers and should handle all cases
|
|
|
def get_target_and_subtarget(self, constraint_or_deformer, input_name = "Target"):
|
|
def get_target_and_subtarget(self, constraint_or_deformer, input_name = "Target"):
|
|
|
from bpy.types import PoseBone, Object, SplineIKConstraint
|
|
from bpy.types import PoseBone, Object, SplineIKConstraint
|
|
@@ -925,7 +930,7 @@ class MantisNode:
|
|
|
else:
|
|
else:
|
|
|
name = 'NAME NOT FOUND'
|
|
name = 'NAME NOT FOUND'
|
|
|
prRed(f"No {input_name} target found for {name} in {self} because there is no connected node, or node is wrong type")
|
|
prRed(f"No {input_name} target found for {name} in {self} because there is no connected node, or node is wrong type")
|
|
|
- return
|
|
|
|
|
|
|
+ return
|
|
|
if (isinstance(target.bGetObject(), PoseBone)):
|
|
if (isinstance(target.bGetObject(), PoseBone)):
|
|
|
subtarget = target.bGetObject().name
|
|
subtarget = target.bGetObject().name
|
|
|
target = target.bGetParentArmature()
|
|
target = target.bGetParentArmature()
|
|
@@ -933,7 +938,7 @@ class MantisNode:
|
|
|
target = target.bGetObject()
|
|
target = target.bGetObject()
|
|
|
else:
|
|
else:
|
|
|
raise RuntimeError("Cannot interpret constraint or deformer target!")
|
|
raise RuntimeError("Cannot interpret constraint or deformer target!")
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (isinstance(constraint_or_deformer, SplineIKConstraint)):
|
|
if (isinstance(constraint_or_deformer, SplineIKConstraint)):
|
|
|
if target and target.type not in ["CURVE"]:
|
|
if target and target.type not in ["CURVE"]:
|
|
|
raise GraphError(wrapRed("Error: %s requires a Curve input, not %s" %
|
|
raise GraphError(wrapRed("Error: %s requires a Curve input, not %s" %
|
|
@@ -960,12 +965,12 @@ class MantisNode:
|
|
|
return
|
|
return
|
|
|
def bModifierApply(self, bContext=None):
|
|
def bModifierApply(self, bContext=None):
|
|
|
return
|
|
return
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if environ.get("DOERROR"):
|
|
if environ.get("DOERROR"):
|
|
|
- def __repr__(self):
|
|
|
|
|
|
|
+ def __repr__(self):
|
|
|
return self.signature.__repr__()
|
|
return self.signature.__repr__()
|
|
|
else:
|
|
else:
|
|
|
- def __repr__(self):
|
|
|
|
|
|
|
+ def __repr__(self):
|
|
|
return self.ui_signature.__repr__()
|
|
return self.ui_signature.__repr__()
|
|
|
|
|
|
|
|
# do I need this and the link class above?
|
|
# do I need this and the link class above?
|
|
@@ -1001,8 +1006,8 @@ class NodeLink:
|
|
|
from_socket = None
|
|
from_socket = None
|
|
|
to_node = None
|
|
to_node = None
|
|
|
to_socket = None
|
|
to_socket = None
|
|
|
-
|
|
|
|
|
- def __init__(self, from_node, from_socket, to_node, to_socket, multi_input_sort_id=0):
|
|
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, from_node, from_socket, to_node, to_socket, multi_input_sort_id=0, sub_sort_id=0):
|
|
|
if from_node.signature == to_node.signature:
|
|
if from_node.signature == to_node.signature:
|
|
|
raise RuntimeError("Cannot connect a node to itself.")
|
|
raise RuntimeError("Cannot connect a node to itself.")
|
|
|
self.from_node = from_node
|
|
self.from_node = from_node
|
|
@@ -1011,11 +1016,12 @@ class NodeLink:
|
|
|
self.to_socket = to_socket
|
|
self.to_socket = to_socket
|
|
|
self.from_node.outputs[self.from_socket].links.append(self)
|
|
self.from_node.outputs[self.from_socket].links.append(self)
|
|
|
# it is the responsibility of the node that uses these links to sort them correctly based on the sort_id
|
|
# it is the responsibility of the node that uses these links to sort them correctly based on the sort_id
|
|
|
- self.multi_input_sort_id = multi_input_sort_id
|
|
|
|
|
|
|
+ self.multi_input_sort_id = multi_input_sort_id # this is the sort_id of the link in the UI
|
|
|
|
|
+ self.sub_sort_id = sub_sort_id # this is for sorting within a bundled link (one link in the UI)
|
|
|
self.to_node.inputs[self.to_socket].links.append(self)
|
|
self.to_node.inputs[self.to_socket].links.append(self)
|
|
|
self.is_hierarchy = detect_hierarchy_link(from_node, from_socket, to_node, to_socket,)
|
|
self.is_hierarchy = detect_hierarchy_link(from_node, from_socket, to_node, to_socket,)
|
|
|
self.is_alive = True
|
|
self.is_alive = True
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def __repr__(self):
|
|
def __repr__(self):
|
|
|
return self.from_node.outputs[self.from_socket].__repr__() + " --> " + self.to_node.inputs[self.to_socket].__repr__()
|
|
return self.from_node.outputs[self.from_socket].__repr__() + " --> " + self.to_node.inputs[self.to_socket].__repr__()
|
|
|
# link_string = # if I need to colorize output for debugging.
|
|
# link_string = # if I need to colorize output for debugging.
|
|
@@ -1023,12 +1029,12 @@ class NodeLink:
|
|
|
# return wrapOrange(link_string)
|
|
# return wrapOrange(link_string)
|
|
|
# else:
|
|
# else:
|
|
|
# return wrapWhite(link_string)
|
|
# return wrapWhite(link_string)
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def die(self):
|
|
def die(self):
|
|
|
self.is_alive = False
|
|
self.is_alive = False
|
|
|
self.to_node.inputs[self.to_socket].flush_links()
|
|
self.to_node.inputs[self.to_socket].flush_links()
|
|
|
self.from_node.outputs[self.from_socket].flush_links()
|
|
self.from_node.outputs[self.from_socket].flush_links()
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def insert_node(self, middle_node, middle_node_in, middle_node_out, re_init_hierarchy = True):
|
|
def insert_node(self, middle_node, middle_node_in, middle_node_out, re_init_hierarchy = True):
|
|
|
to_node = self.to_node
|
|
to_node = self.to_node
|
|
|
to_socket = self.to_socket
|
|
to_socket = self.to_socket
|
|
@@ -1046,7 +1052,7 @@ class NodeSocket:
|
|
|
# @property # this is a read-only property.
|
|
# @property # this is a read-only property.
|
|
|
# def is_linked(self):
|
|
# def is_linked(self):
|
|
|
# return bool(self.links)
|
|
# return bool(self.links)
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def __init__(self, is_input = False,
|
|
def __init__(self, is_input = False,
|
|
|
node = None, name = None,
|
|
node = None, name = None,
|
|
|
traverse_target = None):
|
|
traverse_target = None):
|
|
@@ -1059,8 +1065,8 @@ class NodeSocket:
|
|
|
self.is_linked = False
|
|
self.is_linked = False
|
|
|
if (traverse_target):
|
|
if (traverse_target):
|
|
|
self.can_traverse = True
|
|
self.can_traverse = True
|
|
|
-
|
|
|
|
|
- def connect(self, node, socket, sort_id=0):
|
|
|
|
|
|
|
+
|
|
|
|
|
+ def connect(self, node, socket, sort_id=0, sub_sort_id=0):
|
|
|
if (self.is_input):
|
|
if (self.is_input):
|
|
|
to_node = self.node; from_node = node
|
|
to_node = self.node; from_node = node
|
|
|
to_socket = self.name; from_socket = socket
|
|
to_socket = self.name; from_socket = socket
|
|
@@ -1077,24 +1083,25 @@ class NodeSocket:
|
|
|
from_socket,
|
|
from_socket,
|
|
|
to_node,
|
|
to_node,
|
|
|
to_socket,
|
|
to_socket,
|
|
|
- sort_id)
|
|
|
|
|
|
|
+ sort_id,
|
|
|
|
|
+ sub_sort_id)
|
|
|
return new_link
|
|
return new_link
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def set_traverse_target(self, traverse_target):
|
|
def set_traverse_target(self, traverse_target):
|
|
|
self.traverse_target = traverse_target
|
|
self.traverse_target = traverse_target
|
|
|
self.can_traverse = True
|
|
self.can_traverse = True
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def flush_links(self):
|
|
def flush_links(self):
|
|
|
""" Removes dead links from this socket."""
|
|
""" Removes dead links from this socket."""
|
|
|
self.links = [l for l in self.links if l.is_alive]
|
|
self.links = [l for l in self.links if l.is_alive]
|
|
|
- self.links.sort(key=lambda a : -a.multi_input_sort_id)
|
|
|
|
|
|
|
+ self.links.sort(key=links_sort_key)
|
|
|
self.is_linked = bool(self.links)
|
|
self.is_linked = bool(self.links)
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
@property
|
|
@property
|
|
|
def is_connected(self):
|
|
def is_connected(self):
|
|
|
return len(self.links)>0
|
|
return len(self.links)>0
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
def __repr__(self):
|
|
def __repr__(self):
|
|
|
return self.node.__repr__() + "::" + self.name
|
|
return self.node.__repr__() + "::" + self.name
|
|
|
|
|
|
|
@@ -1102,7 +1109,7 @@ class MantisNodeSocketCollection(dict):
|
|
|
def __init__(self, node, is_input=False):
|
|
def __init__(self, node, is_input=False):
|
|
|
self.is_input = is_input
|
|
self.is_input = is_input
|
|
|
self.node = node
|
|
self.node = node
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def init_sockets(self, sockets):
|
|
def init_sockets(self, sockets):
|
|
|
for socket in sockets:
|
|
for socket in sockets:
|
|
|
if isinstance(socket, str):
|
|
if isinstance(socket, str):
|
|
@@ -1112,15 +1119,14 @@ class MantisNodeSocketCollection(dict):
|
|
|
self[socket.name] = NodeSocket(is_input=self.is_input, name=socket.name, node=self.node)
|
|
self[socket.name] = NodeSocket(is_input=self.is_input, name=socket.name, node=self.node)
|
|
|
else:
|
|
else:
|
|
|
raise RuntimeError(f"NodeSocketCollection keys must be str or MantisSocketTemplate, not {type(socket)}")
|
|
raise RuntimeError(f"NodeSocketCollection keys must be str or MantisSocketTemplate, not {type(socket)}")
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def __delitem__(self, key):
|
|
def __delitem__(self, key):
|
|
|
"""Deletes a node socket by name, and all its links."""
|
|
"""Deletes a node socket by name, and all its links."""
|
|
|
socket = self[key]
|
|
socket = self[key]
|
|
|
for l in socket.links:
|
|
for l in socket.links:
|
|
|
l.die()
|
|
l.die()
|
|
|
super().__delitem__(key)
|
|
super().__delitem__(key)
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def __iter__(self):
|
|
def __iter__(self):
|
|
|
"""Makes the class iterable"""
|
|
"""Makes the class iterable"""
|
|
|
return iter(self.values())
|
|
return iter(self.values())
|
|
|
-
|
|
|