diff --git a/CHANGELOG.md b/CHANGELOG.md index e9ee4e0..1e32151 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ Activate / deactivate layer opaticty according to prefix Activate / deactivate all masks using MA layers --> +0.5.6 + +- feat: `check layers` new `clear frame out of range` option (Disabled by default) +- ui: `check layers` show the number of targeted GP objects + 0.5.5 - ui: add a _total count_ output file to display when output is muted diff --git a/OP_setup_layers.py b/OP_setup_layers.py index 196732e..a57ea6d 100644 --- a/OP_setup_layers.py +++ b/OP_setup_layers.py @@ -31,9 +31,13 @@ class GPEXP_OT_layers_state(bpy.types.Operator): set_blend_mode : BoolProperty(name='Set Regular Blend Mode', default=True, description='Check/Set blend mode to regular') # , options={'SKIP_SAVE'} + clear_frame_out_of_range : BoolProperty(name='Clear Frames Out Of Scene Range', + default=False, description='Delete frames that before scene start and after scene end range\nWith a tolerance of one frame to avoid problem\nAffect all layers)') # , options={'SKIP_SAVE'} + opacity_exclude_list : StringProperty(name='Skip', default='MA', description='Skip prefixes from this list when changing opacity\nSeparate multiple value with a comma (ex: MA,IN)') # , options={'SKIP_SAVE'} + @classmethod def poll(cls, context): return context.object and context.object.type == 'GPENCIL' @@ -49,6 +53,13 @@ class GPEXP_OT_layers_state(bpy.types.Operator): def draw(self, context): layout = self.layout layout.prop(self, 'all_objects') + total = len([o for o in context.scene.objects if o.type == 'GPENCIL']) + + target_num = total if self.all_objects else len([o for o in context.selected_objects if o.type == 'GPENCIL']) + layout.label(text=f'{target_num}/{total} targeted GP') + + layout.separator() + layout.prop(self, 'clear_frame_out_of_range') layout.separator() layout.label(text='Set (or only perform a check):') row = layout.row() @@ -70,6 +81,12 @@ class GPEXP_OT_layers_state(bpy.types.Operator): for ob in pool: changes.append(f'>> {ob.name}') layers = ob.data.layers + + if self.clear_frame_out_of_range: + ct = fn.clear_frame_out_of_range(ob, verbose=False) + if ct: + changes.append(f'{ct} out of range frame deleted') + for l in layers: used = False @@ -117,6 +134,7 @@ class GPEXP_OT_layers_state(bpy.types.Operator): l.blend_mode = 'REGULAR' used = True + if used: print() if changes: diff --git a/__init__.py b/__init__.py index 2ab0547..c1c9bc0 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, 5, 5), + "version": (0, 5, 6), "blender": (2, 93, 0), "location": "View3D", "warning": "", diff --git a/fn.py b/fn.py index 661cbf4..e599000 100644 --- a/fn.py +++ b/fn.py @@ -1037,6 +1037,55 @@ def split_object_to_scene(): export_crop_to_json() +def clear_frame_out_of_range(o, verbose=False): + '''get a GP object + delete frame out of active scene range in all layers + return number of deleted frame + ''' + + scn = bpy.context.scene + ct = 0 + if o.type != 'GPENCIL': + print(f'{o.name} not a Gpencil') + return 0 + for l in o.data.layers: + first = True + for f in reversed(l.frames): + + # after + if f.frame_number > scn.frame_end + 1: + if verbose: + print(f'del: obj {o.name} > layer {l.info} > frame {f.frame_number}') + l.frames.remove(f) + ct += 1 + + # before + elif f.frame_number < scn.frame_start - 1: + if first: + first = False + continue + if verbose: + print(f'del: obj {o.name} > layer {l.info} > frame {f.frame_number}') + l.frames.remove(f) + ct += 1 + + # print('INFO', f'{ct} frames deleted') + return ct + + +## not used +def clear_frame_out_of_range_all_object(): + scene = bpy.context.scene + ct = 0 + for o in scene.objects: + if o.type == 'GPENCIL': + nct = clear_frame_out_of_range(o, verbose=False) + print(f'{o.name}: {nct} frames deleted') + ct += nct + print(f'{ct} gp frames deleted') + return ct + + """ def split_object_to_scene(): '''Create a new scene from selection'''