2021-09-10 18:32:50 +02:00
|
|
|
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"}
|
|
|
|
|
2021-09-23 19:14:48 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
# mode : bpy.props.StringProperty(default='NORMAL', options={'SKIP_SAVE'})
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
|
|
|
|
rd_scn = bpy.data.scenes.get('Render')
|
|
|
|
if not rd_scn:
|
|
|
|
self.report({'ERROR'}, 'Viewlayers needs to be generated first!')
|
|
|
|
return {'CANCELLED'}
|
|
|
|
|
|
|
|
nodes = rd_scn.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
|
|
|
|
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
|
|
|
|
|
|
|
|
for sub_n in reversed(inside_nodes):
|
|
|
|
ngroup.nodes.remove(sub_n)
|
|
|
|
|
|
|
|
# remove render_layer node
|
|
|
|
rd_scn.node_tree.nodes.remove(n)
|
|
|
|
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
|
2021-12-16 19:10:00 +01:00
|
|
|
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"}
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-09-10 18:32:50 +02:00
|
|
|
classes=(
|
|
|
|
GPEXP_OT_reconnect_render_layer,
|
2021-09-23 19:14:48 +02:00
|
|
|
GPEXP_OT_delete_render_layer,
|
2021-12-16 19:10:00 +01:00
|
|
|
GPEXP_OT_set_active_fileout_to_compout,
|
2021-09-10 18:32:50 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
def register():
|
|
|
|
for cls in classes:
|
|
|
|
bpy.utils.register_class(cls)
|
|
|
|
|
|
|
|
def unregister():
|
|
|
|
for cls in reversed(classes):
|
|
|
|
bpy.utils.unregister_class(cls)
|