diff --git a/CHANGELOG.md b/CHANGELOG.md index c62a4e4..b7b290d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ Activate / deactivate layer opacity according to prefix Activate / deactivate all masks using MA layers --> +1.0.2 + +- added: GP object with name starting with `.` are ignored from "all objects" operation (renaming, numbering, sending to render scene) + - temporarily, layer named `note` (case insensitive) are ignored as well. This should be removed in later version to keep only dot exculsion rule. + 1.0.1 - fix: `Export Camera 2D Position To AE` file format not working on windows when export from linux (add CRLF terminator to generated text file) diff --git a/OP_add_layer.py b/OP_add_layer.py index 1d81001..77ee9ff 100644 --- a/OP_add_layer.py +++ b/OP_add_layer.py @@ -90,7 +90,7 @@ class GPEXP_OT_add_objects_to_render(bpy.types.Operator): # if not scn: # self.report({'ERROR'}, 'Could not found default scene') # return {"CANCELLED"} - export_gp_objects([o for o in context.scene.objects if o.type == 'GPENCIL' and not o.hide_get()], exclude_list=excludes, scene=scn) + export_gp_objects([o for o in context.scene.objects if o.type == 'GPENCIL' and not o.hide_get() and fn.is_valid_name(o.name)], exclude_list=excludes, scene=scn) return {"FINISHED"} diff --git a/OP_auto_build.py b/OP_auto_build.py new file mode 100644 index 0000000..43dc02e --- /dev/null +++ b/OP_auto_build.py @@ -0,0 +1,83 @@ +import bpy +from . import gen_vlayer, fn + +class GPEXP_OT_render_auto_build(bpy.types.Operator): + bl_idname = "gp_export.render_auto_build" + bl_label = "Auto-Build" + bl_description = "Trigger all operation to make build render scene with default settings" + bl_options = {"REGISTER"} + + @classmethod + def poll(cls, context): + return context.object and context.object.type == 'GPENCIL' + + # mode : bpy.props.StringProperty(options={'SKIP_SAVE'}) + + def execute(self, context): + ''' + ob = context.object + layer = ob.data.layers.active + if not layer: + self.report({'ERROR'}, 'No active layer') + return {"CANCELLED"} + + ct = 0 + # send scene ? + hided = 0 + for l in ob.data.layers: + if not l.select: + if not l.viewlayer_render: + l.viewlayer_render = fn.get_view_layer('exclude').name + continue + gen_vlayer.get_set_viewlayer_from_gp(ob, l) + + if l.hide: + hided += 1 + ct += 1 + + if hided: + self.report({'WARNING'}, f'{hided}/{ct} layers are hided !') + + else: + self.report({'INFO'}, f'{ct} layer(s) added to scene "Render"') + ''' + + ## TODO: add colors to layers (specified in ENV or hardcoded for now...) + ## Option: Maybe find a way to create a color from prefix hash ? (wlways give unique color with same prefix on other project!) + + + ## Trigger rename lowercase + bpy.ops.gp.lower_layers_name() + + ## Trigger renumber by distance + bpy.ops.gp.auto_number_object() + + ## Export layer infos ? + bpy.ops.gp.export_infos_for_compo() + + ## Send all GP to render scene + bpy.ops.gp.add_object_to_render(mode="ALL") + + ## Group all adjacent layer type + + ## Renumber File outputs + + ## Trigger check file before finishing ? + + + ## note: After all these operation, a ctrl+Z might crash + + return {"FINISHED"} + + +classes=( +GPEXP_OT_render_auto_build, +) + +def register(): + for cls in classes: + bpy.utils.register_class(cls) + +def unregister(): + for cls in reversed(classes): + bpy.utils.unregister_class(cls) \ No newline at end of file diff --git a/OP_setup_layers.py b/OP_setup_layers.py index b8bedc3..5718bcd 100644 --- a/OP_setup_layers.py +++ b/OP_setup_layers.py @@ -76,7 +76,7 @@ class GPEXP_OT_export_infos_for_compo(bpy.types.Operator): def execute(self, context): dic = {} - pool = [o for o in context.scene.objects if o.type == 'GPENCIL'] + pool = [o for o in context.scene.objects if o.type == 'GPENCIL' and fn.is_valid_name(o.name)] for o in pool: # if not o.visible_get(): # continue @@ -186,8 +186,6 @@ class GPEXP_OT_layers_state(bpy.types.Operator): return context.object and context.object.type == 'GPENCIL' def invoke(self, context, event): - if event.alt: - self.all_objects=True ## if no existing infos.json generated, call ops l_infos = Path(bpy.data.filepath).parent / 'render' / 'infos.json' @@ -219,7 +217,7 @@ class GPEXP_OT_layers_state(bpy.types.Operator): def execute(self, context): if self.all_objects: - pool = [o for o in context.scene.objects if o.type == 'GPENCIL'] + pool = [o for o in context.scene.objects if o.type == 'GPENCIL' and fn.is_valid_name(o.name)] else: pool = [o for o in context.selected_objects if o.type == 'GPENCIL'] # pool = [context.object] @@ -326,7 +324,7 @@ class GPEXP_OT_lower_layers_name(bpy.types.Operator): return context.object and context.object.type == 'GPENCIL' all_objects : BoolProperty(name='On All Object', - default=False, description='On All object, else use selected objects') # , options={'SKIP_SAVE'} + default=True, description='On All object, else use selected objects') # , options={'SKIP_SAVE'} object_name : BoolProperty(name='Normalize Object Name', default=True, description='Make the object name lowercase') # , options={'SKIP_SAVE'} @@ -349,7 +347,7 @@ class GPEXP_OT_lower_layers_name(bpy.types.Operator): layout = self.layout layout.prop(self, 'all_objects') if self.all_objects: - gp_ct = len([o for o in context.scene.objects if o.type == 'GPENCIL']) + gp_ct = len([o for o in context.scene.objects if o.type == 'GPENCIL' and fn.is_valid_name(o.name)]) else: gp_ct = len([o for o in context.selected_objects if o.type == 'GPENCIL']) @@ -367,7 +365,7 @@ class GPEXP_OT_lower_layers_name(bpy.types.Operator): def execute(self, context): if self.all_objects: - pool = [o for o in context.scene.objects if o.type == 'GPENCIL'] + pool = [o for o in context.scene.objects if o.type == 'GPENCIL' and fn.is_valid_name(o.name)] else: pool = [o for o in context.selected_objects if o.type == 'GPENCIL'] @@ -387,6 +385,7 @@ class GPEXP_OT_lower_layers_name(bpy.types.Operator): return {"FINISHED"} + class GPEXP_OT_auto_number_object(bpy.types.Operator): bl_idname = "gp.auto_number_object" bl_label = "Auto Number Object" @@ -398,7 +397,7 @@ class GPEXP_OT_auto_number_object(bpy.types.Operator): return context.object and context.object.type == 'GPENCIL' all_objects : BoolProperty(name='On All GP Object', - default=False, description='On All object, else use selected Grease Pencil objects') # , options={'SKIP_SAVE'} + default=True, description='On All object, else use selected Grease Pencil objects') # , options={'SKIP_SAVE'} rename_data : BoolProperty(name='Rename Gpencil Data', default=True, description='Rename Also the Grease Pencil data using same name as object') # , options={'SKIP_SAVE'} @@ -411,7 +410,7 @@ class GPEXP_OT_auto_number_object(bpy.types.Operator): if event.ctrl or self.delete: regex_num = re.compile(r'^(\d{3})_') ct = 0 - gps = [o for o in context.selected_objects if o.type == 'GPENCIL'] + gps = [o for o in context.selected_objects if o.type == 'GPENCIL' and fn.is_valid_name(o.name)] for o in gps: if regex_num.match(o.name): o.name = o.name[4:] @@ -426,7 +425,7 @@ class GPEXP_OT_auto_number_object(bpy.types.Operator): layout = self.layout layout.prop(self, 'all_objects') if self.all_objects: - gp_ct = len([o for o in context.scene.objects if o.type == 'GPENCIL']) + gp_ct = len([o for o in context.scene.objects if o.type == 'GPENCIL' and fn.is_valid_name(o.name)]) else: gp_ct = len([o for o in context.selected_objects if o.type == 'GPENCIL']) @@ -437,7 +436,7 @@ class GPEXP_OT_auto_number_object(bpy.types.Operator): def execute(self, context): if self.all_objects: - pool = [o for o in context.scene.objects if o.type == 'GPENCIL'] + pool = [o for o in context.scene.objects if o.type == 'GPENCIL' and fn.is_valid_name(o.name)] else: pool = [o for o in context.selected_objects if o.type == 'GPENCIL'] @@ -497,7 +496,7 @@ class GPEXP_OT_check_masks(bpy.types.Operator): # else: # pool = [o for o in context.selected_objects if o.type == 'GPENCIL'] changes = [] - pool = [o for o in context.scene.objects if o.type == 'GPENCIL'] + pool = [o for o in context.scene.objects if o.type == 'GPENCIL' and fn.is_valid_name(o.name)] for o in pool: for l in o.data.layers: if l.use_mask_layer: diff --git a/__init__.py b/__init__.py index 48673e3..a8d033b 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": (1, 0, 1), + "version": (1, 0, 2), "blender": (2, 93, 0), "location": "View3D", "warning": "", @@ -26,10 +26,31 @@ from . import OP_render_pdf from . import OP_export_to_ae from . import prefs from . import OP_setup_layers +from . import OP_auto_build from . import ui from .fn import scene_aa +bl_modules = ( + prefs, + OP_add_layer, + OP_clear, + OP_clean, + OP_connect_toggle, + OP_merge_layers, + OP_manage_outputs, + OP_scene_switch, + OP_crop_to_object, + OP_render_scenes, + OP_check_scene, + OP_post_render, + OP_render_pdf, + OP_export_to_ae, + OP_setup_layers, + OP_auto_build, + ui, +) + def update_scene_aa(context, scene): scene_aa(toggle=bpy.context.scene.use_aa) @@ -39,22 +60,9 @@ def register(): if bpy.app.background: return - prefs.register() - OP_add_layer.register() - OP_clear.register() - OP_clean.register() - OP_connect_toggle.register() - OP_merge_layers.register() - OP_manage_outputs.register() - OP_scene_switch.register() - OP_crop_to_object.register() - OP_render_scenes.register() - OP_check_scene.register() - OP_post_render.register() - OP_render_pdf.register() - OP_export_to_ae.register() - OP_setup_layers.register() - ui.register() + for mod in bl_modules: + mod.register() + # bpy.types.Scene.pgroup_name = bpy.props.PointerProperty(type = PROJ_PGT_settings) bpy.types.Scene.use_aa = bpy.props.BoolProperty( name='Use Native Anti Aliasing', @@ -69,22 +77,8 @@ def unregister(): if bpy.app.background: return - ui.unregister() - OP_setup_layers.unregister() - OP_check_scene.unregister() - OP_post_render.unregister() - OP_export_to_ae.unregister() - OP_render_pdf.unregister() - OP_render_scenes.unregister() - OP_crop_to_object.unregister() - OP_scene_switch.unregister() - OP_manage_outputs.unregister() - OP_merge_layers.unregister() - OP_connect_toggle.unregister() - OP_clean.unregister() - OP_clear.unregister() - OP_add_layer.unregister() - prefs.unregister() + for mod in reversed(bl_modules): + mod.unregister() del bpy.types.Scene.use_aa diff --git a/fn.py b/fn.py index 98e5e62..e7d7122 100644 --- a/fn.py +++ b/fn.py @@ -10,6 +10,23 @@ from time import time import json +### -- rules + +def is_valid_name(name): + '''return True if name correspond to a valid object + Don't start with a dot '.' + Is not "note" + ''' + + if name.startswith('.'): + return False + + ## FIXME: /!\ "note" as an exclude word is not good practice, temporary fix + if name.lower() == 'note': + return False + + return True + ### -- node basic def create_node(type, tree=None, **kargs): diff --git a/setup_elements.py b/setup_elements.py new file mode 100644 index 0000000..c080e24 --- /dev/null +++ b/setup_elements.py @@ -0,0 +1,67 @@ +info = { + 'icon': 'AUTO', + 'description': 'Setup things to make the precomp roll and rock' +} + +import bpy +import os, subprocess +import re, fnmatch, glob +from pathlib import Path +from os.path import join, dirname, basename, exists, isfile, isdir, splitext +from mathutils import Vector, Matrix +from math import radians, degrees + +C = bpy.context +D = bpy.data +scn = bpy.context.scene + +## v0.1 +## - Setup layer colors + +## TODO +# - Update libraries +# - Import Fx3D (or render from Fx3D file... maybe easier consifering the number) + + +## tried to make color that fit in White theme +## (difficult for readability since this text color is not the same) + + +prefix_color = { + # 'MA_': (0.09, 0.08, 0.46), # Vivid blue + 'MA_': (0.65, 0.4, 0.6), # Pink Light + + 'FX_': (0.12, 0.33, 0.58), # (0.3, 0.49, 0.63) # Blue Light + # 'CO_': (0.35, 0.0085, 0.25), + 'CO_': (0.5,0.1,0.5), # Clear Pink + # 'CU': (0.092070, 0.177356, 0.447959), # Blue clear + 'CU_': (0.02, 0.27, 0.27), # Indigo +} + +## UW -> TO (here used fo CU): (0.015996, 0.246201, 0.246201) # Indigo + +## invisible (close to violet light) in UW: (0.246201, 0.132868, 0.496933) + + +def set_layer_colors(): + for ob in scn.objects: + if ob.type != 'GPENCIL': + continue + for l in ob.data.layers: + # if l.info.startswith(prefix_color.keys()): + color = prefix_color.get(l.info[:3]) + if not color: + continue + print(l.info, '->', color) + l.channel_color = color + + C.preferences.edit.use_anim_channel_group_colors = True + + + + + +set_layer_colors() + +## update libraries +bpy.ops.gadget.update_libraries() \ No newline at end of file diff --git a/ui.py b/ui.py index 458797a..369709a 100644 --- a/ui.py +++ b/ui.py @@ -173,6 +173,9 @@ class GPEXP_PT_gp_dopesheet_ui(Panel): def draw(self, context): layout = self.layout + + ## TODO: add auto-build + # layout.operator('gp_export.render_auto_build') if context.object: layout.label(text=f'Object: {context.object.name}') if context.object.data.users > 1: @@ -203,7 +206,6 @@ class GPEXP_PT_gp_dopesheet_ui(Panel): row.operator('gp.merge_viewlayers_to_active', text=txt, icon='SELECT_EXTEND') row.enabled= ct > 1 - ## all and objects layout.separator()