From 3a334404a2b16db44d157b2c551230b4c5d4f8c4 Mon Sep 17 00:00:00 2001 From: Pullusb Date: Thu, 16 Sep 2021 00:19:57 +0200 Subject: [PATCH] fixes ui and mutiuser case --- CHANGELOG.md | 12 +++++++++++ OP_merge_layers.py | 39 +++++++++++++++++++++++++----------- __init__.py | 2 +- fn.py | 7 ++++--- gen_vlayer.py | 6 +++++- ui.py | 50 ++++++++++++++++++++++++++++++++++++++-------- 6 files changed, 91 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efed1bb..1c8b003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,20 @@ if objects has multiple user without being linked in render scene : OR always duplicate (safe but heavy scenes...) if duplicate, need to "connect" with namespace ('_duprender') or something + +Activate / deactivate layer opaticty according to prefix +Activate / deactivate all masks using MA layers --> +0.2.5 + +- ui: removed menu above layer stack +- ui: All function in gp dopesheet new tab GP Render +- fix: node rearrange +- fix: merge from dopesheet +- feat: merge can also create the Render scene +- feat: multi-user warning with mini tutorial procedure + 0.2.4 - fix: scene world transfer diff --git a/OP_merge_layers.py b/OP_merge_layers.py index e5174a8..6be2529 100644 --- a/OP_merge_layers.py +++ b/OP_merge_layers.py @@ -1,6 +1,7 @@ import bpy import re from . import fn +from . import gen_vlayer def merge_layers(rlayers, obname=None, active=None, disconnect=True): @@ -120,9 +121,13 @@ class GPEXP_OT_merge_selected_dopesheet_layers(bpy.types.Operator): def execute(self, context): # merge_selected_layers() # function to merge from GP dopesheet ob = bpy.context.object - layer_names = [l.info for l in ob.data.layers if l.select and not l.hide] - - if len(layer_names) < 2: + layers = [l for l in ob.data.layers if l.select and not l.hide] + act = ob.data.layers.active + if not act: + self.report({'ERROR'}, f'An active layer is needed to set merge output name') + return {"CANCELLED"} + + if len(layers) < 2: self.report({'ERROR'}, f'Should select multiple layers for merging') return {"CANCELLED"} @@ -132,19 +137,29 @@ class GPEXP_OT_merge_selected_dopesheet_layers(bpy.types.Operator): clean_ob_name = bpy.path.clean_name(ob.name) rlayers = [] - for l in layer_names: - ## identifier is clean_name(ob.name).layer_name - - idname = f'{clean_ob_name}.{l}' - + for l in layers: + idname = f'{clean_ob_name} / {l.info}' + rlayer = rl = None # check the render layer that have a parent frame - rlayer = [n for n in nodes if n.type == 'R_LAYERS' and n.layer == idname and n.parent] + if not render: + _vl, rl = gen_vlayer.get_set_viewlayer_from_gp(ob, l) + render = bpy.data.scenes.get('Render') + nodes = render.node_tree.nodes + + if not rl: + rlayer = [n for n in nodes if n.type == 'R_LAYERS' and n.layer == idname and n.parent] if not rlayer: # send to function to generate the rlayer and connect - # rlayer = creation - continue + _vl, rl = gen_vlayer.get_set_viewlayer_from_gp(ob, l) + + else: + rlayer.sort(key=lambda n: n.location.y, reverse=True) + rl = rlayer[0] + + if act == l: + nodes.active = rl # make it active so the merge use this one - rlayers.append(rlayer) + rlayers.append(rl) merge_layers(rlayers, disconnect=self.disconnect) diff --git a/__init__.py b/__init__.py index 0daf356..0a501d6 100644 --- a/__init__.py +++ b/__init__.py @@ -2,7 +2,7 @@ bl_info = { "name": "GP exporter", "description": "Organise export of gp layers through compositor output", "author": "Samuel Bernou", - "version": (0, 2, 3), + "version": (0, 2, 5), "blender": (2, 93, 0), "location": "View3D", "warning": "", diff --git a/fn.py b/fn.py index 598c5ed..02c50d0 100644 --- a/fn.py +++ b/fn.py @@ -229,17 +229,18 @@ def rearrange_frames(node_tree): ## order the dict by frame.y location frame_d = {key: value for key, value in sorted(frame_d.items(), key=lambda pair: pair[1][0].y - pair[1][1].y, reverse=True)} frames = [[f, v[0], v[1].y] for f, v in frame_d.items()] # [frame_node, real_loc, real dimensions] - + top = frames[0][1].y # upper node location.y + # top = 0 #always start a 0 offset = 0 for f in frames: ## f[1] : real loc Vector ## f[0] : frame ## move frame by offset needed (delta between real_loc and "fake" loc , minus offset) - f[0].location.y = (f[1].y - f[0].location.y) - top - offset + 40 # + 40 to avoid offset when recalculating from 0 top + f[0].location.y = (f[1].y - f[0].location.y) - offset # avoid offset when recalculating from 0 top # f[0].location.y = f[1].y - top - offset - offset += f[2] + 300 # gap + offset += f[2] + 200 # gap f[0].update() diff --git a/gen_vlayer.py b/gen_vlayer.py index 9c0a192..e10d1be 100644 --- a/gen_vlayer.py +++ b/gen_vlayer.py @@ -217,7 +217,11 @@ def get_set_viewlayer_from_gp(ob, l, scene=None): in_rds = scene.collection.all_objects.get(ob.name) if not in_rds: - # TODO : link with a ob.data copy if its a multiuser object ! + # TODO : ? duplicate the object with name with a specific suffix '_renderdupe' to still parse it ? + ## make single user if its a multiuser object ? maybe let the user do it + if ob.data.users > 1: + print(f'/!!\ {ob.name} data has multiple users ! ({ob.data.users})') + # ob.data = ob.data.copy() # create duplicate (this will also affect the one in original scene !!!) scene.collection.objects.link(ob) ob.hide_viewport = ob.hide_render = False diff --git a/ui.py b/ui.py index 42a9764..21a4125 100644 --- a/ui.py +++ b/ui.py @@ -63,8 +63,8 @@ class GPEXP_PT_gp_node_ui(Panel): col=layout.column() col.label(text='Delete Options:') - col.operator('gp.clear_render_tree', icon='X', text='Clear Render Tree') - col.operator('gp.clear_render_tree', icon='X', text='Clear Delete Render Scene').mode = "COMPLETE" + col.operator('gp.clear_render_tree', icon='X', text='Clear Framed Nodes') + col.operator('gp.clear_render_tree', icon='X', text='Clear & Delete Render Scene').mode = "COMPLETE" # layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='Layer To Render').mode = 'ALL' @@ -75,8 +75,8 @@ class GPEXP_PT_gp_node_ui(Panel): class GPEXP_PT_gp_dopesheet_ui(Panel): bl_space_type = 'DOPESHEET_EDITOR' bl_region_type = 'UI' - # bl_category = "Item" - bl_parent_id='DOPESHEET_PT_gpencil_mode' + bl_category = "GP Render" + # bl_parent_id='DOPESHEET_PT_gpencil_mode' bl_label = "Gpencil Render Manager" @classmethod @@ -85,8 +85,13 @@ class GPEXP_PT_gp_dopesheet_ui(Panel): def draw(self, context): layout = self.layout - layout.label(text=context.object.name) - + if context.object: + layout.label(text=context.object.name) + if context.object.data.users > 1: + row = layout.row() + row.label(text=f'Multiple users ({context.object.data.users})', icon='ERROR') + row.operator("wm.call_menu", text="", icon='QUESTION').name = "GPEXP_MT_multi_user_doc" + ## On layers if context.object and context.object.type == 'GPENCIL': txt = f'{len([l for l in context.object.data.layers if l.select])} Layer(s) To Render' @@ -102,6 +107,34 @@ class GPEXP_PT_gp_dopesheet_ui(Panel): row.operator('gp.merge_selected_dopesheet_layers', text=txt, ) row.enabled= ct > 1 + ## all and objects + if context.scene.name != 'Render': + txt = f'{len([o for o in context.selected_objects if o.type == "GPENCIL" and o.select_get()])} Selected Object(s) To Render' + layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text=txt).mode='SELECTED' + layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='All GP at once').mode='ALL' + + +class GPEXP_MT_multi_user_doc(bpy.types.Menu): + # bl_idname = "OBJECT_MT_custom_menu" + bl_label = "Case of multiuser objects" + + def draw(self, context): + layout = self.layout + # call another menu + #layout.operator("wm.call_menu", text="Unwrap").name = "VIEW3D_MT_uv_map" + #**Behavior from context mode** + col = layout.column() + col.label(text='Multi user data will be rendered all together on last generated viewlayers.', icon='INFO') + col.label(text='Make them single user if needed to render separately.') + # col.label(text='Select objects > call search pop-up (F3) > "Make single user" > tick "object data" > ok') + col.label(text='Procedure:') + + col.label(text='- select concerned objects') + col.label(text='- call search pop-up (F3)') + col.label(text='- search "Make single user"') + col.label(text='- tick only "object data"') + +## not registered for now (better to place render menu in GP dopesheet) def manager_ui(self, context): '''appended to DATA_PT_gpencil_layers''' @@ -136,6 +169,7 @@ def manager_ui(self, context): #-# REGISTER classes=( +GPEXP_MT_multi_user_doc, GPEXP_PT_gp_node_ui, GPEXP_PT_gp_dopesheet_ui, ) @@ -143,9 +177,9 @@ GPEXP_PT_gp_dopesheet_ui, def register(): for cls in classes: bpy.utils.register_class(cls) - bpy.types.DATA_PT_gpencil_layers.prepend(manager_ui) + # bpy.types.DATA_PT_gpencil_layers.prepend(manager_ui) def unregister(): - bpy.types.DATA_PT_gpencil_layers.remove(manager_ui) + # bpy.types.DATA_PT_gpencil_layers.remove(manager_ui) for cls in reversed(classes): bpy.utils.unregister_class(cls) \ No newline at end of file