gp_render/OP_connect_toggle.py

255 lines
8.9 KiB
Python

import bpy
from . import fn
class GPEXP_OT_reconnect_render_layer(bpy.types.Operator):
bl_idname = "gp.reconnect_render_layer"
bl_label = "Reconnect Render Layer"
bl_description = "Reconnect selected render layers"
bl_options = {"REGISTER"}
@classmethod
def poll(cls, context):
return True
# mode : bpy.props.StringProperty(default='NORMAL', options={'SKIP_SAVE'})
def execute(self, context):
node_tree = context.scene.node_tree
nodes = node_tree.nodes
changed = []
for n in nodes:
if not n.select or not n.type == 'R_LAYERS':
continue
if not ' / ' in n.layer:
continue
if n.outputs[0].is_linked: # already connected
continue
# get namme
obname = n.layer.split()[0]
grp_name = f'NG_{obname}'
# get nodegroup
grp = nodes.get(grp_name)
if not grp:
print(f'{n.name} Node group not found : {n.layer} !-> {grp_name}')
continue
inp = grp.inputs.get(n.layer)
if not inp:
print(f'{n.name} no inputs name "{n.layer}" in group {grp_name}')
continue
# reconnect
node_tree.links.new(n.outputs[0], inp)
changed.append(f'{n.name} ({n.layer}) to {grp_name}')
if changed:
self.report({'INFO'}, f'{len(changed)} nodes reconnected')
else:
self.report({'WARNING'}, f'Could not reconnect, see console')
return {"FINISHED"}
class GPEXP_OT_delete_render_layer(bpy.types.Operator):
bl_idname = "gp.delete_render_layer"
bl_label = "Delete Render Layer"
bl_description = "Delete selected render layers"
bl_options = {"REGISTER"}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
## Compositing scene where nodes lives
compo_scene = context.scene
## render scene where viewlayer lives
rd_scn = fn.get_render_scene(create=False)
if not rd_scn:
self.report({'ERROR'}, 'No render scene found')
return {'CANCELLED'}
nodes = compo_scene.node_tree.nodes
# list layers and viewlayers
# vls = [rd_scn.view_layers.get(l.viewlayer_render) for l in layers
# if l.viewlayer_render and l.viewlayer_render != act.viewlayer_render and rd_scn.view_layers.get(l.viewlayer_render)]
rlayers_nodes = [n for n in nodes if n.select and n.type == 'R_LAYERS']
vls = [rd_scn.view_layers.get(n.layer) for n in rlayers_nodes if rd_scn.view_layers.get(n.layer)]
vl_names = [v.name for v in vls]
## disable layers using those VL
for ob in [o for o in rd_scn.objects if o.type == 'GPENCIL']:
for l in ob.data.layers:
if l.viewlayer_render in vl_names:
l.viewlayer_render = fn.get_view_layer('exclude').name
for n in reversed(rlayers_nodes):
# Disconnect linked
for lnk in n.outputs[0].links:
grp = lnk.to_node
if grp.type != 'GROUP':
continue
if not grp.name.startswith('NG'):
continue
sockin = lnk.to_socket
sockout = grp.outputs.get(sockin.name)
if not sockout:
continue
for grplink in sockout.links:
if grplink.to_node.type != 'OUTPUT_FILE':
continue
fo_socket = grplink.to_socket
fo = grplink.to_node
fo.file_slots.remove(fo_socket)
inside_nodes = []
ngroup = grp.node_tree
if bpy.app.version < (4,0,0):
for i in range(len(grp.inputs))[::-1]:
if grp.inputs[i].name == sockin.name:
ngroup.inputs.remove(ngroup.inputs[i])
gp_in_socket = ngroup.nodes['Group Input'].outputs[i]
for lnk in gp_in_socket.links:
inside_nodes += fn.all_connected_forward(lnk.to_node)
list(set(inside_nodes))
break
for i in range(len(grp.outputs))[::-1]:
if grp.outputs[i].name == sockout.name:
ngroup.outputs.remove(ngroup.outputs[i])
break
else:
g_inputs = [s for s in ngroup.interface.items_tree if s.in_out == 'INPUT']
g_outputs = [s for s in ngroup.interface.items_tree if s.in_out == 'OUTPUT']
for i in range(len(grp.inputs))[::-1]:
if grp.inputs[i].name == sockin.name:
ngroup.interface.remove(g_inputs[i])
gp_in_socket = ngroup.nodes['Group Input'].outputs[i]
for lnk in gp_in_socket.links:
inside_nodes += fn.all_connected_forward(lnk.to_node)
list(set(inside_nodes))
break
for i in range(len(grp.outputs))[::-1]:
if grp.outputs[i].name == sockout.name:
ngroup.interface.remove(g_outputs[i])
break
for sub_n in reversed(inside_nodes):
ngroup.nodes.remove(sub_n)
# Remove render_layer node
nodes.remove(n)
return {"FINISHED"}
class GPEXP_OT_set_active_fileout_to_compout(bpy.types.Operator):
bl_idname = "gp.set_active_fileout_to_compout"
bl_label = "Set Active File Output To Composite"
bl_description = "Use active slot of active file output node to set scene output settings (swap connection)"
bl_options = {"REGISTER"}
@classmethod
def poll(cls, context):
return context.scene.use_nodes\
and context.scene.node_tree\
and context.scene.node_tree.nodes.active\
and context.scene.node_tree.nodes.active.type == 'OUTPUT_FILE'
relink_composite : bpy.props.BoolProperty(
name='Relink Composite',
default=True,
description='In case file slot is linked, swap link to Composite file',
options={'SKIP_SAVE'},
)
def invoke(self, context, event):
self.fo = context.scene.node_tree.nodes.active
if not len(self.fo.file_slots):
self.report({'ERROR'}, 'no slots in active file output')
return {'CANCELLED'}
# check if active slot has a source
if not self.fo.inputs[self.fo.active_input_index].is_linked:
return self.execute(context)
# check if composite linked
out = context.scene.node_tree.nodes.get('Composite')
if not out or not out.inputs[0].is_linked:
self.compo_out_from_link = ''
return self.execute(context)
# compo linked, pop panel to choose replace or not
self.compo_out_from_link = out.inputs[0].links[0].from_node.name
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
layout = self.layout
col = layout.column()
col.label(text=f'Composite node connected to: {self.compo_out_from_link}')
col.label(text=f'Would you like to replace by file output slot source ?')
layout.prop(self, 'relink_composite')
def execute(self, context):
# if comp
fn.set_scene_output_from_active_fileout_item()
idx = self.fo.active_input_index
sl = self.fo.file_slots[idx]
sk = self.fo.inputs[idx]
if not sk.is_linked:
self.report({'INFO'}, f'Outut changed to match {sl.path} (slot was not linked)')
return {'FINISHED'}
## If linked replace links to Composite node
if not self.relink_composite:
return {'FINISHED'}
ntree = context.scene.node_tree
links = context.scene.node_tree.links
nodes = context.scene.node_tree.nodes
out = nodes.get('Composite')
if not out:
out = fn.create_node('COMPOSITE', tree=ntree)
fo_loc = fn.real_loc(self.fo)
out.location = (fo_loc.x, fo_loc.y + 160)
# if out.inputs[0].is_linked:
# self.report({'WARNING'}, f'Outut changed to match {sl.path} (Composite node already linked)')
lnk = sk.links[0]
from_sk = sk.links[0].from_socket
links.remove(lnk)
links.new(from_sk, out.inputs[0])
return {"FINISHED"}
classes=(
GPEXP_OT_reconnect_render_layer,
GPEXP_OT_delete_render_layer,
GPEXP_OT_set_active_fileout_to_compout,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)