Changeset View
Changeset View
Standalone View
Standalone View
node_wrangler.py
| Show First 20 Lines • Show All 590 Lines • ▼ Show 20 Lines | |||||
| viewer_socket_name = "tmp_viewer" | viewer_socket_name = "tmp_viewer" | ||||
| def get_nodes_from_category(category_name, context): | def get_nodes_from_category(category_name, context): | ||||
| for category in node_categories_iter(context): | for category in node_categories_iter(context): | ||||
| if category.name == category_name: | if category.name == category_name: | ||||
| return sorted(category.items(context), key=lambda node: node.label) | return sorted(category.items(context), key=lambda node: node.label) | ||||
| def get_first_enabled_output(node): | |||||
| for output in node.outputs: | |||||
| if output.enabled: | |||||
| return output | |||||
| else: | |||||
| return node.outputs[0] | |||||
| def is_visible_socket(socket): | def is_visible_socket(socket): | ||||
| return not socket.hide and socket.enabled and socket.type != 'CUSTOM' | return not socket.hide and socket.enabled and socket.type != 'CUSTOM' | ||||
| def nice_hotkey_name(punc): | def nice_hotkey_name(punc): | ||||
| # convert the ugly string name into the actual character | # convert the ugly string name into the actual character | ||||
| nice_name = { | nice_name = { | ||||
| 'LEFTMOUSE': "LMB", | 'LEFTMOUSE': "LMB", | ||||
| 'MIDDLEMOUSE': "MMB", | 'MIDDLEMOUSE': "MMB", | ||||
| ▲ Show 20 Lines • Show All 1,899 Lines • ▼ Show 20 Lines | def execute(self, context): | ||||
| # Prevent trying to add Z-Combine in not 'COMPOSITING' node tree. | # Prevent trying to add Z-Combine in not 'COMPOSITING' node tree. | ||||
| # 'ZCOMBINE' works only if mode == 'MIX' | # 'ZCOMBINE' works only if mode == 'MIX' | ||||
| # Setting mode to None prevents trying to add 'ZCOMBINE' node. | # Setting mode to None prevents trying to add 'ZCOMBINE' node. | ||||
| if (merge_type == 'ZCOMBINE' or merge_type == 'ALPHAOVER') and tree_type != 'COMPOSITING': | if (merge_type == 'ZCOMBINE' or merge_type == 'ALPHAOVER') and tree_type != 'COMPOSITING': | ||||
| merge_type = 'MIX' | merge_type = 'MIX' | ||||
| mode = 'MIX' | mode = 'MIX' | ||||
| if (merge_type != 'MATH' and merge_type != 'GEOMETRY') and tree_type == 'GEOMETRY': | if (merge_type != 'MATH' and merge_type != 'GEOMETRY') and tree_type == 'GEOMETRY': | ||||
| merge_type = 'AUTO' | merge_type = 'AUTO' | ||||
| # The math nodes used for geometry nodes are of type 'ShaderNode' | # The MixRGB node and math nodes used for geometry nodes are of type 'ShaderNode' | ||||
| if merge_type == 'MATH' and tree_type == 'GEOMETRY': | if (merge_type == 'MATH' or merge_type == 'MIX') and tree_type == 'GEOMETRY': | ||||
| node_type = 'ShaderNode' | node_type = 'ShaderNode' | ||||
| selected_mix = [] # entry = [index, loc] | selected_mix = [] # entry = [index, loc] | ||||
| selected_shader = [] # entry = [index, loc] | selected_shader = [] # entry = [index, loc] | ||||
| selected_geometry = [] # entry = [index, loc] | selected_geometry = [] # entry = [index, loc] | ||||
| selected_math = [] # entry = [index, loc] | selected_math = [] # entry = [index, loc] | ||||
| selected_vector = [] # entry = [index, loc] | selected_vector = [] # entry = [index, loc] | ||||
| selected_z = [] # entry = [index, loc] | selected_z = [] # entry = [index, loc] | ||||
| selected_alphaover = [] # entry = [index, loc] | selected_alphaover = [] # entry = [index, loc] | ||||
| for i, node in enumerate(nodes): | for i, node in enumerate(nodes): | ||||
| if node.select and node.outputs: | if node.select and node.outputs: | ||||
| if merge_type == 'AUTO': | if merge_type == 'AUTO': | ||||
| for (type, types_list, dst) in ( | for (type, types_list, dst) in ( | ||||
| ('SHADER', ('MIX', 'ADD'), selected_shader), | ('SHADER', ('MIX', 'ADD'), selected_shader), | ||||
| ('GEOMETRY', [t[0] for t in geo_combine_operations], selected_geometry), | ('GEOMETRY', [t[0] for t in geo_combine_operations], selected_geometry), | ||||
| ('RGBA', [t[0] for t in blend_types], selected_mix), | ('RGBA', [t[0] for t in blend_types], selected_mix), | ||||
| ('VALUE', [t[0] for t in operations], selected_math), | ('VALUE', [t[0] for t in operations], selected_math), | ||||
| ('VECTOR', [], selected_vector), | ('VECTOR', [], selected_vector), | ||||
| ): | ): | ||||
| output_type = node.outputs[0].type | output = get_first_enabled_output(node) | ||||
| output_type = output.type | |||||
| valid_mode = mode in types_list | valid_mode = mode in types_list | ||||
| # When mode is 'MIX' we have to cheat since the mix node is not used in | # When mode is 'MIX' we have to cheat since the mix node is not used in | ||||
| # geometry nodes. | # geometry nodes. | ||||
| if tree_type == 'GEOMETRY': | if tree_type == 'GEOMETRY': | ||||
| if mode == 'MIX': | if mode == 'MIX': | ||||
| if output_type == 'VALUE' and type == 'VALUE': | if output_type == 'VALUE' and type == 'VALUE': | ||||
| valid_mode = True | valid_mode = True | ||||
| elif output_type == 'VECTOR' and type == 'VECTOR': | elif output_type == 'VECTOR' and type == 'VECTOR': | ||||
| Show All 34 Lines | def execute(self, context): | ||||
| # sort list by loc_x - reversed | # sort list by loc_x - reversed | ||||
| nodes_list.sort(key=lambda k: k[1], reverse=True) | nodes_list.sort(key=lambda k: k[1], reverse=True) | ||||
| # get maximum loc_x | # get maximum loc_x | ||||
| loc_x = nodes_list[0][1] + nodes_list[0][3] + 70 | loc_x = nodes_list[0][1] + nodes_list[0][3] + 70 | ||||
| nodes_list.sort(key=lambda k: k[2], reverse=True) | nodes_list.sort(key=lambda k: k[2], reverse=True) | ||||
| # Change the node type for math nodes in a geometry node tree. | # Change the node type for math nodes in a geometry node tree. | ||||
| if tree_type == 'GEOMETRY': | if tree_type == 'GEOMETRY': | ||||
| if nodes_list is selected_math or nodes_list is selected_vector: | if nodes_list is selected_math or nodes_list is selected_vector or nodes_list is selected_mix: | ||||
| node_type = 'ShaderNode' | node_type = 'ShaderNode' | ||||
| if mode == 'MIX': | if mode == 'MIX': | ||||
| mode = 'ADD' | mode = 'ADD' | ||||
| else: | else: | ||||
| node_type = 'GeometryNode' | node_type = 'GeometryNode' | ||||
| if merge_position == 'CENTER': | if merge_position == 'CENTER': | ||||
| loc_y = ((nodes_list[len(nodes_list) - 1][2]) + (nodes_list[len(nodes_list) - 2][2])) / 2 # average yloc of last two nodes (lowest two) | loc_y = ((nodes_list[len(nodes_list) - 1][2]) + (nodes_list[len(nodes_list) - 2][2])) / 2 # average yloc of last two nodes (lowest two) | ||||
| if nodes_list[len(nodes_list) - 1][-1] == True: # if last node is hidden, mix should be shifted up a bit | if nodes_list[len(nodes_list) - 1][-1] == True: # if last node is hidden, mix should be shifted up a bit | ||||
| ▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | def execute(self, context): | ||||
| # "last" node has been added as first, so its index is count_before. | # "last" node has been added as first, so its index is count_before. | ||||
| last_add = nodes[count_before] | last_add = nodes[count_before] | ||||
| # Create list of invalid indexes. | # Create list of invalid indexes. | ||||
| invalid_nodes = [nodes[n[0]] for n in (selected_mix + selected_math + selected_shader + selected_z + selected_geometry)] | invalid_nodes = [nodes[n[0]] for n in (selected_mix + selected_math + selected_shader + selected_z + selected_geometry)] | ||||
| # Special case: | # Special case: | ||||
| # Two nodes were selected and first selected has no output links, second selected has output links. | # Two nodes were selected and first selected has no output links, second selected has output links. | ||||
| # Then add links from last add to all links 'to_socket' of out links of second selected. | # Then add links from last add to all links 'to_socket' of out links of second selected. | ||||
| first_selected_output = get_first_enabled_output(first_selected) | |||||
| if len(nodes_list) == 2: | if len(nodes_list) == 2: | ||||
| if not first_selected.outputs[0].links: | if not first_selected_output.links: | ||||
| second_selected = nodes[nodes_list[1][0]] | second_selected = nodes[nodes_list[1][0]] | ||||
| for ss_link in second_selected.outputs[0].links: | for ss_link in second_selected.outputs[0].links: | ||||
| # Prevent cyclic dependencies when nodes to be merged are linked to one another. | # Prevent cyclic dependencies when nodes to be merged are linked to one another. | ||||
| # Link only if "to_node" index not in invalid indexes list. | # Link only if "to_node" index not in invalid indexes list. | ||||
| if not self.link_creates_cycle(ss_link, invalid_nodes): | if not self.link_creates_cycle(ss_link, invalid_nodes): | ||||
| links.new(last_add.outputs[0], ss_link.to_socket) | links.new(last_add.outputs[0], ss_link.to_socket) | ||||
| # add links from last_add to all links 'to_socket' of out links of first selected. | # add links from last_add to all links 'to_socket' of out links of first selected. | ||||
| for fs_link in first_selected.outputs[0].links: | for fs_link in first_selected_output.links: | ||||
| # Link only if "to_node" index not in invalid indexes list. | # Link only if "to_node" index not in invalid indexes list. | ||||
| if not self.link_creates_cycle(fs_link, invalid_nodes): | if not self.link_creates_cycle(fs_link, invalid_nodes): | ||||
| links.new(last_add.outputs[0], fs_link.to_socket) | links.new(last_add.outputs[0], fs_link.to_socket) | ||||
| # add link from "first" selected and "first" add node | # add link from "first" selected and "first" add node | ||||
| node_to = nodes[count_after - 1] | node_to = nodes[count_after - 1] | ||||
| links.new(first_selected.outputs[0], node_to.inputs[first]) | links.new(first_selected_output, node_to.inputs[first]) | ||||
| if node_to.type == 'ZCOMBINE': | if node_to.type == 'ZCOMBINE': | ||||
| for fs_out in first_selected.outputs: | for fs_out in first_selected.outputs: | ||||
| if fs_out != first_selected.outputs[0] and fs_out.name in ('Z', 'Depth'): | if fs_out != first_selected_output and fs_out.name in ('Z', 'Depth'): | ||||
| links.new(fs_out, node_to.inputs[1]) | links.new(fs_out, node_to.inputs[1]) | ||||
| break | break | ||||
| # add links between added ADD nodes and between selected and ADD nodes | # add links between added ADD nodes and between selected and ADD nodes | ||||
| for i in range(count_adds): | for i in range(count_adds): | ||||
| if i < count_adds - 1: | if i < count_adds - 1: | ||||
| node_from = nodes[index] | node_from = nodes[index] | ||||
| node_to = nodes[index - 1] | node_to = nodes[index - 1] | ||||
| node_to_input_i = first | node_to_input_i = first | ||||
| node_to_z_i = 1 # if z combine - link z to first z input | node_to_z_i = 1 # if z combine - link z to first z input | ||||
| links.new(node_from.outputs[0], node_to.inputs[node_to_input_i]) | links.new(get_first_enabled_output(node_from), node_to.inputs[node_to_input_i]) | ||||
| if node_to.type == 'ZCOMBINE': | if node_to.type == 'ZCOMBINE': | ||||
| for from_out in node_from.outputs: | for from_out in node_from.outputs: | ||||
| if from_out != node_from.outputs[0] and from_out.name in ('Z', 'Depth'): | if from_out != get_first_enabled_output(node_from) and from_out.name in ('Z', 'Depth'): | ||||
| links.new(from_out, node_to.inputs[node_to_z_i]) | links.new(from_out, node_to.inputs[node_to_z_i]) | ||||
| if len(nodes_list) > 1: | if len(nodes_list) > 1: | ||||
| node_from = nodes[nodes_list[i + 1][0]] | node_from = nodes[nodes_list[i + 1][0]] | ||||
| node_to = nodes[index] | node_to = nodes[index] | ||||
| node_to_input_i = second | node_to_input_i = second | ||||
| node_to_z_i = 3 # if z combine - link z to second z input | node_to_z_i = 3 # if z combine - link z to second z input | ||||
| links.new(node_from.outputs[0], node_to.inputs[node_to_input_i]) | links.new(get_first_enabled_output(node_from), node_to.inputs[node_to_input_i]) | ||||
| if node_to.type == 'ZCOMBINE': | if node_to.type == 'ZCOMBINE': | ||||
| for from_out in node_from.outputs: | for from_out in node_from.outputs: | ||||
| if from_out != node_from.outputs[0] and from_out.name in ('Z', 'Depth'): | if from_out != get_first_enabled_output(node_from) and from_out.name in ('Z', 'Depth'): | ||||
| links.new(from_out, node_to.inputs[node_to_z_i]) | links.new(from_out, node_to.inputs[node_to_z_i]) | ||||
| index -= 1 | index -= 1 | ||||
| # set "last" of added nodes as active | # set "last" of added nodes as active | ||||
| nodes.active = last_add | nodes.active = last_add | ||||
| for i, x, y, dx, h in nodes_list: | for i, x, y, dx, h in nodes_list: | ||||
| nodes[i].select = False | nodes[i].select = False | ||||
| return {'FINISHED'} | return {'FINISHED'} | ||||
| ▲ Show 20 Lines • Show All 2,708 Lines • Show Last 20 Lines | |||||