2021-09-08 18:29:10 +02:00
|
|
|
import bpy
|
2021-09-22 12:06:40 +02:00
|
|
|
import re
|
2024-04-18 15:11:59 +02:00
|
|
|
import os
|
2021-09-22 12:06:40 +02:00
|
|
|
from . import fn
|
2021-09-08 18:29:10 +02:00
|
|
|
|
|
|
|
class GPEXP_OT_mute_toggle_output_nodes(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.mute_toggle_output_nodes"
|
|
|
|
bl_label = "Mute Toggle output nodes"
|
|
|
|
bl_description = "Mute / Unmute all output nodes"
|
|
|
|
bl_options = {"REGISTER"}
|
|
|
|
|
|
|
|
mute : bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'})
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
ct = 0
|
|
|
|
for n in context.scene.node_tree.nodes:
|
|
|
|
if n.type != 'OUTPUT_FILE':
|
|
|
|
continue
|
|
|
|
n.mute = self.mute
|
|
|
|
ct += 1
|
|
|
|
|
|
|
|
state = 'muted' if self.mute else 'unmuted'
|
|
|
|
self.report({"INFO"}, f'{ct} nodes {state}')
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
2021-09-22 12:06:40 +02:00
|
|
|
class GPEXP_OT_number_outputs(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.number_outputs"
|
|
|
|
bl_label = "Number Outputs"
|
2023-06-08 12:39:39 +02:00
|
|
|
bl_description = "(Re)Number the outputs to have ordered file by name in export directories\
|
|
|
|
\nCtrl+Clic : Delete numbering"
|
2021-09-22 12:06:40 +02:00
|
|
|
bl_options = {"REGISTER"}
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def poll(cls, context):
|
|
|
|
return True
|
|
|
|
|
|
|
|
mode : bpy.props.StringProperty(default='SELECTED', options={'SKIP_SAVE'})
|
2023-06-27 11:50:31 +02:00
|
|
|
clear : bpy.props.BoolProperty(default=False, options={'SKIP_SAVE'})
|
2021-09-22 12:06:40 +02:00
|
|
|
|
|
|
|
def invoke(self, context, event):
|
2023-06-27 11:50:31 +02:00
|
|
|
# use clear with Ctrl + Click
|
|
|
|
if event.ctrl:
|
|
|
|
self.clear = True
|
2021-09-22 12:06:40 +02:00
|
|
|
return self.execute(context)
|
|
|
|
|
|
|
|
def execute(self, context):
|
2023-06-27 11:50:31 +02:00
|
|
|
scn = context.scene
|
2023-01-18 14:28:27 +01:00
|
|
|
|
2021-09-22 12:06:40 +02:00
|
|
|
ct = 0
|
2023-06-27 11:50:31 +02:00
|
|
|
nodes = scn.node_tree.nodes
|
2021-09-22 12:06:40 +02:00
|
|
|
for fo in nodes:
|
|
|
|
if fo.type != 'OUTPUT_FILE':
|
|
|
|
continue
|
|
|
|
if self.mode == 'SELECTED' and not fo.select:
|
|
|
|
continue
|
|
|
|
# print(f'numbering {fo.name}')
|
|
|
|
ct += 1
|
2023-06-27 11:50:31 +02:00
|
|
|
if self.clear:
|
2021-09-22 12:06:40 +02:00
|
|
|
fn.delete_numbering(fo)
|
|
|
|
else:
|
|
|
|
fn.renumber_keep_existing(fo)
|
|
|
|
|
2023-06-27 11:50:31 +02:00
|
|
|
txt = 'de-numbered' if self.clear else 're-numbered'
|
2021-09-22 12:06:40 +02:00
|
|
|
if ct:
|
|
|
|
self.report({'INFO'}, f'{ct} output nodes {txt}')
|
|
|
|
else:
|
|
|
|
self.report({'ERROR'}, f'No output nodes {txt}')
|
|
|
|
|
|
|
|
return {"FINISHED"}
|
2021-09-21 18:23:25 +02:00
|
|
|
|
|
|
|
class GPEXP_OT_set_output_node_format(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.set_output_node_format"
|
|
|
|
bl_label = "Set output format from active"
|
|
|
|
bl_description = "Change all selected output node to match active output node format"
|
|
|
|
bl_options = {"REGISTER"}
|
|
|
|
|
|
|
|
mute : bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'})
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
nodes = context.scene.node_tree.nodes
|
|
|
|
if not nodes.active or nodes.active.type != 'OUTPUT_FILE':
|
|
|
|
self.report({"ERROR"}, f'Active node should be an output file to use as reference for output format')
|
|
|
|
return {"CANCELLED"}
|
|
|
|
|
|
|
|
ref = nodes.active
|
2021-09-23 15:13:30 +02:00
|
|
|
|
|
|
|
# file_format = ref.format.file_format
|
|
|
|
# color_mode = ref.format.color_mode
|
|
|
|
# color_depth = ref.format.color_depth
|
|
|
|
# compression = ref.format.compression
|
2021-09-21 18:23:25 +02:00
|
|
|
|
|
|
|
ct = 0
|
2021-09-22 12:06:40 +02:00
|
|
|
for n in nodes:
|
|
|
|
if n.type != 'OUTPUT_FILE' or n == ref or not n.select:
|
2021-09-21 18:23:25 +02:00
|
|
|
continue
|
2023-01-18 14:28:27 +01:00
|
|
|
|
2021-09-23 15:13:30 +02:00
|
|
|
for attr in dir(ref.format):
|
2021-09-23 15:18:06 +02:00
|
|
|
if attr.startswith('__') or attr in {'rna_type','bl_rna', 'view_settings', 'display_settings','stereo_3d_format'}: # views_format
|
2021-09-23 15:13:30 +02:00
|
|
|
continue
|
|
|
|
try:
|
|
|
|
setattr(n.format, attr, getattr(ref.format, attr))
|
|
|
|
except Exception as e:
|
|
|
|
print(f"can't set attribute : {attr}")
|
|
|
|
|
2023-01-18 14:28:27 +01:00
|
|
|
# n.format.file_format = file_format
|
2021-09-23 15:13:30 +02:00
|
|
|
# n.format.color_mode = color_mode
|
2023-01-18 14:28:27 +01:00
|
|
|
# n.format.color_depth = color_depth
|
|
|
|
# n.format.compression = compression
|
2021-09-21 18:23:25 +02:00
|
|
|
|
|
|
|
ct += 1
|
|
|
|
|
|
|
|
# state = 'muted' if self.mute else 'unmuted'
|
|
|
|
self.report({"INFO"}, f'{ct} output format copied from {ref.name}')
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
|
2021-09-23 15:13:30 +02:00
|
|
|
|
2021-09-22 12:06:40 +02:00
|
|
|
def out_norm(x):
|
|
|
|
a = x.group(1) if x.group(1) else ''
|
|
|
|
b = x.group(2) if x.group(2) else ''
|
|
|
|
c = x.group(3) if x.group(3) else ''
|
|
|
|
d = x.group(4) if x.group(4) else ''
|
|
|
|
e = x.group(5) if x.group(5) else ''
|
|
|
|
return f'{a}{b}{fn.normalize(c)}{d}{e}'
|
|
|
|
|
2021-09-23 15:13:30 +02:00
|
|
|
|
2021-09-22 12:06:40 +02:00
|
|
|
## does not match the right thing yet
|
|
|
|
class GPEXP_OT_normalize_outnames(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.normalize_outnames"
|
|
|
|
bl_label = "Normalize Output names"
|
|
|
|
bl_description = "Normalize output names with lowercase and replace dash to underscore"
|
|
|
|
bl_options = {"REGISTER"}
|
|
|
|
|
|
|
|
mute : bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'})
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
nodes = context.scene.node_tree.nodes
|
|
|
|
|
|
|
|
reslash = re.compile('\\/')
|
|
|
|
ct = 0
|
|
|
|
for n in nodes:
|
|
|
|
if n.type != 'OUTPUT_FILE' or not n.select:
|
|
|
|
continue
|
|
|
|
# Normalize last part of the file out names
|
|
|
|
base_path_l = reslash.split(n.base_path)
|
|
|
|
base_path_l[-1] = fn.normalize(base_path_l[-1])
|
|
|
|
n.base_path = '/'.join(base_path_l)
|
|
|
|
|
|
|
|
for fs in n.file_slots:
|
|
|
|
fp = fs.path
|
|
|
|
fp_l = reslash.split(fp)
|
|
|
|
for i, part in enumerate(fp_l):
|
|
|
|
fp_l[1] = re.sub(r'(^\d{3}_)?([A-Z]{2}_)?(.*?)(_[A-Z]{2})?(_)?', out_norm, part)
|
2023-01-18 14:28:27 +01:00
|
|
|
|
2021-09-22 12:06:40 +02:00
|
|
|
fs.path = '/'.join(fp_l)
|
|
|
|
|
|
|
|
ct += 1
|
|
|
|
|
|
|
|
# state = 'muted' if self.mute else 'unmuted'
|
|
|
|
self.report({"INFO"}, f'{ct} output nodes normalized')
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
|
2021-09-23 19:14:48 +02:00
|
|
|
class GPEXP_OT_enable_all_viewlayers(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.enable_all_viewlayers"
|
|
|
|
bl_label = "Enable All Viewlayers"
|
|
|
|
bl_description = "Enable all View layers except those named 'exclude' 'View Layer'"
|
|
|
|
bl_options = {"REGISTER"}
|
|
|
|
|
|
|
|
def execute(self, context):
|
2021-10-08 15:29:56 +02:00
|
|
|
scn = context.scene
|
2021-09-23 19:14:48 +02:00
|
|
|
|
2021-10-08 15:29:56 +02:00
|
|
|
vl_list = [vl for vl in scn.view_layers if not vl.use and vl.name not in {'View Layer', 'exclude'}]
|
2021-09-23 19:14:48 +02:00
|
|
|
for v in vl_list:
|
|
|
|
v.use = True
|
2023-01-18 14:28:27 +01:00
|
|
|
|
2021-09-23 19:14:48 +02:00
|
|
|
self.report({"INFO"}, f'{len(vl_list)} ViewLayers Reactivated')
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
class GPEXP_OT_activate_only_selected_layers(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.activate_only_selected_layers"
|
|
|
|
bl_label = "Activate Only Selected Layers"
|
|
|
|
bl_description = "Activate only selected node view layer , excluding all others"
|
|
|
|
bl_options = {"REGISTER"}
|
|
|
|
|
|
|
|
def execute(self, context):
|
2021-10-08 15:29:56 +02:00
|
|
|
scn = context.scene
|
|
|
|
|
|
|
|
nodes = scn.node_tree.nodes
|
2021-09-23 19:14:48 +02:00
|
|
|
|
|
|
|
rlayers_nodes = [n for n in nodes if n.select and n.type == 'R_LAYERS']
|
2021-10-08 15:29:56 +02:00
|
|
|
vls = [scn.view_layers.get(n.layer) for n in rlayers_nodes if scn.view_layers.get(n.layer)]
|
|
|
|
for v in scn.view_layers:
|
2021-09-23 19:14:48 +02:00
|
|
|
v.use = v in vls
|
2023-01-18 14:28:27 +01:00
|
|
|
|
2021-10-08 15:29:56 +02:00
|
|
|
self.report({"INFO"}, f'Now only {len(vls)} viewlayer active (/{len(scn.view_layers)})')
|
2021-09-23 19:14:48 +02:00
|
|
|
return {"FINISHED"}
|
|
|
|
|
2021-09-22 12:06:40 +02:00
|
|
|
|
2021-10-25 16:02:11 +02:00
|
|
|
### TODO reset scene settings (set settings )
|
|
|
|
|
|
|
|
class GPEXP_OT_reset_render_settings(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.reset_render_settings"
|
|
|
|
bl_label = "Reset Render Settings"
|
|
|
|
bl_description = "Reset render settings on all scene, disabling AA nodes when there is no Merge nodegroup"
|
|
|
|
bl_options = {"REGISTER"}
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
for scn in bpy.data.scenes:
|
|
|
|
if scn.name == 'Scene':
|
|
|
|
# don't touch original scene
|
|
|
|
continue
|
2023-01-18 14:28:27 +01:00
|
|
|
|
2021-10-25 16:02:11 +02:00
|
|
|
# set a unique preview output
|
|
|
|
# - avoid possible write/sync overlap (point to tmp on linux ?)
|
|
|
|
# - allow to monitor output of a scene and possibly use Overwrite
|
2023-01-18 14:28:27 +01:00
|
|
|
|
2021-10-25 16:02:11 +02:00
|
|
|
if scn.render.filepath.startswith('//render/preview/'):
|
2021-11-11 14:48:53 +01:00
|
|
|
scn.render.filepath = f'//render/preview/{bpy.path.clean_name(scn.name.lower())}/preview_'
|
2021-10-25 16:28:54 +02:00
|
|
|
print(f'Scene {scn.name}: change output to {scn.render.filepath}')
|
2023-01-18 14:28:27 +01:00
|
|
|
|
2021-10-25 16:02:11 +02:00
|
|
|
if not scn.use_nodes:
|
|
|
|
continue
|
2023-01-18 14:28:27 +01:00
|
|
|
|
2021-10-25 16:02:11 +02:00
|
|
|
# set the settings depending on merges node presences
|
|
|
|
use_native_aa = True
|
|
|
|
for n in scn.node_tree.nodes:
|
|
|
|
if n.name.startswith('merge_NG_'):
|
|
|
|
use_native_aa = False
|
|
|
|
break
|
2023-01-18 14:28:27 +01:00
|
|
|
|
2024-04-16 18:01:10 +02:00
|
|
|
if scn.gp_render_settings.use_aa != use_native_aa:
|
2021-10-25 16:28:54 +02:00
|
|
|
print(f'Scene {scn.name}: changed scene AA settings, native AA = {use_native_aa}')
|
2021-10-25 16:02:11 +02:00
|
|
|
fn.scene_aa(scene=scn, toggle=use_native_aa)
|
2021-10-25 16:28:54 +02:00
|
|
|
|
2021-10-25 16:19:37 +02:00
|
|
|
# set propertie on scn to reflect changes (without triggering update)
|
2024-04-16 18:01:10 +02:00
|
|
|
scn.gp_render_settings['use_aa'] = use_native_aa
|
2021-10-25 16:02:11 +02:00
|
|
|
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
2024-04-18 15:11:59 +02:00
|
|
|
class GPEXP_PG_selectable_prop(bpy.types.PropertyGroup):
|
|
|
|
node_name: bpy.props.StringProperty(name="Object Name")
|
|
|
|
name: bpy.props.StringProperty(name="Name or Path")
|
2024-06-24 16:10:44 +02:00
|
|
|
socket_name: bpy.props.StringProperty(name="Source socket Name") # Source socket name as reference
|
2024-04-18 15:11:59 +02:00
|
|
|
select: bpy.props.BoolProperty(name="Selected", default=True)
|
|
|
|
is_linked: bpy.props.BoolProperty(name="Linked", default=False)
|
|
|
|
# is_valid: bpy.props.BoolProperty(name="Valid", default=True)
|
|
|
|
|
2024-01-16 16:55:07 +01:00
|
|
|
class GPEXP_OT_connect_selected_to_file_out(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.connect_selected_to_file_out"
|
|
|
|
bl_label = "Connect Selected To File Output"
|
|
|
|
bl_description = "Connect Selected Nodes to a fileoutput node\
|
|
|
|
\nIf a fileoutput node is selected, socket are added to it"
|
|
|
|
bl_options = {"REGISTER", "UNDO"}
|
|
|
|
|
2024-04-18 15:11:59 +02:00
|
|
|
socket_collection : bpy.props.CollectionProperty(type=GPEXP_PG_selectable_prop)
|
|
|
|
|
|
|
|
show_custom_settings : bpy.props.BoolProperty(
|
|
|
|
name='Settings',
|
|
|
|
default=False)
|
|
|
|
|
|
|
|
base_path : bpy.props.StringProperty(
|
|
|
|
name='Custom base path',
|
|
|
|
default='',
|
|
|
|
description='Set the base path of created file_output (not if already exists)')
|
|
|
|
|
|
|
|
file_format : bpy.props.EnumProperty(
|
|
|
|
name='Output Format',
|
|
|
|
default='NONE',
|
|
|
|
items=(
|
|
|
|
('NONE', 'Default', 'Use default settings'),
|
|
|
|
('OPEN_EXR_MULTILAYER', 'OpenEXR MultiLayer', 'Output image in multilayer OpenEXR format'),
|
|
|
|
('OPEN_EXR', 'OpenEXR', 'Output image in OpenEXR format'),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
exr_codec : bpy.props.EnumProperty(
|
|
|
|
name='Codec',
|
|
|
|
default='PIZ',
|
|
|
|
description='Codec settings for OpenEXR',
|
|
|
|
items=(
|
|
|
|
('PIZ', 'PIZ (lossless)', ''),
|
|
|
|
('ZIP', 'ZIP (lossless)', ''),
|
|
|
|
('RLE', 'RLE (lossless)', ''),
|
|
|
|
('ZIPS', 'ZIPS (lossless)', ''),
|
|
|
|
('PXR24', 'Pxr24 (lossy)', ''),
|
|
|
|
('B44', 'B44 (lossy)', ''),
|
|
|
|
('B44A', 'B44A (lossy)', ''),
|
|
|
|
('DWAA', 'DWAA (lossy)', ''),
|
|
|
|
('DWAB', 'DWAB (lossy)', ''),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
color_depth : bpy.props.EnumProperty(
|
|
|
|
name='Color Depth',
|
|
|
|
default='16',
|
|
|
|
description='Bit depth per channel',
|
|
|
|
items=(
|
|
|
|
# ('8', '8', '8-bit color channels'),
|
|
|
|
# ('10', '10', '10-bit color channels'),
|
|
|
|
# ('12', '12', '12-bit color channels'),
|
|
|
|
('16', '16 (Half)', '16-bit color channels'),
|
|
|
|
('32', '32 (Full)', '32-bit color channels'),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
def invoke(self, context, event):
|
|
|
|
self.socket_collection.clear()
|
|
|
|
if event.ctrl:
|
|
|
|
# Direct connect, do not use any options
|
|
|
|
self.base_path = ''
|
|
|
|
return self.execute(context)
|
|
|
|
|
|
|
|
selected = [n for n in context.scene.node_tree.nodes if n.select and n.type != 'OUTPUT_FILE']
|
|
|
|
if not selected:
|
|
|
|
self.report({'ERROR'}, 'No render layer nodes selected')
|
|
|
|
return {'CANCELLED'}
|
|
|
|
for n in selected:
|
|
|
|
for o in n.outputs:
|
|
|
|
if o.is_unavailable:
|
|
|
|
continue
|
|
|
|
item = self.socket_collection.add()
|
|
|
|
item.node_name = n.name
|
2024-06-24 16:10:44 +02:00
|
|
|
item.socket_name = item.name = o.name
|
|
|
|
## TODO: rename item.name according to tamplate pairs in preferences (to add later)
|
2024-04-18 15:11:59 +02:00
|
|
|
if o.is_linked:
|
|
|
|
item.is_linked = True
|
|
|
|
item.select = False
|
|
|
|
|
|
|
|
return context.window_manager.invoke_props_dialog(self, width=500)
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
layout = self.layout
|
|
|
|
expand_icon = 'DISCLOSURE_TRI_DOWN' if self.show_custom_settings else 'DISCLOSURE_TRI_RIGHT'
|
|
|
|
layout.prop(self, 'show_custom_settings', emboss=False, icon=expand_icon)
|
|
|
|
## Settings
|
|
|
|
if self.show_custom_settings:
|
|
|
|
layout.use_property_split = True
|
|
|
|
layout.prop(self, 'base_path')
|
|
|
|
col = layout.column()
|
|
|
|
col.prop(self, 'file_format')
|
|
|
|
col.prop(self, 'exr_codec')
|
|
|
|
col.row().prop(self, 'color_depth', expand=True)
|
|
|
|
|
|
|
|
## Node Sockets
|
|
|
|
layout.use_property_split = False
|
|
|
|
col = layout.column()
|
|
|
|
current_node_name = ''
|
|
|
|
for item in self.socket_collection:
|
|
|
|
if item.node_name != current_node_name:
|
|
|
|
current_node_name = item.node_name
|
|
|
|
col.separator()
|
|
|
|
col.label(text=item.node_name, icon='NODE_SEL')
|
2024-06-24 16:10:44 +02:00
|
|
|
|
2024-04-18 15:11:59 +02:00
|
|
|
row = col.row()
|
|
|
|
if item.is_linked:
|
|
|
|
row.label(text='', icon='LINKED') # NODETREE
|
|
|
|
else:
|
|
|
|
row.label(text='', icon='BLANK1')
|
|
|
|
row.prop(item, 'select', text='')
|
|
|
|
|
2024-06-24 16:10:44 +02:00
|
|
|
display_name = item.socket_name
|
2024-04-18 15:11:59 +02:00
|
|
|
if 'crypto' in display_name.lower():
|
|
|
|
display_name = f'{display_name} (-> separate 32bit output node)'
|
|
|
|
row.label(text=display_name)
|
2024-06-24 16:10:44 +02:00
|
|
|
row.label(text='', icon='RIGHTARROW')
|
|
|
|
row.prop(item, 'name', text='')
|
2024-04-18 15:11:59 +02:00
|
|
|
|
2024-01-16 16:55:07 +01:00
|
|
|
def execute(self, context):
|
2024-04-18 15:11:59 +02:00
|
|
|
|
|
|
|
# Build exclude dict from selection
|
|
|
|
excludes = {}
|
2024-06-24 16:10:44 +02:00
|
|
|
remap_names = {}
|
2024-04-18 15:11:59 +02:00
|
|
|
if len(self.socket_collection):
|
|
|
|
for item in self.socket_collection:
|
|
|
|
if not item.select:
|
|
|
|
# All deselected goes to exclude with {node_name: [socket1, ...]}
|
|
|
|
excludes.setdefault(item.node_name, []).append(item.name)
|
2024-06-24 16:10:44 +02:00
|
|
|
elif item.socket_name != item.name:
|
|
|
|
remap_names[item.socket_name] = item.name
|
|
|
|
|
2024-04-18 15:11:59 +02:00
|
|
|
## Handle default file format
|
|
|
|
file_ext = self.file_format
|
|
|
|
if self.file_format == 'NONE':
|
|
|
|
env_file_format = os.environ.get('FILE_FORMAT')
|
|
|
|
file_ext = env_file_format if env_file_format else 'OPEN_EXR_MULTILAYER'
|
2024-06-24 16:10:44 +02:00
|
|
|
|
2024-04-18 15:11:59 +02:00
|
|
|
file_format = {
|
|
|
|
'file_format' : file_ext,
|
|
|
|
'exr_codec' : self.exr_codec,
|
|
|
|
'color_depth' : self.color_depth,
|
|
|
|
}
|
|
|
|
|
2024-01-16 16:55:07 +01:00
|
|
|
scn = context.scene
|
|
|
|
nodes = scn.node_tree.nodes
|
|
|
|
selected = [n for n in nodes if n.select]
|
|
|
|
outfile = next((n for n in selected if n.type == 'OUTPUT_FILE'), None)
|
|
|
|
# Exclude output file from
|
|
|
|
selected = [n for n in selected if n.type != 'OUTPUT_FILE']
|
|
|
|
|
|
|
|
# fn.connect_to_file_output(selected, outfile)
|
|
|
|
for n in selected:
|
2024-06-24 16:10:44 +02:00
|
|
|
fn.connect_to_file_output(n, outfile, base_path=self.base_path, excludes=excludes, remap_names=remap_names, file_format=file_format)
|
2024-01-16 16:55:07 +01:00
|
|
|
return {"FINISHED"}
|
|
|
|
|
2021-09-08 18:29:10 +02:00
|
|
|
classes=(
|
|
|
|
GPEXP_OT_mute_toggle_output_nodes,
|
2021-09-21 18:23:25 +02:00
|
|
|
GPEXP_OT_set_output_node_format,
|
2021-09-22 12:06:40 +02:00
|
|
|
GPEXP_OT_number_outputs,
|
2021-09-23 19:14:48 +02:00
|
|
|
GPEXP_OT_enable_all_viewlayers,
|
|
|
|
GPEXP_OT_activate_only_selected_layers,
|
2021-10-25 16:02:11 +02:00
|
|
|
GPEXP_OT_reset_render_settings,
|
2024-04-18 15:11:59 +02:00
|
|
|
GPEXP_PG_selectable_prop,
|
2024-01-16 16:55:07 +01:00
|
|
|
GPEXP_OT_connect_selected_to_file_out,
|
2021-09-22 12:06:40 +02:00
|
|
|
# GPEXP_OT_normalize_outnames,
|
2021-09-08 18:29:10 +02:00
|
|
|
)
|
|
|
|
|
2023-01-18 14:28:27 +01:00
|
|
|
def register():
|
2021-09-08 18:29:10 +02:00
|
|
|
for cls in classes:
|
|
|
|
bpy.utils.register_class(cls)
|
|
|
|
|
|
|
|
def unregister():
|
|
|
|
for cls in reversed(classes):
|
|
|
|
bpy.utils.unregister_class(cls)
|