fixes ui and mutiuser case
This commit is contained in:
		
							parent
							
								
									a3ab7644a7
								
							
						
					
					
						commit
						3a334404a2
					
				
							
								
								
									
										12
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@ -7,8 +7,20 @@ if objects has multiple user without being linked in render scene :
 | 
				
			|||||||
OR always duplicate (safe but heavy scenes...)
 | 
					OR always duplicate (safe but heavy scenes...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if duplicate, need to "connect" with namespace ('_duprender') or something
 | 
					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
 | 
					0.2.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- fix: scene world transfer
 | 
					- fix: scene world transfer
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
import bpy
 | 
					import bpy
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
from . import fn
 | 
					from . import fn
 | 
				
			||||||
 | 
					from . import gen_vlayer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def merge_layers(rlayers, obname=None, active=None, disconnect=True):
 | 
					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):
 | 
					    def execute(self, context):
 | 
				
			||||||
        # merge_selected_layers() # function to merge from GP dopesheet
 | 
					        # merge_selected_layers() # function to merge from GP dopesheet
 | 
				
			||||||
        ob = bpy.context.object
 | 
					        ob = bpy.context.object
 | 
				
			||||||
        layer_names = [l.info for l in ob.data.layers if l.select and not l.hide]
 | 
					        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(layer_names) < 2:
 | 
					        if len(layers) < 2:
 | 
				
			||||||
            self.report({'ERROR'}, f'Should select multiple layers for merging')
 | 
					            self.report({'ERROR'}, f'Should select multiple layers for merging')
 | 
				
			||||||
            return {"CANCELLED"}
 | 
					            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)
 | 
					        clean_ob_name = bpy.path.clean_name(ob.name)
 | 
				
			||||||
        rlayers = []
 | 
					        rlayers = []
 | 
				
			||||||
        for l in layer_names:
 | 
					        for l in layers:
 | 
				
			||||||
            ## identifier is clean_name(ob.name).layer_name
 | 
					            idname = f'{clean_ob_name} / {l.info}'
 | 
				
			||||||
            
 | 
					            rlayer = rl = None
 | 
				
			||||||
            idname = f'{clean_ob_name}.{l}'
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            # check the render layer that have a parent frame
 | 
					            # 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:
 | 
					            if not rlayer:
 | 
				
			||||||
                # send to function to generate the rlayer and connect
 | 
					                # send to function to generate the rlayer and connect
 | 
				
			||||||
                # rlayer = creation
 | 
					                _vl, rl = gen_vlayer.get_set_viewlayer_from_gp(ob, l)
 | 
				
			||||||
                continue
 | 
					 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
            rlayers.append(rlayer)
 | 
					            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(rl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        merge_layers(rlayers, disconnect=self.disconnect)
 | 
					        merge_layers(rlayers, disconnect=self.disconnect)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@ bl_info = {
 | 
				
			|||||||
    "name": "GP exporter",
 | 
					    "name": "GP exporter",
 | 
				
			||||||
    "description": "Organise export of gp layers through compositor output",
 | 
					    "description": "Organise export of gp layers through compositor output",
 | 
				
			||||||
    "author": "Samuel Bernou",
 | 
					    "author": "Samuel Bernou",
 | 
				
			||||||
    "version": (0, 2, 3),
 | 
					    "version": (0, 2, 5),
 | 
				
			||||||
    "blender": (2, 93, 0),
 | 
					    "blender": (2, 93, 0),
 | 
				
			||||||
    "location": "View3D",
 | 
					    "location": "View3D",
 | 
				
			||||||
    "warning": "",
 | 
					    "warning": "",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										5
									
								
								fn.py
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								fn.py
									
									
									
									
									
								
							@ -231,15 +231,16 @@ def rearrange_frames(node_tree):
 | 
				
			|||||||
    frames = [[f, v[0], v[1].y] for f, v in frame_d.items()] # [frame_node, real_loc, real dimensions]
 | 
					    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 = frames[0][1].y # upper node location.y
 | 
				
			||||||
 | 
					    # top = 0 #always start a 0
 | 
				
			||||||
    offset = 0
 | 
					    offset = 0
 | 
				
			||||||
    for f in frames:
 | 
					    for f in frames:
 | 
				
			||||||
        ## f[1] : real loc Vector
 | 
					        ## f[1] : real loc Vector
 | 
				
			||||||
        ## f[0] : frame
 | 
					        ## f[0] : frame
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ## move frame by offset needed (delta between real_loc and "fake" loc , minus offset)
 | 
					        ## 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
 | 
					        # f[0].location.y = f[1].y - top - offset
 | 
				
			||||||
        offset += f[2] + 300 # gap
 | 
					        offset += f[2] + 200 # gap
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        f[0].update()
 | 
					        f[0].update()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -217,7 +217,11 @@ def get_set_viewlayer_from_gp(ob, l, scene=None):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    in_rds = scene.collection.all_objects.get(ob.name)
 | 
					    in_rds = scene.collection.all_objects.get(ob.name)
 | 
				
			||||||
    if not in_rds:
 | 
					    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)
 | 
					        scene.collection.objects.link(ob)
 | 
				
			||||||
        ob.hide_viewport = ob.hide_render = False
 | 
					        ob.hide_viewport = ob.hide_render = False
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										48
									
								
								ui.py
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								ui.py
									
									
									
									
									
								
							@ -63,8 +63,8 @@ class GPEXP_PT_gp_node_ui(Panel):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        col=layout.column()
 | 
					        col=layout.column()
 | 
				
			||||||
        col.label(text='Delete Options:')
 | 
					        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 Framed Nodes')
 | 
				
			||||||
        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 & Delete Render Scene').mode = "COMPLETE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # layout.operator('gp.add_object_to_render', icon='RENDERLAYERS', text='Layer To Render').mode = 'ALL'
 | 
					        # 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):
 | 
					class GPEXP_PT_gp_dopesheet_ui(Panel):
 | 
				
			||||||
    bl_space_type = 'DOPESHEET_EDITOR'
 | 
					    bl_space_type = 'DOPESHEET_EDITOR'
 | 
				
			||||||
    bl_region_type = 'UI'
 | 
					    bl_region_type = 'UI'
 | 
				
			||||||
    # bl_category = "Item"
 | 
					    bl_category = "GP Render"
 | 
				
			||||||
    bl_parent_id='DOPESHEET_PT_gpencil_mode'
 | 
					    # bl_parent_id='DOPESHEET_PT_gpencil_mode'
 | 
				
			||||||
    bl_label = "Gpencil Render Manager"
 | 
					    bl_label = "Gpencil Render Manager"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
@ -85,7 +85,12 @@ class GPEXP_PT_gp_dopesheet_ui(Panel):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def draw(self, context):
 | 
					    def draw(self, context):
 | 
				
			||||||
        layout = self.layout
 | 
					        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
 | 
					        ## On layers
 | 
				
			||||||
        if context.object and context.object.type == 'GPENCIL':
 | 
					        if context.object and context.object.type == 'GPENCIL':
 | 
				
			||||||
@ -102,6 +107,34 @@ class GPEXP_PT_gp_dopesheet_ui(Panel):
 | 
				
			|||||||
        row.operator('gp.merge_selected_dopesheet_layers', text=txt, )
 | 
					        row.operator('gp.merge_selected_dopesheet_layers', text=txt, )
 | 
				
			||||||
        row.enabled= ct > 1
 | 
					        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):
 | 
					def manager_ui(self, context):
 | 
				
			||||||
    '''appended to DATA_PT_gpencil_layers'''
 | 
					    '''appended to DATA_PT_gpencil_layers'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -136,6 +169,7 @@ def manager_ui(self, context):
 | 
				
			|||||||
#-# REGISTER
 | 
					#-# REGISTER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
classes=(
 | 
					classes=(
 | 
				
			||||||
 | 
					GPEXP_MT_multi_user_doc,
 | 
				
			||||||
GPEXP_PT_gp_node_ui,
 | 
					GPEXP_PT_gp_node_ui,
 | 
				
			||||||
GPEXP_PT_gp_dopesheet_ui,
 | 
					GPEXP_PT_gp_dopesheet_ui,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -143,9 +177,9 @@ GPEXP_PT_gp_dopesheet_ui,
 | 
				
			|||||||
def register(): 
 | 
					def register(): 
 | 
				
			||||||
    for cls in classes:
 | 
					    for cls in classes:
 | 
				
			||||||
        bpy.utils.register_class(cls)
 | 
					        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():
 | 
					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):
 | 
					    for cls in reversed(classes):
 | 
				
			||||||
        bpy.utils.unregister_class(cls)
 | 
					        bpy.utils.unregister_class(cls)
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user