From 55f9248c6a0ba753cff607a44e30ffe41a192e1b Mon Sep 17 00:00:00 2001 From: Pullusb Date: Thu, 16 Dec 2021 19:10:00 +0100 Subject: [PATCH] Set composite output from fileout node 0.8.0 - feat: Select a file output node. Set active file slot path and settings to main Scene output. - Button in GP render panel with `Advanced` options active. - Or search operator label `Set Active File Output To Composite` - if Composite is already linked, pop-up ask if link should be replaced --- CHANGELOG.md | 6 ++++ OP_connect_toggle.py | 86 ++++++++++++++++++++++++++++++++++++++++++++ __init__.py | 2 +- fn.py | 38 ++++++++++++++++++++ ui.py | 3 +- 5 files changed, 133 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eadeb9..4edbe6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,12 @@ Activate / deactivate layer opaticty according to prefix Activate / deactivate all masks using MA layers --> +0.8.0 + +- feat: Select a file output node. Set active file slot path and settings to main Scene output. + - Button in GP render panel with `Advanced` options active. + - Or search operator label `Set Active File Output To Composite` + - if Composite is already linked, pop-up ask if link should be replaced 0.7.0 diff --git a/OP_connect_toggle.py b/OP_connect_toggle.py index fd2542c..b2dcfde 100644 --- a/OP_connect_toggle.py +++ b/OP_connect_toggle.py @@ -135,9 +135,95 @@ class GPEXP_OT_delete_render_layer(bpy.types.Operator): 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(): diff --git a/__init__.py b/__init__.py index af50b29..9536398 100644 --- a/__init__.py +++ b/__init__.py @@ -2,7 +2,7 @@ bl_info = { "name": "GP Render", "description": "Organise export of gp layers through compositor output", "author": "Samuel Bernou", - "version": (0, 7, 0), + "version": (0, 8, 0), "blender": (2, 93, 0), "location": "View3D", "warning": "", diff --git a/fn.py b/fn.py index 92456e9..0f5d95f 100644 --- a/fn.py +++ b/fn.py @@ -1,5 +1,6 @@ from typing import Coroutine import bpy +import os import re from mathutils import Vector from pathlib import Path @@ -1199,3 +1200,40 @@ def clear_frame_out_of_range_all_object(): ct += nct print(f'{ct} gp frames deleted') return ct + +def set_scene_output_from_active_fileout_item(): + scn = bpy.context.scene + rd = scn.render + ntree =scn.node_tree + fo = ntree.nodes.active + + if fo.type != 'OUTPUT_FILE': + return + sl = fo.file_slots[fo.active_input_index] + full_path = os.path.join(fo.base_path, sl.path) + + rd.filepath = full_path + + fmt = fo.format if sl.use_node_format else sl.format + ## set those attr first to avoid error settings other attributes in next loop + rd.image_settings.file_format = fmt.file_format + rd.image_settings.color_mode = fmt.color_mode + rd.image_settings.color_depth = fmt.color_depth if fmt.color_depth else 8 # Force set since Sometimes it's weirdly set to "" (not in enum choice) + + excluded = ['file_format', 'color_mode', 'color_depth', + 'view_settings', 'views_format'] + + ''' ## all attrs + # 'cineon_black', 'cineon_gamma', 'cineon_white', + # 'color_depth', 'color_mode', 'compression', 'display_settings', + # 'exr_codec', 'file_format', 'jpeg2k_codec', 'quality', + # 'rna_type', 'stereo_3d_format', 'tiff_codec', 'use_cineon_log', + # 'use_jpeg2k_cinema_48', 'use_jpeg2k_cinema_preset', 'use_jpeg2k_ycc', + # 'use_preview', 'use_zbuffer'] + ''' + + for attr in dir(fmt): + if attr.startswith('__') or attr.startswith('bl_') or attr in excluded: + continue + if hasattr(scn.render.image_settings, attr) and not scn.render.image_settings.is_property_readonly(attr): + setattr(scn.render.image_settings, attr, getattr(fmt, attr)) \ No newline at end of file diff --git a/ui.py b/ui.py index ba86d0b..ea72717 100644 --- a/ui.py +++ b/ui.py @@ -120,8 +120,9 @@ class GPEXP_PT_gp_node_ui(Panel): if advanced: subcol.operator('gp.set_output_node_format', icon='OUTPUT', text='Copy Active Output Format') + subcol.operator('gp.set_active_fileout_to_compout', icon='OUTPUT', text='Active Slot to Composite') - + layout.separator() col=layout.column()