Node Wrangler: refactor by splitting the script into several files #104463
@ -125,9 +125,11 @@ class NWMergeNodesMenu(Menu, NWBase):
|
|||||||
props.mode = 'MIX'
|
props.mode = 'MIX'
|
||||||
props.merge_type = 'ALPHAOVER'
|
props.merge_type = 'ALPHAOVER'
|
||||||
|
|
||||||
|
|
||||||
class NWMergeGeometryMenu(Menu, NWBase):
|
class NWMergeGeometryMenu(Menu, NWBase):
|
||||||
bl_idname = "NODE_MT_nw_merge_geometry_menu"
|
bl_idname = "NODE_MT_nw_merge_geometry_menu"
|
||||||
bl_label = "Merge Selected Nodes using Geometry Nodes"
|
bl_label = "Merge Selected Nodes using Geometry Nodes"
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
# The boolean node + Join Geometry node
|
# The boolean node + Join Geometry node
|
||||||
@ -136,6 +138,7 @@ class NWMergeGeometryMenu(Menu, NWBase):
|
|||||||
props.mode = type
|
props.mode = type
|
||||||
props.merge_type = 'GEOMETRY'
|
props.merge_type = 'GEOMETRY'
|
||||||
|
|
||||||
|
|
||||||
class NWMergeShadersMenu(Menu, NWBase):
|
class NWMergeShadersMenu(Menu, NWBase):
|
||||||
bl_idname = "NODE_MT_nw_merge_shaders_menu"
|
bl_idname = "NODE_MT_nw_merge_shaders_menu"
|
||||||
bl_label = "Merge Selected Nodes using Shaders"
|
bl_label = "Merge Selected Nodes using Shaders"
|
||||||
@ -172,7 +175,10 @@ class NWConnectionListOutputs(Menu, NWBase):
|
|||||||
for index, output in enumerate(n1.outputs):
|
for index, output in enumerate(n1.outputs):
|
||||||
# Only show sockets that are exposed.
|
# Only show sockets that are exposed.
|
||||||
if output.enabled:
|
if output.enabled:
|
||||||
layout.operator(operators.NWCallInputsMenu.bl_idname, text=output.name, icon="RADIOBUT_OFF").from_socket=index
|
layout.operator(
|
||||||
|
operators.NWCallInputsMenu.bl_idname,
|
||||||
|
text=output.name,
|
||||||
|
icon="RADIOBUT_OFF").from_socket = index
|
||||||
|
|
||||||
|
|
||||||
class NWConnectionListInputs(Menu, NWBase):
|
class NWConnectionListInputs(Menu, NWBase):
|
||||||
@ -407,9 +413,11 @@ def draw_switch_category_submenu(self, context):
|
|||||||
# APPENDAGES TO EXISTING UI
|
# APPENDAGES TO EXISTING UI
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
def select_parent_children_buttons(self, context):
|
def select_parent_children_buttons(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
layout.operator(operators.NWSelectParentChildren.bl_idname, text="Select frame's members (children)").option = 'CHILD'
|
layout.operator(operators.NWSelectParentChildren.bl_idname,
|
||||||
|
text="Select frame's members (children)").option = 'CHILD'
|
||||||
layout.operator(operators.NWSelectParentChildren.bl_idname, text="Select parent frame").option = 'PARENT'
|
layout.operator(operators.NWSelectParentChildren.bl_idname, text="Select parent frame").option = 'PARENT'
|
||||||
|
|
||||||
|
|
||||||
@ -441,7 +449,7 @@ def save_viewer_menu_func(self, context):
|
|||||||
def reset_nodes_button(self, context):
|
def reset_nodes_button(self, context):
|
||||||
node_active = context.active_node
|
node_active = context.active_node
|
||||||
node_selected = context.selected_nodes
|
node_selected = context.selected_nodes
|
||||||
node_ignore = ["FRAME","REROUTE", "GROUP"]
|
node_ignore = ["FRAME", "REROUTE", "GROUP"]
|
||||||
|
|
||||||
# Check if active node is in the selection and respective type
|
# Check if active node is in the selection and respective type
|
||||||
if (len(node_selected) == 1) and node_active and node_active.select and node_active.type not in node_ignore:
|
if (len(node_selected) == 1) and node_active and node_active.select and node_active.type not in node_ignore:
|
||||||
@ -479,6 +487,7 @@ classes = (
|
|||||||
NWSwitchNodeTypeMenu,
|
NWSwitchNodeTypeMenu,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
from bpy.utils import register_class
|
from bpy.utils import register_class
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
|
@ -94,7 +94,8 @@ class NWLazyMix(Operator, NWBase):
|
|||||||
args = (self, context, 'MIX')
|
args = (self, context, 'MIX')
|
||||||
# Add the region OpenGL drawing callback
|
# Add the region OpenGL drawing callback
|
||||||
# draw in view space with 'POST_VIEW' and 'PRE_VIEW'
|
# draw in view space with 'POST_VIEW' and 'PRE_VIEW'
|
||||||
self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(draw_callback_nodeoutline, args, 'WINDOW', 'POST_PIXEL')
|
self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(
|
||||||
|
draw_callback_nodeoutline, args, 'WINDOW', 'POST_PIXEL')
|
||||||
|
|
||||||
self.mouse_path = []
|
self.mouse_path = []
|
||||||
|
|
||||||
@ -152,7 +153,7 @@ class NWLazyConnect(Operator, NWBase):
|
|||||||
original_sel = []
|
original_sel = []
|
||||||
original_unsel = []
|
original_unsel = []
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
if node.select == True:
|
if node.select:
|
||||||
node.select = False
|
node.select = False
|
||||||
original_sel.append(node)
|
original_sel.append(node)
|
||||||
else:
|
else:
|
||||||
@ -160,7 +161,7 @@ class NWLazyConnect(Operator, NWBase):
|
|||||||
node1.select = True
|
node1.select = True
|
||||||
node2.select = True
|
node2.select = True
|
||||||
|
|
||||||
#link_success = autolink(node1, node2, links)
|
# link_success = autolink(node1, node2, links)
|
||||||
if self.with_menu:
|
if self.with_menu:
|
||||||
if len(node1.outputs) > 1 and node2.inputs:
|
if len(node1.outputs) > 1 and node2.inputs:
|
||||||
bpy.ops.wm.call_menu("INVOKE_DEFAULT", name=NWConnectionListOutputs.bl_idname)
|
bpy.ops.wm.call_menu("INVOKE_DEFAULT", name=NWConnectionListOutputs.bl_idname)
|
||||||
@ -199,7 +200,8 @@ class NWLazyConnect(Operator, NWBase):
|
|||||||
args = (self, context, mode)
|
args = (self, context, mode)
|
||||||
# Add the region OpenGL drawing callback
|
# Add the region OpenGL drawing callback
|
||||||
# draw in view space with 'POST_VIEW' and 'PRE_VIEW'
|
# draw in view space with 'POST_VIEW' and 'PRE_VIEW'
|
||||||
self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(draw_callback_nodeoutline, args, 'WINDOW', 'POST_PIXEL')
|
self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(
|
||||||
|
draw_callback_nodeoutline, args, 'WINDOW', 'POST_PIXEL')
|
||||||
|
|
||||||
self.mouse_path = []
|
self.mouse_path = []
|
||||||
|
|
||||||
@ -216,13 +218,19 @@ class NWDeleteUnused(Operator, NWBase):
|
|||||||
bl_label = 'Delete Unused Nodes'
|
bl_label = 'Delete Unused Nodes'
|
||||||
bl_options = {'REGISTER', 'UNDO'}
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
delete_muted: BoolProperty(name="Delete Muted", description="Delete (but reconnect, like Ctrl-X) all muted nodes", default=True)
|
delete_muted: BoolProperty(
|
||||||
delete_frames: BoolProperty(name="Delete Empty Frames", description="Delete all frames that have no nodes inside them", default=True)
|
name="Delete Muted",
|
||||||
|
description="Delete (but reconnect, like Ctrl-X) all muted nodes",
|
||||||
|
default=True)
|
||||||
|
delete_frames: BoolProperty(
|
||||||
|
name="Delete Empty Frames",
|
||||||
|
description="Delete all frames that have no nodes inside them",
|
||||||
|
default=True)
|
||||||
|
|
||||||
def is_unused_node(self, node):
|
def is_unused_node(self, node):
|
||||||
end_types = ['OUTPUT_MATERIAL', 'OUTPUT', 'VIEWER', 'COMPOSITE', \
|
end_types = ['OUTPUT_MATERIAL', 'OUTPUT', 'VIEWER', 'COMPOSITE',
|
||||||
'SPLITVIEWER', 'OUTPUT_FILE', 'LEVELS', 'OUTPUT_LIGHT', \
|
'SPLITVIEWER', 'OUTPUT_FILE', 'LEVELS', 'OUTPUT_LIGHT',
|
||||||
'OUTPUT_WORLD', 'GROUP_INPUT', 'GROUP_OUTPUT', 'FRAME']
|
'OUTPUT_WORLD', 'GROUP_INPUT', 'GROUP_OUTPUT', 'FRAME']
|
||||||
if node.type in end_types:
|
if node.type in end_types:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -245,7 +253,7 @@ class NWDeleteUnused(Operator, NWBase):
|
|||||||
# Store selection
|
# Store selection
|
||||||
selection = []
|
selection = []
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
if node.select == True:
|
if node.select:
|
||||||
selection.append(node.name)
|
selection.append(node.name)
|
||||||
|
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
@ -362,12 +370,14 @@ class NWSwapLinks(Operator, NWBase):
|
|||||||
try:
|
try:
|
||||||
links.new(n2.outputs[connection[0]], connection[1])
|
links.new(n2.outputs[connection[0]], connection[1])
|
||||||
except:
|
except:
|
||||||
self.report({'WARNING'}, "Some connections have been lost due to differing numbers of output sockets")
|
self.report({'WARNING'},
|
||||||
|
"Some connections have been lost due to differing numbers of output sockets")
|
||||||
for connection in n2_outputs:
|
for connection in n2_outputs:
|
||||||
try:
|
try:
|
||||||
links.new(n1.outputs[connection[0]], connection[1])
|
links.new(n1.outputs[connection[0]], connection[1])
|
||||||
except:
|
except:
|
||||||
self.report({'WARNING'}, "Some connections have been lost due to differing numbers of output sockets")
|
self.report({'WARNING'},
|
||||||
|
"Some connections have been lost due to differing numbers of output sockets")
|
||||||
else:
|
else:
|
||||||
if n1.outputs or n2.outputs:
|
if n1.outputs or n2.outputs:
|
||||||
self.report({'WARNING'}, "One of the nodes has no outputs!")
|
self.report({'WARNING'}, "One of the nodes has no outputs!")
|
||||||
@ -381,14 +391,14 @@ class NWSwapLinks(Operator, NWBase):
|
|||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
if n1.inputs:
|
if n1.inputs:
|
||||||
types = []
|
types = []
|
||||||
i=0
|
i = 0
|
||||||
for i1 in n1.inputs:
|
for i1 in n1.inputs:
|
||||||
if i1.is_linked and not i1.is_multi_input:
|
if i1.is_linked and not i1.is_multi_input:
|
||||||
similar_types = 0
|
similar_types = 0
|
||||||
for i2 in n1.inputs:
|
for i2 in n1.inputs:
|
||||||
if i1.type == i2.type and i2.is_linked and not i2.is_multi_input:
|
if i1.type == i2.type and i2.is_linked and not i2.is_multi_input:
|
||||||
similar_types += 1
|
similar_types += 1
|
||||||
types.append ([i1, similar_types, i])
|
types.append([i1, similar_types, i])
|
||||||
i += 1
|
i += 1
|
||||||
types.sort(key=lambda k: k[1], reverse=True)
|
types.sort(key=lambda k: k[1], reverse=True)
|
||||||
|
|
||||||
@ -409,7 +419,7 @@ class NWSwapLinks(Operator, NWBase):
|
|||||||
fs = t[0].links[0].from_socket
|
fs = t[0].links[0].from_socket
|
||||||
i = t[2]
|
i = t[2]
|
||||||
links.remove(t[0].links[0])
|
links.remove(t[0].links[0])
|
||||||
if i+1 == len(n1.inputs):
|
if i + 1 == len(n1.inputs):
|
||||||
i = -1
|
i = -1
|
||||||
i += 1
|
i += 1
|
||||||
while n1.inputs[i].is_linked:
|
while n1.inputs[i].is_linked:
|
||||||
@ -495,24 +505,24 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def ensure_viewer_socket(self, node, socket_type, connect_socket=None):
|
def ensure_viewer_socket(self, node, socket_type, connect_socket=None):
|
||||||
#check if a viewer output already exists in a node group otherwise create
|
# check if a viewer output already exists in a node group otherwise create
|
||||||
if hasattr(node, "node_tree"):
|
if hasattr(node, "node_tree"):
|
||||||
index = None
|
index = None
|
||||||
if len(node.node_tree.outputs):
|
if len(node.node_tree.outputs):
|
||||||
free_socket = None
|
free_socket = None
|
||||||
for i, socket in enumerate(node.node_tree.outputs):
|
for i, socket in enumerate(node.node_tree.outputs):
|
||||||
if is_viewer_socket(socket) and is_visible_socket(node.outputs[i]) and socket.type == socket_type:
|
if is_viewer_socket(socket) and is_visible_socket(node.outputs[i]) and socket.type == socket_type:
|
||||||
#if viewer output is already used but leads to the same socket we can still use it
|
# if viewer output is already used but leads to the same socket we can still use it
|
||||||
is_used = self.is_socket_used_other_mats(socket)
|
is_used = self.is_socket_used_other_mats(socket)
|
||||||
if is_used:
|
if is_used:
|
||||||
if connect_socket == None:
|
if connect_socket is None:
|
||||||
continue
|
continue
|
||||||
groupout = get_group_output_node(node.node_tree)
|
groupout = get_group_output_node(node.node_tree)
|
||||||
groupout_input = groupout.inputs[i]
|
groupout_input = groupout.inputs[i]
|
||||||
links = groupout_input.links
|
links = groupout_input.links
|
||||||
if connect_socket not in [link.from_socket for link in links]:
|
if connect_socket not in [link.from_socket for link in links]:
|
||||||
continue
|
continue
|
||||||
index=i
|
index = i
|
||||||
break
|
break
|
||||||
if not free_socket:
|
if not free_socket:
|
||||||
free_socket = i
|
free_socket = i
|
||||||
@ -520,7 +530,7 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
index = free_socket
|
index = free_socket
|
||||||
|
|
||||||
if not index:
|
if not index:
|
||||||
#create viewer socket
|
# create viewer socket
|
||||||
node.node_tree.outputs.new(socket_type, viewer_socket_name)
|
node.node_tree.outputs.new(socket_type, viewer_socket_name)
|
||||||
index = len(node.node_tree.outputs) - 1
|
index = len(node.node_tree.outputs) - 1
|
||||||
node.node_tree.outputs[index].NWViewerSocket = True
|
node.node_tree.outputs[index].NWViewerSocket = True
|
||||||
@ -541,12 +551,12 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
|
|
||||||
def get_shader_output_node(self, tree):
|
def get_shader_output_node(self, tree):
|
||||||
for node in tree.nodes:
|
for node in tree.nodes:
|
||||||
if node.type == self.shader_output_type and node.is_active_output == True:
|
if node.type == self.shader_output_type and node.is_active_output:
|
||||||
return node
|
return node
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def ensure_group_output(cls, tree):
|
def ensure_group_output(cls, tree):
|
||||||
#check if a group output node exists otherwise create
|
# check if a group output node exists otherwise create
|
||||||
groupout = get_group_output_node(tree)
|
groupout = get_group_output_node(tree)
|
||||||
if not groupout:
|
if not groupout:
|
||||||
groupout = tree.nodes.new('NodeGroupOutput')
|
groupout = tree.nodes.new('NodeGroupOutput')
|
||||||
@ -575,7 +585,7 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
socket = next_node.node_tree.outputs[socket_index]
|
socket = next_node.node_tree.outputs[socket_index]
|
||||||
if is_viewer_socket(socket) and socket not in sockets:
|
if is_viewer_socket(socket) and socket not in sockets:
|
||||||
sockets.append(socket)
|
sockets.append(socket)
|
||||||
#continue search inside of node group but restrict socket to where we came from
|
# continue search inside of node group but restrict socket to where we came from
|
||||||
groupout = get_group_output_node(next_node.node_tree)
|
groupout = get_group_output_node(next_node.node_tree)
|
||||||
cls.search_sockets(groupout, sockets, index=socket_index)
|
cls.search_sockets(groupout, sockets, index=socket_index)
|
||||||
|
|
||||||
@ -592,12 +602,12 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
cls.scan_nodes(node.node_tree, sockets)
|
cls.scan_nodes(node.node_tree, sockets)
|
||||||
|
|
||||||
def link_leads_to_used_socket(self, link):
|
def link_leads_to_used_socket(self, link):
|
||||||
#return True if link leads to a socket that is already used in this material
|
# return True if link leads to a socket that is already used in this material
|
||||||
socket = get_internal_socket(link.to_socket)
|
socket = get_internal_socket(link.to_socket)
|
||||||
return (socket and self.is_socket_used_active_mat(socket))
|
return (socket and self.is_socket_used_active_mat(socket))
|
||||||
|
|
||||||
def is_socket_used_active_mat(self, socket):
|
def is_socket_used_active_mat(self, socket):
|
||||||
#ensure used sockets in active material is calculated and check given socket
|
# ensure used sockets in active material is calculated and check given socket
|
||||||
if not hasattr(self, "used_viewer_sockets_active_mat"):
|
if not hasattr(self, "used_viewer_sockets_active_mat"):
|
||||||
self.used_viewer_sockets_active_mat = []
|
self.used_viewer_sockets_active_mat = []
|
||||||
materialout = self.get_shader_output_node(bpy.context.space_data.node_tree)
|
materialout = self.get_shader_output_node(bpy.context.space_data.node_tree)
|
||||||
@ -606,7 +616,7 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
return socket in self.used_viewer_sockets_active_mat
|
return socket in self.used_viewer_sockets_active_mat
|
||||||
|
|
||||||
def is_socket_used_other_mats(self, socket):
|
def is_socket_used_other_mats(self, socket):
|
||||||
#ensure used sockets in other materials are calculated and check given socket
|
# ensure used sockets in other materials are calculated and check given socket
|
||||||
if not hasattr(self, "used_viewer_sockets_other_mats"):
|
if not hasattr(self, "used_viewer_sockets_other_mats"):
|
||||||
self.used_viewer_sockets_other_mats = []
|
self.used_viewer_sockets_other_mats = []
|
||||||
for mat in bpy.data.materials:
|
for mat in bpy.data.materials:
|
||||||
@ -680,7 +690,7 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
socket_type = 'GEOMETRY'
|
socket_type = 'GEOMETRY'
|
||||||
# Find an input socket of the output of type geometry
|
# Find an input socket of the output of type geometry
|
||||||
geometryoutindex = None
|
geometryoutindex = None
|
||||||
for i,inp in enumerate(geometryoutput.inputs):
|
for i, inp in enumerate(geometryoutput.inputs):
|
||||||
if inp.type == socket_type:
|
if inp.type == socket_type:
|
||||||
geometryoutindex = i
|
geometryoutindex = i
|
||||||
break
|
break
|
||||||
@ -697,7 +707,8 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
link_end = output_socket
|
link_end = output_socket
|
||||||
while tree.nodes.active != active:
|
while tree.nodes.active != active:
|
||||||
node = tree.nodes.active
|
node = tree.nodes.active
|
||||||
index = self.ensure_viewer_socket(node,'NodeSocketGeometry', connect_socket=active.outputs[out_i] if node.node_tree.nodes.active == active else None)
|
index = self.ensure_viewer_socket(
|
||||||
|
node, 'NodeSocketGeometry', connect_socket=active.outputs[out_i] if node.node_tree.nodes.active == active else None)
|
||||||
link_start = node.outputs[index]
|
link_start = node.outputs[index]
|
||||||
node_socket = node.node_tree.outputs[index]
|
node_socket = node.node_tree.outputs[index]
|
||||||
if node_socket in delete_sockets:
|
if node_socket in delete_sockets:
|
||||||
@ -718,7 +729,6 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
force_update(context)
|
force_update(context)
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
# What follows is code for the shader editor
|
# What follows is code for the shader editor
|
||||||
output_types = [x.nodetype for x in
|
output_types = [x.nodetype for x in
|
||||||
get_nodes_from_category('Output', context)]
|
get_nodes_from_category('Output', context)]
|
||||||
@ -734,7 +744,7 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
materialout = None # placeholder node
|
materialout = None # placeholder node
|
||||||
delete_sockets = []
|
delete_sockets = []
|
||||||
|
|
||||||
#scan through all nodes in tree including nodes inside of groups to find viewer sockets
|
# scan through all nodes in tree including nodes inside of groups to find viewer sockets
|
||||||
self.scan_nodes(base_node_tree, delete_sockets)
|
self.scan_nodes(base_node_tree, delete_sockets)
|
||||||
|
|
||||||
materialout = self.get_shader_output_node(base_node_tree)
|
materialout = self.get_shader_output_node(base_node_tree)
|
||||||
@ -773,7 +783,8 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
link_end = output_socket
|
link_end = output_socket
|
||||||
while tree.nodes.active != active:
|
while tree.nodes.active != active:
|
||||||
node = tree.nodes.active
|
node = tree.nodes.active
|
||||||
index = self.ensure_viewer_socket(node, socket_type, connect_socket=active.outputs[out_i] if node.node_tree.nodes.active == active else None)
|
index = self.ensure_viewer_socket(
|
||||||
|
node, socket_type, connect_socket=active.outputs[out_i] if node.node_tree.nodes.active == active else None)
|
||||||
link_start = node.outputs[index]
|
link_start = node.outputs[index]
|
||||||
node_socket = node.node_tree.outputs[index]
|
node_socket = node.node_tree.outputs[index]
|
||||||
if node_socket in delete_sockets:
|
if node_socket in delete_sockets:
|
||||||
@ -836,7 +847,7 @@ class NWFrameSelected(Operator, NWBase):
|
|||||||
nodes, links = get_nodes_links(context)
|
nodes, links = get_nodes_links(context)
|
||||||
selected = []
|
selected = []
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
if node.select == True:
|
if node.select:
|
||||||
selected.append(node)
|
selected.append(node)
|
||||||
|
|
||||||
bpy.ops.node.add_node(type='NodeFrame')
|
bpy.ops.node.add_node(type='NodeFrame')
|
||||||
@ -902,7 +913,7 @@ class NWSwitchNodeType(Operator, NWBase):
|
|||||||
|
|
||||||
to_type: StringProperty(
|
to_type: StringProperty(
|
||||||
name="Switch to type",
|
name="Switch to type",
|
||||||
default = '',
|
default='',
|
||||||
)
|
)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
@ -970,8 +981,10 @@ class NWSwitchNodeType(Operator, NWBase):
|
|||||||
for the_type in types_order_one:
|
for the_type in types_order_one:
|
||||||
if socket.type == the_type:
|
if socket.type == the_type:
|
||||||
# create values for sockets['INPUTS'][the_type] and sockets['OUTPUTS'][the_type]
|
# create values for sockets['INPUTS'][the_type] and sockets['OUTPUTS'][the_type]
|
||||||
# entry structure: (index_in_type, socket_index, socket_name, socket_default_value, socket_links)
|
# entry structure: (index_in_type, socket_index, socket_name,
|
||||||
sockets[in_out_name][the_type].append((len(sockets[in_out_name][the_type]), i, the_name, dval, socket_links))
|
# socket_default_value, socket_links)
|
||||||
|
sockets[in_out_name][the_type].append(
|
||||||
|
(len(sockets[in_out_name][the_type]), i, the_name, dval, socket_links))
|
||||||
# Check which of the types in inputs/outputs is considered to be "main".
|
# Check which of the types in inputs/outputs is considered to be "main".
|
||||||
# Set values of sockets['INPUTS']['MAIN'] and sockets['OUTPUTS']['MAIN']
|
# Set values of sockets['INPUTS']['MAIN'] and sockets['OUTPUTS']['MAIN']
|
||||||
for type_check in types_order_one:
|
for type_check in types_order_one:
|
||||||
@ -1090,7 +1103,7 @@ class NWMergeNodes(Operator, NWBase):
|
|||||||
mode: EnumProperty(
|
mode: EnumProperty(
|
||||||
name="mode",
|
name="mode",
|
||||||
description="All possible blend types, boolean operations and math operations",
|
description="All possible blend types, boolean operations and math operations",
|
||||||
items= blend_types + [op for op in geo_combine_operations if op not in blend_types] + [op for op in operations if op not in blend_types],
|
items=blend_types + [op for op in geo_combine_operations if op not in blend_types] + [op for op in operations if op not in blend_types],
|
||||||
)
|
)
|
||||||
merge_type: EnumProperty(
|
merge_type: EnumProperty(
|
||||||
name="merge type",
|
name="merge type",
|
||||||
@ -1112,7 +1125,7 @@ class NWMergeNodes(Operator, NWBase):
|
|||||||
# in selected_nodes, it returns False. The depth is used to prevent
|
# in selected_nodes, it returns False. The depth is used to prevent
|
||||||
# getting stuck in a loop because of an already present cycle.
|
# getting stuck in a loop because of an already present cycle.
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def link_creates_cycle(link, selected_nodes, depth=0)->bool:
|
def link_creates_cycle(link, selected_nodes, depth=0) -> bool:
|
||||||
if depth > 255:
|
if depth > 255:
|
||||||
# We're stuck in a cycle, but that cycle was already present,
|
# We're stuck in a cycle, but that cycle was already present,
|
||||||
# so we return False.
|
# so we return False.
|
||||||
@ -1126,7 +1139,7 @@ class NWMergeNodes(Operator, NWBase):
|
|||||||
for output in node.outputs:
|
for output in node.outputs:
|
||||||
if output.is_linked:
|
if output.is_linked:
|
||||||
for olink in output.links:
|
for olink in output.links:
|
||||||
if NWMergeNodes.link_creates_cycle(olink, selected_nodes, depth+1):
|
if NWMergeNodes.link_creates_cycle(olink, selected_nodes, depth + 1):
|
||||||
return True
|
return True
|
||||||
# None of the outputs found a node in selected_nodes, so there is no cycle.
|
# None of the outputs found a node in selected_nodes, so there is no cycle.
|
||||||
return False
|
return False
|
||||||
@ -1136,14 +1149,14 @@ class NWMergeNodes(Operator, NWBase):
|
|||||||
# be connected. The last one is assumed to be a multi input socket.
|
# be connected. The last one is assumed to be a multi input socket.
|
||||||
# For convenience the node is returned.
|
# For convenience the node is returned.
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def merge_with_multi_input(nodes_list, merge_position,do_hide, loc_x, links, nodes, node_name, socket_indices):
|
def merge_with_multi_input(nodes_list, merge_position, do_hide, loc_x, links, nodes, node_name, socket_indices):
|
||||||
# The y-location of the last node
|
# The y-location of the last node
|
||||||
loc_y = nodes_list[-1][2]
|
loc_y = nodes_list[-1][2]
|
||||||
if merge_position == 'CENTER':
|
if merge_position == 'CENTER':
|
||||||
# Average the y-location
|
# Average the y-location
|
||||||
for i in range(len(nodes_list)-1):
|
for i in range(len(nodes_list) - 1):
|
||||||
loc_y += nodes_list[i][2]
|
loc_y += nodes_list[i][2]
|
||||||
loc_y = loc_y/len(nodes_list)
|
loc_y = loc_y / len(nodes_list)
|
||||||
new_node = nodes.new(node_name)
|
new_node = nodes.new(node_name)
|
||||||
new_node.hide = do_hide
|
new_node.hide = do_hide
|
||||||
new_node.location.x = loc_x
|
new_node.location.x = loc_x
|
||||||
@ -1151,12 +1164,14 @@ class NWMergeNodes(Operator, NWBase):
|
|||||||
selected_nodes = [nodes[node_info[0]] for node_info in nodes_list]
|
selected_nodes = [nodes[node_info[0]] for node_info in nodes_list]
|
||||||
prev_links = []
|
prev_links = []
|
||||||
outputs_for_multi_input = []
|
outputs_for_multi_input = []
|
||||||
for i,node in enumerate(selected_nodes):
|
for i, node in enumerate(selected_nodes):
|
||||||
node.select = False
|
node.select = False
|
||||||
# Search for the first node which had output links that do not create
|
# Search for the first node which had output links that do not create
|
||||||
# a cycle, which we can then reconnect afterwards.
|
# a cycle, which we can then reconnect afterwards.
|
||||||
if prev_links == [] and node.outputs[0].is_linked:
|
if prev_links == [] and node.outputs[0].is_linked:
|
||||||
prev_links = [link for link in node.outputs[0].links if not NWMergeNodes.link_creates_cycle(link, selected_nodes)]
|
prev_links = [
|
||||||
|
link for link in node.outputs[0].links if not NWMergeNodes.link_creates_cycle(
|
||||||
|
link, selected_nodes)]
|
||||||
# Get the index of the socket, the last one is a multi input, and is thus used repeatedly
|
# Get the index of the socket, the last one is a multi input, and is thus used repeatedly
|
||||||
# To get the placement to look right we need to reverse the order in which we connect the
|
# To get the placement to look right we need to reverse the order in which we connect the
|
||||||
# outputs to the multi input socket.
|
# outputs to the multi input socket.
|
||||||
@ -1212,9 +1227,9 @@ class NWMergeNodes(Operator, NWBase):
|
|||||||
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]
|
||||||
|
|
||||||
@ -1268,7 +1283,14 @@ class NWMergeNodes(Operator, NWBase):
|
|||||||
if selected_mix and selected_math and merge_type == 'AUTO':
|
if selected_mix and selected_math and merge_type == 'AUTO':
|
||||||
selected_mix += selected_math
|
selected_mix += selected_math
|
||||||
selected_math = []
|
selected_math = []
|
||||||
for nodes_list in [selected_mix, selected_shader, selected_geometry, selected_math, selected_vector, selected_z, selected_alphaover]:
|
for nodes_list in [
|
||||||
|
selected_mix,
|
||||||
|
selected_shader,
|
||||||
|
selected_geometry,
|
||||||
|
selected_math,
|
||||||
|
selected_vector,
|
||||||
|
selected_z,
|
||||||
|
selected_alphaover]:
|
||||||
if not nodes_list:
|
if not nodes_list:
|
||||||
continue
|
continue
|
||||||
count_before = len(nodes)
|
count_before = len(nodes)
|
||||||
@ -1285,8 +1307,9 @@ class NWMergeNodes(Operator, NWBase):
|
|||||||
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)
|
# 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
|
loc_y = ((nodes_list[len(nodes_list) - 1][2]) + (nodes_list[len(nodes_list) - 2][2])) / 2
|
||||||
|
if nodes_list[len(nodes_list) - 1][-1]: # if last node is hidden, mix should be shifted up a bit
|
||||||
if do_hide:
|
if do_hide:
|
||||||
loc_y += 40
|
loc_y += 40
|
||||||
else:
|
else:
|
||||||
@ -1356,11 +1379,13 @@ class NWMergeNodes(Operator, NWBase):
|
|||||||
elif nodes_list == selected_geometry:
|
elif nodes_list == selected_geometry:
|
||||||
if mode in ('JOIN', 'MIX'):
|
if mode in ('JOIN', 'MIX'):
|
||||||
add_type = node_type + 'JoinGeometry'
|
add_type = node_type + 'JoinGeometry'
|
||||||
add = self.merge_with_multi_input(nodes_list, merge_position, do_hide, loc_x, links, nodes, add_type,[0])
|
add = self.merge_with_multi_input(
|
||||||
|
nodes_list, merge_position, do_hide, loc_x, links, nodes, add_type, [0])
|
||||||
else:
|
else:
|
||||||
add_type = node_type + 'MeshBoolean'
|
add_type = node_type + 'MeshBoolean'
|
||||||
indices = [0,1] if mode == 'DIFFERENCE' else [1]
|
indices = [0, 1] if mode == 'DIFFERENCE' else [1]
|
||||||
add = self.merge_with_multi_input(nodes_list, merge_position, do_hide, loc_x, links, nodes, add_type,indices)
|
add = self.merge_with_multi_input(
|
||||||
|
nodes_list, merge_position, do_hide, loc_x, links, nodes, add_type, indices)
|
||||||
add.operation = mode
|
add.operation = mode
|
||||||
was_multi = True
|
was_multi = True
|
||||||
break
|
break
|
||||||
@ -1406,7 +1431,8 @@ class NWMergeNodes(Operator, NWBase):
|
|||||||
# "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.
|
||||||
@ -1484,12 +1510,12 @@ class NWBatchChangeNodes(Operator, NWBase):
|
|||||||
operation = self.operation
|
operation = self.operation
|
||||||
for node in context.selected_nodes:
|
for node in context.selected_nodes:
|
||||||
if node.type == 'MIX_RGB' or (node.bl_idname == 'ShaderNodeMix' and node.data_type == 'RGBA'):
|
if node.type == 'MIX_RGB' or (node.bl_idname == 'ShaderNodeMix' and node.data_type == 'RGBA'):
|
||||||
if not blend_type in [nav[0] for nav in navs]:
|
if blend_type not in [nav[0] for nav in navs]:
|
||||||
node.blend_type = blend_type
|
node.blend_type = blend_type
|
||||||
else:
|
else:
|
||||||
if blend_type == 'NEXT':
|
if blend_type == 'NEXT':
|
||||||
index = [i for i, entry in enumerate(blend_types) if node.blend_type in entry][0]
|
index = [i for i, entry in enumerate(blend_types) if node.blend_type in entry][0]
|
||||||
#index = blend_types.index(node.blend_type)
|
# index = blend_types.index(node.blend_type)
|
||||||
if index == len(blend_types) - 1:
|
if index == len(blend_types) - 1:
|
||||||
node.blend_type = blend_types[0][0]
|
node.blend_type = blend_types[0][0]
|
||||||
else:
|
else:
|
||||||
@ -1503,12 +1529,12 @@ class NWBatchChangeNodes(Operator, NWBase):
|
|||||||
node.blend_type = blend_types[index - 1][0]
|
node.blend_type = blend_types[index - 1][0]
|
||||||
|
|
||||||
if node.type == 'MATH' or node.bl_idname == 'ShaderNodeMath':
|
if node.type == 'MATH' or node.bl_idname == 'ShaderNodeMath':
|
||||||
if not operation in [nav[0] for nav in navs]:
|
if operation not in [nav[0] for nav in navs]:
|
||||||
node.operation = operation
|
node.operation = operation
|
||||||
else:
|
else:
|
||||||
if operation == 'NEXT':
|
if operation == 'NEXT':
|
||||||
index = [i for i, entry in enumerate(operations) if node.operation in entry][0]
|
index = [i for i, entry in enumerate(operations) if node.operation in entry][0]
|
||||||
#index = operations.index(node.operation)
|
# index = operations.index(node.operation)
|
||||||
if index == len(operations) - 1:
|
if index == len(operations) - 1:
|
||||||
node.operation = operations[0][0]
|
node.operation = operations[0][0]
|
||||||
else:
|
else:
|
||||||
@ -1516,7 +1542,7 @@ class NWBatchChangeNodes(Operator, NWBase):
|
|||||||
|
|
||||||
if operation == 'PREV':
|
if operation == 'PREV':
|
||||||
index = [i for i, entry in enumerate(operations) if node.operation in entry][0]
|
index = [i for i, entry in enumerate(operations) if node.operation in entry][0]
|
||||||
#index = operations.index(node.operation)
|
# index = operations.index(node.operation)
|
||||||
if index == 0:
|
if index == 0:
|
||||||
node.operation = operations[len(operations) - 1][0]
|
node.operation = operations[len(operations) - 1][0]
|
||||||
else:
|
else:
|
||||||
@ -1599,11 +1625,15 @@ class NWCopySettings(Operator, NWBase):
|
|||||||
# Report nodes that are not valid
|
# Report nodes that are not valid
|
||||||
valid_node_names = [n.name for n in valid_nodes]
|
valid_node_names = [n.name for n in valid_nodes]
|
||||||
not_valid_names = list(set(selected_node_names) - set(valid_node_names))
|
not_valid_names = list(set(selected_node_names) - set(valid_node_names))
|
||||||
self.report({'INFO'}, "Ignored {} (not of the same type as {})".format(", ".join(not_valid_names), node_active.name))
|
self.report(
|
||||||
|
{'INFO'},
|
||||||
|
"Ignored {} (not of the same type as {})".format(
|
||||||
|
", ".join(not_valid_names),
|
||||||
|
node_active.name))
|
||||||
|
|
||||||
# Reference original
|
# Reference original
|
||||||
orig = node_active
|
orig = node_active
|
||||||
#node_selected_names = [n.name for n in node_selected]
|
# node_selected_names = [n.name for n in node_selected]
|
||||||
|
|
||||||
# Output list
|
# Output list
|
||||||
success_names = []
|
success_names = []
|
||||||
@ -1664,7 +1694,11 @@ class NWCopySettings(Operator, NWBase):
|
|||||||
|
|
||||||
orig.select = True
|
orig.select = True
|
||||||
node_tree.nodes.active = orig
|
node_tree.nodes.active = orig
|
||||||
self.report({'INFO'}, "Successfully copied attributes from {} to: {}".format(orig.name, ", ".join(success_names)))
|
self.report(
|
||||||
|
{'INFO'},
|
||||||
|
"Successfully copied attributes from {} to: {}".format(
|
||||||
|
orig.name,
|
||||||
|
", ".join(success_names)))
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
@ -1772,7 +1806,10 @@ class NWAddTextureSetup(Operator, NWBase):
|
|||||||
bl_description = "Add Texture Node Setup to Selected Shaders"
|
bl_description = "Add Texture Node Setup to Selected Shaders"
|
||||||
bl_options = {'REGISTER', 'UNDO'}
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
add_mapping: BoolProperty(name="Add Mapping Nodes", description="Create coordinate and mapping nodes for the texture (ignored for selected texture nodes)", default=True)
|
add_mapping: BoolProperty(
|
||||||
|
name="Add Mapping Nodes",
|
||||||
|
description="Create coordinate and mapping nodes for the texture (ignored for selected texture nodes)",
|
||||||
|
default=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
@ -1913,23 +1950,23 @@ class NWAddPrincipledSetup(Operator, NWBase, ImportHelper):
|
|||||||
gloss_abbr = tags.gloss.split(' ')
|
gloss_abbr = tags.gloss.split(' ')
|
||||||
rough_abbr = tags.rough.split(' ')
|
rough_abbr = tags.rough.split(' ')
|
||||||
socketnames = [
|
socketnames = [
|
||||||
['Displacement', tags.displacement.split(' '), None],
|
['Displacement', tags.displacement.split(' '), None],
|
||||||
['Base Color', tags.base_color.split(' '), None],
|
['Base Color', tags.base_color.split(' '), None],
|
||||||
['Subsurface Color', tags.sss_color.split(' '), None],
|
['Subsurface Color', tags.sss_color.split(' '), None],
|
||||||
['Metallic', tags.metallic.split(' '), None],
|
['Metallic', tags.metallic.split(' '), None],
|
||||||
['Specular', tags.specular.split(' '), None],
|
['Specular', tags.specular.split(' '), None],
|
||||||
['Roughness', rough_abbr + gloss_abbr, None],
|
['Roughness', rough_abbr + gloss_abbr, None],
|
||||||
['Normal', normal_abbr + bump_abbr, None],
|
['Normal', normal_abbr + bump_abbr, None],
|
||||||
['Transmission', tags.transmission.split(' '), None],
|
['Transmission', tags.transmission.split(' '), None],
|
||||||
['Emission', tags.emission.split(' '), None],
|
['Emission', tags.emission.split(' '), None],
|
||||||
['Alpha', tags.alpha.split(' '), None],
|
['Alpha', tags.alpha.split(' '), None],
|
||||||
['Ambient Occlusion', tags.ambient_occlusion.split(' '), None],
|
['Ambient Occlusion', tags.ambient_occlusion.split(' '), None],
|
||||||
]
|
]
|
||||||
|
|
||||||
match_files_to_socket_names(self.files, socketnames)
|
match_files_to_socket_names(self.files, socketnames)
|
||||||
# Remove socketnames without found files
|
# Remove socketnames without found files
|
||||||
socketnames = [s for s in socketnames if s[2]
|
socketnames = [s for s in socketnames if s[2]
|
||||||
and path.exists(self.directory+s[2])]
|
and path.exists(self.directory + s[2])]
|
||||||
if not socketnames:
|
if not socketnames:
|
||||||
self.report({'INFO'}, 'No matching images found')
|
self.report({'INFO'}, 'No matching images found')
|
||||||
print('No matching images found')
|
print('No matching images found')
|
||||||
@ -2076,7 +2113,8 @@ class NWAddPrincipledSetup(Operator, NWBase, ImportHelper):
|
|||||||
# If more than one texture add reroute node in between
|
# If more than one texture add reroute node in between
|
||||||
reroute = nodes.new(type='NodeReroute')
|
reroute = nodes.new(type='NodeReroute')
|
||||||
texture_nodes.append(reroute)
|
texture_nodes.append(reroute)
|
||||||
tex_coords = Vector((texture_nodes[0].location.x, sum(n.location.y for n in texture_nodes)/len(texture_nodes)))
|
tex_coords = Vector((texture_nodes[0].location.x,
|
||||||
|
sum(n.location.y for n in texture_nodes) / len(texture_nodes)))
|
||||||
reroute.location = tex_coords + Vector((-50, -120))
|
reroute.location = tex_coords + Vector((-50, -120))
|
||||||
for texture_node in texture_nodes:
|
for texture_node in texture_nodes:
|
||||||
link = links.new(texture_node.inputs[0], reroute.outputs[0])
|
link = links.new(texture_node.inputs[0], reroute.outputs[0])
|
||||||
@ -2316,7 +2354,8 @@ class NWAlignNodes(Operator, NWBase):
|
|||||||
active_loc = copy(nodes.active.location) # make a copy, not a reference
|
active_loc = copy(nodes.active.location) # make a copy, not a reference
|
||||||
|
|
||||||
# Check if nodes should be laid out horizontally or vertically
|
# Check if nodes should be laid out horizontally or vertically
|
||||||
x_locs = [n.location.x + (n.dimensions.x / 2) for n in selection] # use dimension to get center of node, not corner
|
# use dimension to get center of node, not corner
|
||||||
|
x_locs = [n.location.x + (n.dimensions.x / 2) for n in selection]
|
||||||
y_locs = [n.location.y - (n.dimensions.y / 2) for n in selection]
|
y_locs = [n.location.y - (n.dimensions.y / 2) for n in selection]
|
||||||
x_range = max(x_locs) - min(x_locs)
|
x_range = max(x_locs) - min(x_locs)
|
||||||
y_range = max(y_locs) - min(y_locs)
|
y_range = max(y_locs) - min(y_locs)
|
||||||
@ -2351,7 +2390,8 @@ class NWAlignNodes(Operator, NWBase):
|
|||||||
for node in selection:
|
for node in selection:
|
||||||
node.location += active_loc_diff
|
node.location += active_loc_diff
|
||||||
else: # Position nodes centered around where they used to be
|
else: # Position nodes centered around where they used to be
|
||||||
locs = ([n.location.x + (n.dimensions.x / 2) for n in selection]) if horizontal else ([n.location.y - (n.dimensions.y / 2) for n in selection])
|
locs = ([n.location.x + (n.dimensions.x / 2) for n in selection]
|
||||||
|
) if horizontal else ([n.location.y - (n.dimensions.y / 2) for n in selection])
|
||||||
new_mid = (max(locs) + min(locs)) / 2
|
new_mid = (max(locs) + min(locs)) / 2
|
||||||
for node in selection:
|
for node in selection:
|
||||||
if horizontal:
|
if horizontal:
|
||||||
@ -2437,8 +2477,8 @@ class NWLinkToOutputNode(Operator):
|
|||||||
active = nodes.active
|
active = nodes.active
|
||||||
output_index = None
|
output_index = None
|
||||||
tree_type = context.space_data.tree_type
|
tree_type = context.space_data.tree_type
|
||||||
shader_outputs = {'OBJECT': 'ShaderNodeOutputMaterial',
|
shader_outputs = {'OBJECT': 'ShaderNodeOutputMaterial',
|
||||||
'WORLD': 'ShaderNodeOutputWorld',
|
'WORLD': 'ShaderNodeOutputWorld',
|
||||||
'LINESTYLE': 'ShaderNodeOutputLineStyle'}
|
'LINESTYLE': 'ShaderNodeOutputLineStyle'}
|
||||||
output_type = {
|
output_type = {
|
||||||
'ShaderNodeTree': shader_outputs[context.space_data.shader_type],
|
'ShaderNodeTree': shader_outputs[context.space_data.shader_type],
|
||||||
@ -2579,24 +2619,23 @@ class NWAddSequence(Operator, NWBase, ImportHelper):
|
|||||||
if not files[0].name and not filename:
|
if not files[0].name and not filename:
|
||||||
self.report({'ERROR'}, "No file chosen")
|
self.report({'ERROR'}, "No file chosen")
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
elif files[0].name and (not filename or not path.exists(directory+filename)):
|
elif files[0].name and (not filename or not path.exists(directory + filename)):
|
||||||
# User has selected multiple files without an active one, or the active one is non-existent
|
# User has selected multiple files without an active one, or the active one is non-existent
|
||||||
filename = files[0].name
|
filename = files[0].name
|
||||||
|
|
||||||
if not path.exists(directory+filename):
|
if not path.exists(directory + filename):
|
||||||
self.report({'ERROR'}, filename+" does not exist!")
|
self.report({'ERROR'}, filename + " does not exist!")
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
without_ext = '.'.join(filename.split('.')[:-1])
|
without_ext = '.'.join(filename.split('.')[:-1])
|
||||||
|
|
||||||
# if last digit isn't a number, it's not a sequence
|
# if last digit isn't a number, it's not a sequence
|
||||||
if not without_ext[-1].isdigit():
|
if not without_ext[-1].isdigit():
|
||||||
self.report({'ERROR'}, filename+" does not seem to be part of a sequence")
|
self.report({'ERROR'}, filename + " does not seem to be part of a sequence")
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
|
||||||
extension = filename.split('.')[-1]
|
extension = filename.split('.')[-1]
|
||||||
reverse = without_ext[::-1] # reverse string
|
reverse = without_ext[::-1] # reverse string
|
||||||
|
|
||||||
count_numbers = 0
|
count_numbers = 0
|
||||||
for char in reverse:
|
for char in reverse:
|
||||||
@ -2605,9 +2644,9 @@ class NWAddSequence(Operator, NWBase, ImportHelper):
|
|||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
without_num = without_ext[:count_numbers*-1]
|
without_num = without_ext[:count_numbers * -1]
|
||||||
|
|
||||||
files = sorted(glob(directory + without_num + "[0-9]"*count_numbers + "." + extension))
|
files = sorted(glob(directory + without_num + "[0-9]" * count_numbers + "." + extension))
|
||||||
|
|
||||||
num_frames = len(files)
|
num_frames = len(files)
|
||||||
|
|
||||||
@ -2619,18 +2658,18 @@ class NWAddSequence(Operator, NWBase, ImportHelper):
|
|||||||
for node in nodes:
|
for node in nodes:
|
||||||
node.select = False
|
node.select = False
|
||||||
yloc += node_mid_pt(node, 'y')
|
yloc += node_mid_pt(node, 'y')
|
||||||
yloc = yloc/len(nodes)
|
yloc = yloc / len(nodes)
|
||||||
else:
|
else:
|
||||||
xloc = 0
|
xloc = 0
|
||||||
yloc = 0
|
yloc = 0
|
||||||
|
|
||||||
name_with_hashes = without_num + "#"*count_numbers + '.' + extension
|
name_with_hashes = without_num + "#" * count_numbers + '.' + extension
|
||||||
|
|
||||||
bpy.ops.node.add_node('INVOKE_DEFAULT', use_transform=True, type=node_type)
|
bpy.ops.node.add_node('INVOKE_DEFAULT', use_transform=True, type=node_type)
|
||||||
node = nodes.active
|
node = nodes.active
|
||||||
node.label = name_with_hashes
|
node.label = name_with_hashes
|
||||||
|
|
||||||
filepath = directory+(without_ext+'.'+extension)
|
filepath = directory + (without_ext + '.' + extension)
|
||||||
if self.relative_path:
|
if self.relative_path:
|
||||||
if bpy.data.filepath:
|
if bpy.data.filepath:
|
||||||
try:
|
try:
|
||||||
@ -2643,7 +2682,8 @@ class NWAddSequence(Operator, NWBase, ImportHelper):
|
|||||||
img.name = name_with_hashes
|
img.name = name_with_hashes
|
||||||
node.image = img
|
node.image = img
|
||||||
image_user = node.image_user if tree.type == 'SHADER' else node
|
image_user = node.image_user if tree.type == 'SHADER' else node
|
||||||
image_user.frame_offset = int(files[0][len(without_num)+len(directory):-1*(len(extension)+1)]) - 1 # separate the number from the file name of the first file
|
# separate the number from the file name of the first file
|
||||||
|
image_user.frame_offset = int(files[0][len(without_num) + len(directory):-1 * (len(extension) + 1)]) - 1
|
||||||
image_user.frame_duration = num_frames
|
image_user.frame_duration = num_frames
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
@ -2665,7 +2705,7 @@ class NWAddMultipleImages(Operator, NWBase, ImportHelper):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
nodes, links = get_nodes_links(context)
|
nodes, links = get_nodes_links(context)
|
||||||
|
|
||||||
xloc, yloc = context.region.view2d.region_to_view(context.area.width/2, context.area.height/2)
|
xloc, yloc = context.region.view2d.region_to_view(context.area.width / 2, context.area.height / 2)
|
||||||
|
|
||||||
if context.space_data.node_tree.type == 'SHADER':
|
if context.space_data.node_tree.type == 'SHADER':
|
||||||
node_type = "ShaderNodeTexImage"
|
node_type = "ShaderNodeTexImage"
|
||||||
@ -2688,7 +2728,7 @@ class NWAddMultipleImages(Operator, NWBase, ImportHelper):
|
|||||||
node.location.y = yloc
|
node.location.y = yloc
|
||||||
yloc -= 40
|
yloc -= 40
|
||||||
|
|
||||||
img = bpy.data.images.load(self.directory+fname)
|
img = bpy.data.images.load(self.directory + fname)
|
||||||
node.image = img
|
node.image = img
|
||||||
|
|
||||||
# shift new nodes up to center of tree
|
# shift new nodes up to center of tree
|
||||||
@ -2696,7 +2736,7 @@ class NWAddMultipleImages(Operator, NWBase, ImportHelper):
|
|||||||
for node in nodes:
|
for node in nodes:
|
||||||
if node in new_nodes:
|
if node in new_nodes:
|
||||||
node.select = True
|
node.select = True
|
||||||
node.location.y += (list_size/2)
|
node.location.y += (list_size / 2)
|
||||||
else:
|
else:
|
||||||
node.select = False
|
node.select = False
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
@ -2720,7 +2760,7 @@ class NWViewerFocus(bpy.types.Operator):
|
|||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
render = context.scene.render
|
render = context.scene.render
|
||||||
space = context.space_data
|
space = context.space_data
|
||||||
percent = render.resolution_percentage*0.01
|
percent = render.resolution_percentage * 0.01
|
||||||
|
|
||||||
nodes, links = get_nodes_links(context)
|
nodes, links = get_nodes_links(context)
|
||||||
viewers = [n for n in nodes if n.type == 'VIEWER']
|
viewers = [n for n in nodes if n.type == 'VIEWER']
|
||||||
@ -2730,11 +2770,11 @@ class NWViewerFocus(bpy.types.Operator):
|
|||||||
mlocy = event.mouse_region_y
|
mlocy = event.mouse_region_y
|
||||||
select_node = bpy.ops.node.select(location=(mlocx, mlocy), extend=False)
|
select_node = bpy.ops.node.select(location=(mlocx, mlocy), extend=False)
|
||||||
|
|
||||||
if not 'FINISHED' in select_node: # only run if we're not clicking on a node
|
if 'FINISHED' not in select_node: # only run if we're not clicking on a node
|
||||||
region_x = context.region.width
|
region_x = context.region.width
|
||||||
region_y = context.region.height
|
region_y = context.region.height
|
||||||
|
|
||||||
region_center_x = context.region.width / 2
|
region_center_x = context.region.width / 2
|
||||||
region_center_y = context.region.height / 2
|
region_center_y = context.region.height / 2
|
||||||
|
|
||||||
bd_x = render.resolution_x * percent * space.backdrop_zoom
|
bd_x = render.resolution_x * percent * space.backdrop_zoom
|
||||||
@ -2764,21 +2804,21 @@ class NWSaveViewer(bpy.types.Operator, ExportHelper):
|
|||||||
bl_label = "Save This Image"
|
bl_label = "Save This Image"
|
||||||
filepath: StringProperty(subtype="FILE_PATH")
|
filepath: StringProperty(subtype="FILE_PATH")
|
||||||
filename_ext: EnumProperty(
|
filename_ext: EnumProperty(
|
||||||
name="Format",
|
name="Format",
|
||||||
description="Choose the file format to save to",
|
description="Choose the file format to save to",
|
||||||
items=(('.bmp', "BMP", ""),
|
items=(('.bmp', "BMP", ""),
|
||||||
('.rgb', 'IRIS', ""),
|
('.rgb', 'IRIS', ""),
|
||||||
('.png', 'PNG', ""),
|
('.png', 'PNG', ""),
|
||||||
('.jpg', 'JPEG', ""),
|
('.jpg', 'JPEG', ""),
|
||||||
('.jp2', 'JPEG2000', ""),
|
('.jp2', 'JPEG2000', ""),
|
||||||
('.tga', 'TARGA', ""),
|
('.tga', 'TARGA', ""),
|
||||||
('.cin', 'CINEON', ""),
|
('.cin', 'CINEON', ""),
|
||||||
('.dpx', 'DPX', ""),
|
('.dpx', 'DPX', ""),
|
||||||
('.exr', 'OPEN_EXR', ""),
|
('.exr', 'OPEN_EXR', ""),
|
||||||
('.hdr', 'HDR', ""),
|
('.hdr', 'HDR', ""),
|
||||||
('.tif', 'TIFF', "")),
|
('.tif', 'TIFF', "")),
|
||||||
default='.png',
|
default='.png',
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
@ -2794,19 +2834,19 @@ class NWSaveViewer(bpy.types.Operator, ExportHelper):
|
|||||||
fp = self.filepath
|
fp = self.filepath
|
||||||
if fp:
|
if fp:
|
||||||
formats = {
|
formats = {
|
||||||
'.bmp': 'BMP',
|
'.bmp': 'BMP',
|
||||||
'.rgb': 'IRIS',
|
'.rgb': 'IRIS',
|
||||||
'.png': 'PNG',
|
'.png': 'PNG',
|
||||||
'.jpg': 'JPEG',
|
'.jpg': 'JPEG',
|
||||||
'.jpeg': 'JPEG',
|
'.jpeg': 'JPEG',
|
||||||
'.jp2': 'JPEG2000',
|
'.jp2': 'JPEG2000',
|
||||||
'.tga': 'TARGA',
|
'.tga': 'TARGA',
|
||||||
'.cin': 'CINEON',
|
'.cin': 'CINEON',
|
||||||
'.dpx': 'DPX',
|
'.dpx': 'DPX',
|
||||||
'.exr': 'OPEN_EXR',
|
'.exr': 'OPEN_EXR',
|
||||||
'.hdr': 'HDR',
|
'.hdr': 'HDR',
|
||||||
'.tiff': 'TIFF',
|
'.tiff': 'TIFF',
|
||||||
'.tif': 'TIFF'}
|
'.tif': 'TIFF'}
|
||||||
basename, ext = path.splitext(fp)
|
basename, ext = path.splitext(fp)
|
||||||
old_render_format = context.scene.render.image_settings.file_format
|
old_render_format = context.scene.render.image_settings.file_format
|
||||||
context.scene.render.image_settings.file_format = formats[self.filename_ext]
|
context.scene.render.image_settings.file_format = formats[self.filename_ext]
|
||||||
@ -2832,7 +2872,7 @@ class NWResetNodes(bpy.types.Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
node_active = context.active_node
|
node_active = context.active_node
|
||||||
node_selected = context.selected_nodes
|
node_selected = context.selected_nodes
|
||||||
node_ignore = ["FRAME","REROUTE", "GROUP"]
|
node_ignore = ["FRAME", "REROUTE", "GROUP"]
|
||||||
|
|
||||||
# Check if one node is selected at least
|
# Check if one node is selected at least
|
||||||
if not (len(node_selected) > 0):
|
if not (len(node_selected) > 0):
|
||||||
|
@ -114,7 +114,11 @@ class NWNodeWrangler(bpy.types.AddonPreferences):
|
|||||||
|
|
||||||
box = layout.box()
|
box = layout.box()
|
||||||
col = box.column(align=True)
|
col = box.column(align=True)
|
||||||
col.prop(self, "show_principled_lists", text='Edit tags for auto texture detection in Principled BSDF setup', toggle=True)
|
col.prop(
|
||||||
|
self,
|
||||||
|
"show_principled_lists",
|
||||||
|
text='Edit tags for auto texture detection in Principled BSDF setup',
|
||||||
|
toggle=True)
|
||||||
if self.show_principled_lists:
|
if self.show_principled_lists:
|
||||||
tags = self.principled_tags
|
tags = self.principled_tags
|
||||||
|
|
||||||
@ -157,6 +161,7 @@ class NWNodeWrangler(bpy.types.AddonPreferences):
|
|||||||
keystr = "Ctrl " + keystr
|
keystr = "Ctrl " + keystr
|
||||||
row.label(text=keystr)
|
row.label(text=keystr)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# REGISTER/UNREGISTER CLASSES AND KEYMAP ITEMS
|
# REGISTER/UNREGISTER CLASSES AND KEYMAP ITEMS
|
||||||
#
|
#
|
||||||
@ -285,13 +290,20 @@ kmi_defs = (
|
|||||||
(operators.NWLinkActiveToSelected.bl_idname, 'SEMI_COLON', 'PRESS', False, True, False,
|
(operators.NWLinkActiveToSelected.bl_idname, 'SEMI_COLON', 'PRESS', False, True, False,
|
||||||
(('replace', True), ('use_node_name', False), ('use_outputs_names', True),), "Link active to selected (Replace links, output names)"),
|
(('replace', True), ('use_node_name', False), ('use_outputs_names', True),), "Link active to selected (Replace links, output names)"),
|
||||||
# CHANGE MIX FACTOR
|
# CHANGE MIX FACTOR
|
||||||
(operators.NWChangeMixFactor.bl_idname, 'LEFT_ARROW', 'PRESS', False, False, True, (('option', -0.1),), "Reduce Mix Factor by 0.1"),
|
(operators.NWChangeMixFactor.bl_idname, 'LEFT_ARROW', 'PRESS', False,
|
||||||
(operators.NWChangeMixFactor.bl_idname, 'RIGHT_ARROW', 'PRESS', False, False, True, (('option', 0.1),), "Increase Mix Factor by 0.1"),
|
False, True, (('option', -0.1),), "Reduce Mix Factor by 0.1"),
|
||||||
(operators.NWChangeMixFactor.bl_idname, 'LEFT_ARROW', 'PRESS', False, True, True, (('option', -0.01),), "Reduce Mix Factor by 0.01"),
|
(operators.NWChangeMixFactor.bl_idname, 'RIGHT_ARROW', 'PRESS', False,
|
||||||
(operators.NWChangeMixFactor.bl_idname, 'RIGHT_ARROW', 'PRESS', False, True, True, (('option', 0.01),), "Increase Mix Factor by 0.01"),
|
False, True, (('option', 0.1),), "Increase Mix Factor by 0.1"),
|
||||||
(operators.NWChangeMixFactor.bl_idname, 'LEFT_ARROW', 'PRESS', True, True, True, (('option', 0.0),), "Set Mix Factor to 0.0"),
|
(operators.NWChangeMixFactor.bl_idname, 'LEFT_ARROW', 'PRESS', False,
|
||||||
(operators.NWChangeMixFactor.bl_idname, 'RIGHT_ARROW', 'PRESS', True, True, True, (('option', 1.0),), "Set Mix Factor to 1.0"),
|
True, True, (('option', -0.01),), "Reduce Mix Factor by 0.01"),
|
||||||
(operators.NWChangeMixFactor.bl_idname, 'NUMPAD_0', 'PRESS', True, True, True, (('option', 0.0),), "Set Mix Factor to 0.0"),
|
(operators.NWChangeMixFactor.bl_idname, 'RIGHT_ARROW', 'PRESS', False,
|
||||||
|
True, True, (('option', 0.01),), "Increase Mix Factor by 0.01"),
|
||||||
|
(operators.NWChangeMixFactor.bl_idname, 'LEFT_ARROW', 'PRESS',
|
||||||
|
True, True, True, (('option', 0.0),), "Set Mix Factor to 0.0"),
|
||||||
|
(operators.NWChangeMixFactor.bl_idname, 'RIGHT_ARROW', 'PRESS',
|
||||||
|
True, True, True, (('option', 1.0),), "Set Mix Factor to 1.0"),
|
||||||
|
(operators.NWChangeMixFactor.bl_idname, 'NUMPAD_0', 'PRESS',
|
||||||
|
True, True, True, (('option', 0.0),), "Set Mix Factor to 0.0"),
|
||||||
(operators.NWChangeMixFactor.bl_idname, 'ZERO', 'PRESS', True, True, True, (('option', 0.0),), "Set Mix Factor to 0.0"),
|
(operators.NWChangeMixFactor.bl_idname, 'ZERO', 'PRESS', True, True, True, (('option', 0.0),), "Set Mix Factor to 0.0"),
|
||||||
(operators.NWChangeMixFactor.bl_idname, 'NUMPAD_1', 'PRESS', True, True, True, (('option', 1.0),), "Mix Factor to 1.0"),
|
(operators.NWChangeMixFactor.bl_idname, 'NUMPAD_1', 'PRESS', True, True, True, (('option', 1.0),), "Mix Factor to 1.0"),
|
||||||
(operators.NWChangeMixFactor.bl_idname, 'ONE', 'PRESS', True, True, True, (('option', 1.0),), "Set Mix Factor to 1.0"),
|
(operators.NWChangeMixFactor.bl_idname, 'ONE', 'PRESS', True, True, True, (('option', 1.0),), "Set Mix Factor to 1.0"),
|
||||||
@ -300,16 +312,19 @@ kmi_defs = (
|
|||||||
# MODIFY LABEL (Alt Shift L)
|
# MODIFY LABEL (Alt Shift L)
|
||||||
(operators.NWModifyLabels.bl_idname, 'L', 'PRESS', False, True, True, None, "Modify node labels"),
|
(operators.NWModifyLabels.bl_idname, 'L', 'PRESS', False, True, True, None, "Modify node labels"),
|
||||||
# Copy Label from active to selected
|
# Copy Label from active to selected
|
||||||
(operators.NWCopyLabel.bl_idname, 'V', 'PRESS', False, True, False, (('option', 'FROM_ACTIVE'),), "Copy label from active to selected"),
|
(operators.NWCopyLabel.bl_idname, 'V', 'PRESS', False, True, False,
|
||||||
|
(('option', 'FROM_ACTIVE'),), "Copy label from active to selected"),
|
||||||
# DETACH OUTPUTS (Alt Shift D)
|
# DETACH OUTPUTS (Alt Shift D)
|
||||||
(operators.NWDetachOutputs.bl_idname, 'D', 'PRESS', False, True, True, None, "Detach outputs"),
|
(operators.NWDetachOutputs.bl_idname, 'D', 'PRESS', False, True, True, None, "Detach outputs"),
|
||||||
# LINK TO OUTPUT NODE (O)
|
# LINK TO OUTPUT NODE (O)
|
||||||
(operators.NWLinkToOutputNode.bl_idname, 'O', 'PRESS', False, False, False, None, "Link to output node"),
|
(operators.NWLinkToOutputNode.bl_idname, 'O', 'PRESS', False, False, False, None, "Link to output node"),
|
||||||
# SELECT PARENT/CHILDREN
|
# SELECT PARENT/CHILDREN
|
||||||
# Select Children
|
# Select Children
|
||||||
(operators.NWSelectParentChildren.bl_idname, 'RIGHT_BRACKET', 'PRESS', False, False, False, (('option', 'CHILD'),), "Select children"),
|
(operators.NWSelectParentChildren.bl_idname, 'RIGHT_BRACKET', 'PRESS',
|
||||||
|
False, False, False, (('option', 'CHILD'),), "Select children"),
|
||||||
# Select Parent
|
# Select Parent
|
||||||
(operators.NWSelectParentChildren.bl_idname, 'LEFT_BRACKET', 'PRESS', False, False, False, (('option', 'PARENT'),), "Select Parent"),
|
(operators.NWSelectParentChildren.bl_idname, 'LEFT_BRACKET', 'PRESS',
|
||||||
|
False, False, False, (('option', 'PARENT'),), "Select Parent"),
|
||||||
# Add Texture Setup
|
# Add Texture Setup
|
||||||
(operators.NWAddTextureSetup.bl_idname, 'T', 'PRESS', True, False, False, None, "Add texture setup"),
|
(operators.NWAddTextureSetup.bl_idname, 'T', 'PRESS', True, False, False, None, "Add texture setup"),
|
||||||
# Add Principled BSDF Texture Setup
|
# Add Principled BSDF Texture Setup
|
||||||
@ -323,8 +338,10 @@ kmi_defs = (
|
|||||||
# Swap Links
|
# Swap Links
|
||||||
(operators.NWSwapLinks.bl_idname, 'S', 'PRESS', False, False, True, None, "Swap Links"),
|
(operators.NWSwapLinks.bl_idname, 'S', 'PRESS', False, False, True, None, "Swap Links"),
|
||||||
# Preview Node
|
# Preview Node
|
||||||
(operators.NWPreviewNode.bl_idname, 'LEFTMOUSE', 'PRESS', True, True, False, (('run_in_geometry_nodes', False),), "Preview node output"),
|
(operators.NWPreviewNode.bl_idname, 'LEFTMOUSE', 'PRESS', True, True,
|
||||||
(operators.NWPreviewNode.bl_idname, 'LEFTMOUSE', 'PRESS', False, True, True, (('run_in_geometry_nodes', True),), "Preview node output"),
|
False, (('run_in_geometry_nodes', False),), "Preview node output"),
|
||||||
|
(operators.NWPreviewNode.bl_idname, 'LEFTMOUSE', 'PRESS', False, True,
|
||||||
|
True, (('run_in_geometry_nodes', True),), "Preview node output"),
|
||||||
# Reload Images
|
# Reload Images
|
||||||
(operators.NWReloadImages.bl_idname, 'R', 'PRESS', False, False, True, None, "Reload images"),
|
(operators.NWReloadImages.bl_idname, 'R', 'PRESS', False, False, True, None, "Reload images"),
|
||||||
# Lazy Mix
|
# Lazy Mix
|
||||||
@ -332,26 +349,35 @@ kmi_defs = (
|
|||||||
# Lazy Connect
|
# Lazy Connect
|
||||||
(operators.NWLazyConnect.bl_idname, 'RIGHTMOUSE', 'PRESS', False, False, True, (('with_menu', False),), "Lazy Connect"),
|
(operators.NWLazyConnect.bl_idname, 'RIGHTMOUSE', 'PRESS', False, False, True, (('with_menu', False),), "Lazy Connect"),
|
||||||
# Lazy Connect with Menu
|
# Lazy Connect with Menu
|
||||||
(operators.NWLazyConnect.bl_idname, 'RIGHTMOUSE', 'PRESS', False, True, True, (('with_menu', True),), "Lazy Connect with Socket Menu"),
|
(operators.NWLazyConnect.bl_idname, 'RIGHTMOUSE', 'PRESS', False,
|
||||||
|
True, True, (('with_menu', True),), "Lazy Connect with Socket Menu"),
|
||||||
# Viewer Tile Center
|
# Viewer Tile Center
|
||||||
(operators.NWViewerFocus.bl_idname, 'LEFTMOUSE', 'DOUBLE_CLICK', False, False, False, None, "Set Viewers Tile Center"),
|
(operators.NWViewerFocus.bl_idname, 'LEFTMOUSE', 'DOUBLE_CLICK', False, False, False, None, "Set Viewers Tile Center"),
|
||||||
# Align Nodes
|
# Align Nodes
|
||||||
(operators.NWAlignNodes.bl_idname, 'EQUAL', 'PRESS', False, True, False, None, "Align selected nodes neatly in a row/column"),
|
(operators.NWAlignNodes.bl_idname, 'EQUAL', 'PRESS', False, True,
|
||||||
|
False, None, "Align selected nodes neatly in a row/column"),
|
||||||
# Reset Nodes (Back Space)
|
# Reset Nodes (Back Space)
|
||||||
(operators.NWResetNodes.bl_idname, 'BACK_SPACE', 'PRESS', False, False, False, None, "Revert node back to default state, but keep connections"),
|
(operators.NWResetNodes.bl_idname, 'BACK_SPACE', 'PRESS', False, False,
|
||||||
|
False, None, "Revert node back to default state, but keep connections"),
|
||||||
# MENUS
|
# MENUS
|
||||||
('wm.call_menu', 'W', 'PRESS', False, True, False, (('name', interface.NodeWranglerMenu.bl_idname),), "Node Wrangler menu"),
|
('wm.call_menu', 'W', 'PRESS', False, True, False, (('name', interface.NodeWranglerMenu.bl_idname),), "Node Wrangler menu"),
|
||||||
('wm.call_menu', 'SLASH', 'PRESS', False, False, False, (('name', interface.NWAddReroutesMenu.bl_idname),), "Add Reroutes menu"),
|
('wm.call_menu', 'SLASH', 'PRESS', False, False, False,
|
||||||
('wm.call_menu', 'NUMPAD_SLASH', 'PRESS', False, False, False, (('name', interface.NWAddReroutesMenu.bl_idname),), "Add Reroutes menu"),
|
(('name', interface.NWAddReroutesMenu.bl_idname),), "Add Reroutes menu"),
|
||||||
('wm.call_menu', 'BACK_SLASH', 'PRESS', False, False, False, (('name', interface.NWLinkActiveToSelectedMenu.bl_idname),), "Link active to selected (menu)"),
|
('wm.call_menu', 'NUMPAD_SLASH', 'PRESS', False, False, False,
|
||||||
('wm.call_menu', 'C', 'PRESS', False, True, False, (('name', interface.NWCopyToSelectedMenu.bl_idname),), "Copy to selected (menu)"),
|
(('name', interface.NWAddReroutesMenu.bl_idname),), "Add Reroutes menu"),
|
||||||
('wm.call_menu', 'S', 'PRESS', False, True, False, (('name', interface.NWSwitchNodeTypeMenu.bl_idname),), "Switch node type menu"),
|
('wm.call_menu', 'BACK_SLASH', 'PRESS', False, False, False,
|
||||||
|
(('name', interface.NWLinkActiveToSelectedMenu.bl_idname),), "Link active to selected (menu)"),
|
||||||
|
('wm.call_menu', 'C', 'PRESS', False, True, False,
|
||||||
|
(('name', interface.NWCopyToSelectedMenu.bl_idname),), "Copy to selected (menu)"),
|
||||||
|
('wm.call_menu', 'S', 'PRESS', False, True, False,
|
||||||
|
(('name', interface.NWSwitchNodeTypeMenu.bl_idname),), "Switch node type menu"),
|
||||||
)
|
)
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
NWPrincipledPreferences, NWNodeWrangler
|
NWPrincipledPreferences, NWNodeWrangler
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
from bpy.utils import register_class
|
from bpy.utils import register_class
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
@ -386,6 +412,7 @@ def register():
|
|||||||
|
|
||||||
bpy.utils.register_class(switch_category_type)
|
bpy.utils.register_class(switch_category_type)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
for cat_types in switch_category_menus:
|
for cat_types in switch_category_menus:
|
||||||
bpy.utils.unregister_class(cat_types)
|
bpy.utils.unregister_class(cat_types)
|
||||||
|
@ -38,7 +38,7 @@ rl_outputs = (
|
|||||||
RL_entry('use_pass_uv', 'UV', 'UV', True, True),
|
RL_entry('use_pass_uv', 'UV', 'UV', True, True),
|
||||||
RL_entry('use_pass_vector', 'Speed', 'Vector', False, True),
|
RL_entry('use_pass_vector', 'Speed', 'Vector', False, True),
|
||||||
RL_entry('use_pass_z', 'Z', 'Depth', True, True),
|
RL_entry('use_pass_z', 'Z', 'Depth', True, True),
|
||||||
)
|
)
|
||||||
|
|
||||||
# list of blend types of "Mix" nodes in a form that can be used as 'items' for EnumProperty.
|
# list of blend types of "Mix" nodes in a form that can be used as 'items' for EnumProperty.
|
||||||
# used list, not tuple for easy merging with other lists.
|
# used list, not tuple for easy merging with other lists.
|
||||||
|
@ -14,11 +14,11 @@ def draw_line(x1, y1, x2, y2, size, colour=(1.0, 1.0, 1.0, 0.7)):
|
|||||||
shader.uniform_float("lineWidth", size * prefs_line_width())
|
shader.uniform_float("lineWidth", size * prefs_line_width())
|
||||||
|
|
||||||
vertices = ((x1, y1), (x2, y2))
|
vertices = ((x1, y1), (x2, y2))
|
||||||
vertex_colors = ((colour[0]+(1.0-colour[0])/4,
|
vertex_colors = ((colour[0] + (1.0 - colour[0]) / 4,
|
||||||
colour[1]+(1.0-colour[1])/4,
|
colour[1] + (1.0 - colour[1]) / 4,
|
||||||
colour[2]+(1.0-colour[2])/4,
|
colour[2] + (1.0 - colour[2]) / 4,
|
||||||
colour[3]+(1.0-colour[3])/4),
|
colour[3] + (1.0 - colour[3]) / 4),
|
||||||
colour)
|
colour)
|
||||||
|
|
||||||
batch = batch_for_shader(shader, 'LINE_STRIP', {"pos": vertices, "color": vertex_colors})
|
batch = batch_for_shader(shader, 'LINE_STRIP', {"pos": vertices, "color": vertex_colors})
|
||||||
batch.draw(shader)
|
batch.draw(shader)
|
||||||
@ -29,7 +29,7 @@ def draw_circle_2d_filled(mx, my, radius, colour=(1.0, 1.0, 1.0, 0.7)):
|
|||||||
sides = 12
|
sides = 12
|
||||||
vertices = [(radius * cos(i * 2 * pi / sides) + mx,
|
vertices = [(radius * cos(i * 2 * pi / sides) + mx,
|
||||||
radius * sin(i * 2 * pi / sides) + my)
|
radius * sin(i * 2 * pi / sides) + my)
|
||||||
for i in range(sides + 1)]
|
for i in range(sides + 1)]
|
||||||
|
|
||||||
shader = gpu.shader.from_builtin('UNIFORM_COLOR')
|
shader = gpu.shader.from_builtin('UNIFORM_COLOR')
|
||||||
shader.uniform_float("color", colour)
|
shader.uniform_float("color", colour)
|
||||||
@ -44,8 +44,8 @@ def draw_rounded_node_border(node, radius=8, colour=(1.0, 1.0, 1.0, 0.7)):
|
|||||||
|
|
||||||
nlocx, nlocy = abs_node_location(node)
|
nlocx, nlocy = abs_node_location(node)
|
||||||
|
|
||||||
nlocx = (nlocx+1) * dpi_fac()
|
nlocx = (nlocx + 1) * dpi_fac()
|
||||||
nlocy = (nlocy+1) * dpi_fac()
|
nlocy = (nlocy + 1) * dpi_fac()
|
||||||
ndimx = node.dimensions.x
|
ndimx = node.dimensions.x
|
||||||
ndimy = node.dimensions.y
|
ndimy = node.dimensions.y
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ def draw_rounded_node_border(node, radius=8, colour=(1.0, 1.0, 1.0, 0.7)):
|
|||||||
nlocx += -1
|
nlocx += -1
|
||||||
nlocy += 5
|
nlocy += 5
|
||||||
if node.type == 'REROUTE':
|
if node.type == 'REROUTE':
|
||||||
#nlocx += 1
|
# nlocx += 1
|
||||||
nlocy -= 1
|
nlocy -= 1
|
||||||
ndimx = 0
|
ndimx = 0
|
||||||
ndimy = 0
|
ndimy = 0
|
||||||
@ -64,52 +64,52 @@ def draw_rounded_node_border(node, radius=8, colour=(1.0, 1.0, 1.0, 0.7)):
|
|||||||
|
|
||||||
# Top left corner
|
# Top left corner
|
||||||
mx, my = bpy.context.region.view2d.view_to_region(nlocx, nlocy, clip=False)
|
mx, my = bpy.context.region.view2d.view_to_region(nlocx, nlocy, clip=False)
|
||||||
vertices = [(mx,my)]
|
vertices = [(mx, my)]
|
||||||
for i in range(sides+1):
|
for i in range(sides + 1):
|
||||||
if (4<=i<=8):
|
if (4 <= i <= 8):
|
||||||
if mx < area_width:
|
if mx < area_width:
|
||||||
cosine = radius * cos(i * 2 * pi / sides) + mx
|
cosine = radius * cos(i * 2 * pi / sides) + mx
|
||||||
sine = radius * sin(i * 2 * pi / sides) + my
|
sine = radius * sin(i * 2 * pi / sides) + my
|
||||||
vertices.append((cosine,sine))
|
vertices.append((cosine, sine))
|
||||||
|
|
||||||
batch = batch_for_shader(shader, 'TRI_FAN', {"pos": vertices})
|
batch = batch_for_shader(shader, 'TRI_FAN', {"pos": vertices})
|
||||||
batch.draw(shader)
|
batch.draw(shader)
|
||||||
|
|
||||||
# Top right corner
|
# Top right corner
|
||||||
mx, my = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy, clip=False)
|
mx, my = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy, clip=False)
|
||||||
vertices = [(mx,my)]
|
vertices = [(mx, my)]
|
||||||
for i in range(sides+1):
|
for i in range(sides + 1):
|
||||||
if (0<=i<=4):
|
if (0 <= i <= 4):
|
||||||
if mx < area_width:
|
if mx < area_width:
|
||||||
cosine = radius * cos(i * 2 * pi / sides) + mx
|
cosine = radius * cos(i * 2 * pi / sides) + mx
|
||||||
sine = radius * sin(i * 2 * pi / sides) + my
|
sine = radius * sin(i * 2 * pi / sides) + my
|
||||||
vertices.append((cosine,sine))
|
vertices.append((cosine, sine))
|
||||||
|
|
||||||
batch = batch_for_shader(shader, 'TRI_FAN', {"pos": vertices})
|
batch = batch_for_shader(shader, 'TRI_FAN', {"pos": vertices})
|
||||||
batch.draw(shader)
|
batch.draw(shader)
|
||||||
|
|
||||||
# Bottom left corner
|
# Bottom left corner
|
||||||
mx, my = bpy.context.region.view2d.view_to_region(nlocx, nlocy - ndimy, clip=False)
|
mx, my = bpy.context.region.view2d.view_to_region(nlocx, nlocy - ndimy, clip=False)
|
||||||
vertices = [(mx,my)]
|
vertices = [(mx, my)]
|
||||||
for i in range(sides+1):
|
for i in range(sides + 1):
|
||||||
if (8<=i<=12):
|
if (8 <= i <= 12):
|
||||||
if mx < area_width:
|
if mx < area_width:
|
||||||
cosine = radius * cos(i * 2 * pi / sides) + mx
|
cosine = radius * cos(i * 2 * pi / sides) + mx
|
||||||
sine = radius * sin(i * 2 * pi / sides) + my
|
sine = radius * sin(i * 2 * pi / sides) + my
|
||||||
vertices.append((cosine,sine))
|
vertices.append((cosine, sine))
|
||||||
|
|
||||||
batch = batch_for_shader(shader, 'TRI_FAN', {"pos": vertices})
|
batch = batch_for_shader(shader, 'TRI_FAN', {"pos": vertices})
|
||||||
batch.draw(shader)
|
batch.draw(shader)
|
||||||
|
|
||||||
# Bottom right corner
|
# Bottom right corner
|
||||||
mx, my = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy - ndimy, clip=False)
|
mx, my = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy - ndimy, clip=False)
|
||||||
vertices = [(mx,my)]
|
vertices = [(mx, my)]
|
||||||
for i in range(sides+1):
|
for i in range(sides + 1):
|
||||||
if (12<=i<=16):
|
if (12 <= i <= 16):
|
||||||
if mx < area_width:
|
if mx < area_width:
|
||||||
cosine = radius * cos(i * 2 * pi / sides) + mx
|
cosine = radius * cos(i * 2 * pi / sides) + mx
|
||||||
sine = radius * sin(i * 2 * pi / sides) + my
|
sine = radius * sin(i * 2 * pi / sides) + my
|
||||||
vertices.append((cosine,sine))
|
vertices.append((cosine, sine))
|
||||||
|
|
||||||
batch = batch_for_shader(shader, 'TRI_FAN', {"pos": vertices})
|
batch = batch_for_shader(shader, 'TRI_FAN', {"pos": vertices})
|
||||||
batch.draw(shader)
|
batch.draw(shader)
|
||||||
@ -123,10 +123,10 @@ def draw_rounded_node_border(node, radius=8, colour=(1.0, 1.0, 1.0, 0.7)):
|
|||||||
m1x, m1y = bpy.context.region.view2d.view_to_region(nlocx, nlocy, clip=False)
|
m1x, m1y = bpy.context.region.view2d.view_to_region(nlocx, nlocy, clip=False)
|
||||||
m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx, nlocy - ndimy, clip=False)
|
m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx, nlocy - ndimy, clip=False)
|
||||||
if m1x < area_width and m2x < area_width:
|
if m1x < area_width and m2x < area_width:
|
||||||
vertices.extend([(m2x-radius,m2y), (m2x,m2y),
|
vertices.extend([(m2x - radius, m2y), (m2x, m2y),
|
||||||
(m1x,m1y), (m1x-radius,m1y)])
|
(m1x, m1y), (m1x - radius, m1y)])
|
||||||
indices.extend([(id_last, id_last+1, id_last+3),
|
indices.extend([(id_last, id_last + 1, id_last + 3),
|
||||||
(id_last+3, id_last+1, id_last+2)])
|
(id_last + 3, id_last + 1, id_last + 2)])
|
||||||
id_last += 4
|
id_last += 4
|
||||||
|
|
||||||
# Top edge
|
# Top edge
|
||||||
@ -134,31 +134,31 @@ def draw_rounded_node_border(node, radius=8, colour=(1.0, 1.0, 1.0, 0.7)):
|
|||||||
m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy, clip=False)
|
m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy, clip=False)
|
||||||
m1x = min(m1x, area_width)
|
m1x = min(m1x, area_width)
|
||||||
m2x = min(m2x, area_width)
|
m2x = min(m2x, area_width)
|
||||||
vertices.extend([(m1x,m1y), (m2x,m1y),
|
vertices.extend([(m1x, m1y), (m2x, m1y),
|
||||||
(m2x,m1y+radius), (m1x,m1y+radius)])
|
(m2x, m1y + radius), (m1x, m1y + radius)])
|
||||||
indices.extend([(id_last, id_last+1, id_last+3),
|
indices.extend([(id_last, id_last + 1, id_last + 3),
|
||||||
(id_last+3, id_last+1, id_last+2)])
|
(id_last + 3, id_last + 1, id_last + 2)])
|
||||||
id_last += 4
|
id_last += 4
|
||||||
|
|
||||||
# Right edge
|
# Right edge
|
||||||
m1x, m1y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy, clip=False)
|
m1x, m1y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy, clip=False)
|
||||||
m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy - ndimy, clip=False)
|
m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy - ndimy, clip=False)
|
||||||
if m1x < area_width and m2x < area_width:
|
if m1x < area_width and m2x < area_width:
|
||||||
vertices.extend([(m1x,m2y), (m1x+radius,m2y),
|
vertices.extend([(m1x, m2y), (m1x + radius, m2y),
|
||||||
(m1x+radius,m1y), (m1x,m1y)])
|
(m1x + radius, m1y), (m1x, m1y)])
|
||||||
indices.extend([(id_last, id_last+1, id_last+3),
|
indices.extend([(id_last, id_last + 1, id_last + 3),
|
||||||
(id_last+3, id_last+1, id_last+2)])
|
(id_last + 3, id_last + 1, id_last + 2)])
|
||||||
id_last += 4
|
id_last += 4
|
||||||
|
|
||||||
# Bottom edge
|
# Bottom edge
|
||||||
m1x, m1y = bpy.context.region.view2d.view_to_region(nlocx, nlocy-ndimy, clip=False)
|
m1x, m1y = bpy.context.region.view2d.view_to_region(nlocx, nlocy - ndimy, clip=False)
|
||||||
m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy-ndimy, clip=False)
|
m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy - ndimy, clip=False)
|
||||||
m1x = min(m1x, area_width)
|
m1x = min(m1x, area_width)
|
||||||
m2x = min(m2x, area_width)
|
m2x = min(m2x, area_width)
|
||||||
vertices.extend([(m1x,m2y), (m2x,m2y),
|
vertices.extend([(m1x, m2y), (m2x, m2y),
|
||||||
(m2x,m1y-radius), (m1x,m1y-radius)])
|
(m2x, m1y - radius), (m1x, m1y - radius)])
|
||||||
indices.extend([(id_last, id_last+1, id_last+3),
|
indices.extend([(id_last, id_last + 1, id_last + 3),
|
||||||
(id_last+3, id_last+1, id_last+2)])
|
(id_last + 3, id_last + 1, id_last + 2)])
|
||||||
|
|
||||||
# now draw all edges in one batch
|
# now draw all edges in one batch
|
||||||
if len(vertices) != 0:
|
if len(vertices) != 0:
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from math import hypot
|
from math import hypot
|
||||||
|
|
||||||
|
|
||||||
def force_update(context):
|
def force_update(context):
|
||||||
context.space_data.node_tree.update_tag()
|
context.space_data.node_tree.update_tag()
|
||||||
|
|
||||||
@ -169,7 +170,7 @@ def is_viewer_socket(socket):
|
|||||||
|
|
||||||
|
|
||||||
def get_internal_socket(socket):
|
def get_internal_socket(socket):
|
||||||
#get the internal socket from a socket inside or outside the group
|
# get the internal socket from a socket inside or outside the group
|
||||||
node = socket.node
|
node = socket.node
|
||||||
if node.type == 'GROUP_OUTPUT':
|
if node.type == 'GROUP_OUTPUT':
|
||||||
source_iterator = node.inputs
|
source_iterator = node.inputs
|
||||||
@ -205,7 +206,7 @@ def is_viewer_link(link, output_node):
|
|||||||
|
|
||||||
def get_group_output_node(tree):
|
def get_group_output_node(tree):
|
||||||
for node in tree.nodes:
|
for node in tree.nodes:
|
||||||
if node.type == 'GROUP_OUTPUT' and node.is_active_output == True:
|
if node.type == 'GROUP_OUTPUT' and node.is_active_output:
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user