|
|
@@ -141,7 +141,7 @@ def make_connections_to_ng_dummy(base_tree, tree_path_names, local_mantis_nodes,
|
|
|
else:
|
|
|
prRed("No available auto-generated class for input %s in %s" % (inp.name, np.name))
|
|
|
|
|
|
-def gen_mantis_nodes(base_tree, current_tree, tree_path_names, all_mantis_nodes, local_mantis_nodes, dummy_nodes, group_nodes, schema_nodes ):
|
|
|
+def gen_mantis_nodes(base_tree, current_tree, tree_path_names, mContext, all_mantis_nodes, local_mantis_nodes, dummy_nodes, group_nodes, schema_nodes ):
|
|
|
from .internal_nodes import DummyNode
|
|
|
for ui_node in current_tree.nodes:
|
|
|
# HACK I found that this isn't being set sometimes. I wonder why? It makes the most sense to do this here.
|
|
|
@@ -182,10 +182,11 @@ def gen_mantis_nodes(base_tree, current_tree, tree_path_names, all_mantis_nodes,
|
|
|
mantis_node = None
|
|
|
prRed(f"Can't make mantis_node for.. {ui_node.bl_idname}")
|
|
|
# this should be done at init
|
|
|
+ mantis_node.mContext = mContext
|
|
|
if mantis_node.signature[0] not in ['MANTIS_AUTOGENERATED'] and mantis_node.node_type not in ['SCHEMA', 'DUMMY', 'DUMMY_SCHEMA']:
|
|
|
mantis_node.fill_parameters()
|
|
|
|
|
|
-def data_from_tree(base_tree, tree_path, dummy_nodes, all_mantis_nodes, all_schema):#
|
|
|
+def data_from_tree(base_tree, tree_path, mContext, dummy_nodes, all_mantis_nodes, all_schema):#
|
|
|
# TODO: it should be relatively easy to make this use a while loop instead of recursion.
|
|
|
local_mantis_nodes, group_nodes = {}, []
|
|
|
tree_path_names = [tree.name for tree in tree_path if hasattr(tree, "name")]
|
|
|
@@ -197,7 +198,7 @@ def data_from_tree(base_tree, tree_path, dummy_nodes, all_mantis_nodes, all_sche
|
|
|
if current_tree: # the node-group may not have a tree set - if so, ignore it.
|
|
|
from .utilities import clear_reroutes
|
|
|
links = clear_reroutes(list(current_tree.links))
|
|
|
- gen_mantis_nodes(base_tree, current_tree, tree_path_names, all_mantis_nodes, local_mantis_nodes, dummy_nodes, group_nodes, all_schema)
|
|
|
+ gen_mantis_nodes(base_tree, current_tree, tree_path_names, mContext, all_mantis_nodes, local_mantis_nodes, dummy_nodes, group_nodes, all_schema)
|
|
|
|
|
|
from .utilities import link_mantis_nodes
|
|
|
for link in links:
|
|
|
@@ -207,9 +208,94 @@ def data_from_tree(base_tree, tree_path, dummy_nodes, all_mantis_nodes, all_sche
|
|
|
insert_default_values_base_tree(base_tree, all_mantis_nodes)
|
|
|
# Now, descend into the Node Groups and recurse
|
|
|
for mantis_node in group_nodes:
|
|
|
- data_from_tree(base_tree, tree_path+[mantis_node.ui_node], dummy_nodes, all_mantis_nodes, all_schema)
|
|
|
+ data_from_tree(base_tree, tree_path+[mantis_node.ui_node], mContext, dummy_nodes, all_mantis_nodes, all_schema)
|
|
|
return dummy_nodes, all_mantis_nodes, all_schema
|
|
|
|
|
|
+# Do not use these input names as overlay keys:
|
|
|
+forbidden_key_names = ["",]
|
|
|
+forbidden_in_key_name = ['$',]
|
|
|
+def node_scan_overlays(node, socket_id,):
|
|
|
+ interface_nodes = node.mContext.interface_nodes
|
|
|
+ from .utilities import get_ui_node
|
|
|
+ ui_node = get_ui_node(node.ui_signature, node.base_tree)
|
|
|
+ # we'll assume that the overlay tag system checked if this is linked.
|
|
|
+ # First let's check if it is a simple input node, by checking outputs that are marked "input"
|
|
|
+ for socket in ui_node.outputs:
|
|
|
+ # weird edge case for simple input nodes with unnamed sockets
|
|
|
+ # the socket.identifier is not used by Mantis but it defaults to 'socket'\
|
|
|
+ if socket.identifier == socket_id and socket.input == True: break
|
|
|
+ else:
|
|
|
+ for socket in ui_node.inputs:
|
|
|
+ if socket.identifier == socket_id: break
|
|
|
+ else:
|
|
|
+ raise KeyError(f"Socket not found by ID {socket_id} in node {node.ui_signature}\n"
|
|
|
+ f"Candidates: {[socket.identifier for socket in ui_node.inputs]}")
|
|
|
+ value = socket.default_value # get the ACTUAL UI value
|
|
|
+ if not isinstance(value, str): return
|
|
|
+ # First step: get the interface nodes and the overlay keys
|
|
|
+ # this should only check interfaces that are ancestors of this node
|
|
|
+ my_interfaces = []
|
|
|
+ for index in range(len(node.signature)-1):
|
|
|
+ if index == 0: continue # root
|
|
|
+ interface_signature = (*node.signature[:index+1], "InputInterface")
|
|
|
+ my_interfaces.append( interface_nodes[interface_signature] )
|
|
|
+ # the my_interfaces list is sorted in REVERSE order of importance
|
|
|
+ # Next, get all the overlay providers.
|
|
|
+ name_to_id_map = {}
|
|
|
+ overlay_keys = set()
|
|
|
+ root_overlay_values = {}
|
|
|
+ # First, we'll get the base tree's default inputs
|
|
|
+ for interface_item in node.mContext.base_tree.interface.items_tree:
|
|
|
+ if interface_item.item_type != "SOCKET": continue
|
|
|
+ if interface_item.in_out != "INPUT": continue
|
|
|
+ # NOTE this will need to change if overlays extend to other data types
|
|
|
+ if not hasattr(interface_item, "default_string"): continue
|
|
|
+ # NOTE that there may be duplicate names. Too bad!
|
|
|
+ root_overlay_values[interface_item.name] = interface_item.default_string
|
|
|
+ overlay_keys.add(interface_item.name)
|
|
|
+ name_to_id_map[interface_item.name] = None # don't worry about it
|
|
|
+ for interface_node in interface_nodes.values():
|
|
|
+ # problem: the interface node stores socket identifiers as keys
|
|
|
+ # so in reality we need to get the group UI node and ask for its input names
|
|
|
+ # if there is a duplicate name, too bad!
|
|
|
+ group_ui_node = get_ui_node(interface_node.ui_signature[:-1], node.base_tree)
|
|
|
+ for input in group_ui_node.inputs:
|
|
|
+ if input.name in forbidden_key_names: continue
|
|
|
+ for substr in forbidden_in_key_name:
|
|
|
+ if substr in input.name:
|
|
|
+ break
|
|
|
+ else: # if we do not find a bad substr
|
|
|
+ name_to_id_map[input.name]=input.identifier
|
|
|
+ overlay_keys.add(input.name)
|
|
|
+ # sort by reverse length so we find "CatsAndFrogs" before "Cats"
|
|
|
+ overlay_keys = sorted(overlay_keys, key= lambda a :-1*len(a))
|
|
|
+ overlay_tries = value.split("$")
|
|
|
+ result = overlay_tries[0] # the 0th element is always before the split character
|
|
|
+ # the reason for the difference between overlay_try and key is because
|
|
|
+ # we don't actually know if the $text part has a key in it
|
|
|
+ for overlay_try in overlay_tries[1:]:
|
|
|
+ overlay_resolved_value = "$" + overlay_try
|
|
|
+ for key in overlay_keys:
|
|
|
+ if key in overlay_try:
|
|
|
+ overlay_resolved_value = "$" + key
|
|
|
+ for interface in reversed(my_interfaces): # since this is reversed when we build it
|
|
|
+ if interface.inputs.get(actual_key := name_to_id_map.get(key)):
|
|
|
+ overlay_resolved_value = overlay_try.replace(key, interface.evaluate_input(actual_key))
|
|
|
+ break
|
|
|
+ else: # we'll try the base tree
|
|
|
+ if base_tree_result := root_overlay_values.get(overlay_try):
|
|
|
+ overlay_resolved_value = base_tree_result
|
|
|
+ else:
|
|
|
+ prOrange(f"WARN: no overlay value applied for {node.ui_signature} for key {key}")
|
|
|
+ break # we found the key and are done here. One found Key per overlay-try
|
|
|
+ result += overlay_resolved_value
|
|
|
+ # Simple Input sockets with unnamed sockets assign this ID automatically
|
|
|
+ # But Mantis uses the name instead. Usually the name and ID are the same.
|
|
|
+ if socket_id == 'socket' and ui_node.outputs[0].name == "":
|
|
|
+ socket_id = ''
|
|
|
+ node.parameters[socket_id] = result
|
|
|
+ return result # because sometimes I need to get the result, too
|
|
|
+
|
|
|
from .utilities import check_and_add_root, init_connections, init_dependencies, init_schema_dependencies
|
|
|
|
|
|
def is_signature_in_other_signature(parent_signature, child_signature):
|
|
|
@@ -380,7 +466,7 @@ def parse_tree(base_tree, error_popups=False):
|
|
|
# then they stick around because the function definition inits them once and keeps a reference
|
|
|
# so instead I have to supply them to avoid ugly code or bugs elsewhere
|
|
|
# it's REALLY confusing when you run into this sort of problem. So it warrants four entire lines of comments!
|
|
|
- dummy_nodes, all_mantis_nodes, all_schema = data_from_tree(base_tree, tree_path = [None], dummy_nodes = {}, all_mantis_nodes = {}, all_schema={})
|
|
|
+ dummy_nodes, all_mantis_nodes, all_schema = data_from_tree(base_tree, tree_path = [None], mContext=mContext, dummy_nodes = {}, all_mantis_nodes = {}, all_schema={})
|
|
|
for dummy in dummy_nodes.values(): # reroute the links in the group nodes
|
|
|
if (hasattr(dummy, "reroute_links")):
|
|
|
dummy.reroute_links(dummy, all_mantis_nodes)
|
|
|
@@ -394,7 +480,8 @@ def parse_tree(base_tree, error_popups=False):
|
|
|
|
|
|
from .base_definitions import array_output_types, GraphError
|
|
|
for mantis_node in all_mantis_nodes.values():
|
|
|
- # add the Mantis Context here, so that it available during parsing.
|
|
|
+ # TODO I still need to assign mContext here because of autogen_node
|
|
|
+ # so I have to do a deeper refactor to ensure autogen nodes get this at creation time.
|
|
|
mantis_node.mContext = mContext
|
|
|
if mantis_node.node_type in ["DUMMY"]: # clean up the groups
|
|
|
if mantis_node.ui_node.bl_idname in ("MantisNodeGroup", "NodeGroupOutput"):
|
|
|
@@ -407,6 +494,8 @@ def parse_tree(base_tree, error_popups=False):
|
|
|
if mantis_node.__class__.__name__ in array_output_types:
|
|
|
solve_only_these.append(mantis_node)
|
|
|
array_nodes.append(mantis_node)
|
|
|
+ if mantis_node.node_type == 'INTERFACE':
|
|
|
+ mContext.interface_nodes[mantis_node.signature] = mantis_node
|
|
|
|
|
|
from itertools import chain
|
|
|
for schema in chain(all_schema.values(), array_nodes):
|
|
|
@@ -599,6 +688,22 @@ def execute_tree(nodes, base_tree, context, error_popups = False, profile=False)
|
|
|
mantis_node.reset_execution()
|
|
|
mContext.execution_failed = False
|
|
|
|
|
|
+ interface_nodes = {}
|
|
|
+ from .internal_nodes import GroupInterface
|
|
|
+ for node in nodes.values():
|
|
|
+ if isinstance(node, GroupInterface):
|
|
|
+ interface_nodes[node.signature] = node
|
|
|
+ overlay_tagged_nodes = {}
|
|
|
+ for node_signature, socket_id in mContext.tagged_for_overlay:
|
|
|
+ if overlay_tagged_nodes.get(node_signature):
|
|
|
+ overlay_tagged_nodes[node_signature].append(socket_id)
|
|
|
+ else:
|
|
|
+ overlay_tagged_nodes[node_signature] = [socket_id]
|
|
|
+ def check_and_apply_overlay(n):
|
|
|
+ if overlays_for_this_node := overlay_tagged_nodes.get(n.signature):
|
|
|
+ for socket_id in overlays_for_this_node:
|
|
|
+ node_scan_overlays(n, socket_id,)
|
|
|
+
|
|
|
select_me, switch_me = [], [] # switch the mode on these objects
|
|
|
active = None # only need it for switching modes
|
|
|
select_me = []
|
|
|
@@ -612,6 +717,7 @@ def execute_tree(nodes, base_tree, context, error_popups = False, profile=False)
|
|
|
sorted_nodes, execution_failed = sort_execution(nodes)
|
|
|
for n in sorted_nodes:
|
|
|
try:
|
|
|
+ check_and_apply_overlay(n)
|
|
|
if not n.prepared:
|
|
|
if profiler: profiler.record(n, "bPrepare", context)
|
|
|
else: n.bPrepare(context)
|
|
|
@@ -636,6 +742,7 @@ def execute_tree(nodes, base_tree, context, error_popups = False, profile=False)
|
|
|
|
|
|
for n in sorted_nodes:
|
|
|
try:
|
|
|
+ check_and_apply_overlay(n)
|
|
|
if not n.prepared:
|
|
|
if profiler: profiler.record(n, "bPrepare", context)
|
|
|
else: n.bPrepare(context)
|