diff --git a/__init__.py b/__init__.py index c56266d..97535c0 100644 --- a/__init__.py +++ b/__init__.py @@ -2,7 +2,7 @@ "name": "Sequence Loader", "description": "Loader for meshio supported mesh files/ simulation sequences", "author": "Interactive Computer Graphics", - "version": (0, 3, 1), + "version": (0, 3, 2), "blender": (4, 0, 0), "warning": "", "support": "COMMUNITY", @@ -65,7 +65,8 @@ # BSEQ_OT_import_zip, # BSEQ_OT_delete_zips, # BSEQ_addon_preferences, - BSEQ_OT_load_all + BSEQ_OT_load_all, + BSEQ_OT_load_all_recursive ] def register(): diff --git a/bseq/__init__.py b/bseq/__init__.py index 114296c..17cb3bf 100644 --- a/bseq/__init__.py +++ b/bseq/__init__.py @@ -1,5 +1,5 @@ from bseq.utils import refresh_obj -from .operators import BSEQ_OT_load, BSEQ_OT_edit, BSEQ_OT_resetpt, BSEQ_OT_resetmesh, BSEQ_OT_resetins, BSEQ_OT_set_as_split_norm, BSEQ_OT_remove_split_norm, BSEQ_OT_disable_selected, BSEQ_OT_enable_selected, BSEQ_OT_refresh_seq, BSEQ_OT_disable_all, BSEQ_OT_enable_all, BSEQ_OT_refresh_sequences, BSEQ_OT_set_start_end_frames, BSEQ_OT_batch_sequences, BSEQ_PT_batch_sequences_settings, BSEQ_OT_meshio_object, BSEQ_OT_import_zip, BSEQ_OT_delete_zips, BSEQ_addon_preferences, BSEQ_OT_load_all +from .operators import BSEQ_OT_load, BSEQ_OT_edit, BSEQ_OT_resetpt, BSEQ_OT_resetmesh, BSEQ_OT_resetins, BSEQ_OT_set_as_split_norm, BSEQ_OT_remove_split_norm, BSEQ_OT_disable_selected, BSEQ_OT_enable_selected, BSEQ_OT_refresh_seq, BSEQ_OT_disable_all, BSEQ_OT_enable_all, BSEQ_OT_refresh_sequences, BSEQ_OT_set_start_end_frames, BSEQ_OT_batch_sequences, BSEQ_PT_batch_sequences_settings, BSEQ_OT_meshio_object, BSEQ_OT_import_zip, BSEQ_OT_delete_zips, BSEQ_addon_preferences, BSEQ_OT_load_all, BSEQ_OT_load_all_recursive from .properties import BSEQ_scene_property, BSEQ_obj_property, BSEQ_mesh_property from .panels import BSEQ_UL_Obj_List, BSEQ_List_Panel, BSEQ_Settings, BSEQ_PT_Import, BSEQ_PT_Import_Child1, BSEQ_PT_Import_Child2, BSEQ_Globals_Panel, BSEQ_Advanced_Panel, BSEQ_Templates, BSEQ_UL_Att_List, draw_template from .messenger import subscribe_to_selected, unsubscribe_to_selected @@ -62,5 +62,6 @@ def BSEQ_initialize(scene): "BSEQ_OT_import_zip", "BSEQ_OT_delete_zips", "BSEQ_addon_preferences", - "BSEQ_OT_load_all" + "BSEQ_OT_load_all", + "BSEQ_OT_load_all_recursive" ] diff --git a/bseq/operators.py b/bseq/operators.py index a7c7582..525f407 100644 --- a/bseq/operators.py +++ b/bseq/operators.py @@ -6,6 +6,7 @@ from .utils import refresh_obj, show_message_box, get_relative_path from .importer import create_obj, create_meshio_obj import numpy as np +import os addon_name = "blendersequenceloader" @@ -541,6 +542,52 @@ def execute(self, context): for s in seqs: create_obj_wrapper(s, importer_prop) return {'FINISHED'} + +class BSEQ_OT_load_all_recursive(bpy.types.Operator): + """Load all sequences from selected folder recursively""" + bl_idname = "bseq.load_all_recursive" + bl_label = "Load All Recursive" + bl_options = {'PRESET', 'UNDO'} + + def execute(self, context): + importer_prop = context.scene.BSEQ + + if importer_prop.use_relative and not bpy.data.is_saved: + return relative_path_error() + + root_dir = importer_prop.path + # Recurse through subdirectories + for root, dirs, files in os.walk(bpy.path.abspath(root_dir)): + for dir in sorted(dirs): + # Process subdirectory + subdirectory = os.path.join(root, dir) + + seqs = fileseq.findSequencesOnDisk(subdirectory) + if len(seqs) == 0: + continue + + # Get list of directories from the root_dir to the current subdirectory + coll_list = bpy.path.relpath(subdirectory, start=root_dir).strip("//").split("/") + + # Get or create a nested collection starting from the root + last_coll = bpy.context.scene.collection + layer_collection = bpy.context.view_layer.layer_collection + for coll in coll_list: + cur_coll = bpy.data.collections.get(coll) if bpy.data.collections.get(coll) is not None else bpy.data.collections.new(coll) + if last_coll is not None and cur_coll.name not in last_coll.children: + last_coll.children.link(cur_coll) + layer_collection = layer_collection.children[cur_coll.name] + last_coll = cur_coll + + # Set the last collection as the active collection by recursing through the collections + context.view_layer.active_layer_collection = layer_collection + + # for s in seqs: + # print(s) + + for s in seqs: + create_obj_wrapper(s, importer_prop) + return {'FINISHED'} class BSEQ_OT_meshio_object(bpy.types.Operator, ImportHelper): diff --git a/bseq/panels.py b/bseq/panels.py index 598bd79..be1c142 100644 --- a/bseq/panels.py +++ b/bseq/panels.py @@ -292,11 +292,13 @@ def draw(self, context): col3.prop(importer_prop, "fileseq", text="") col4.operator("bseq.refreshall", text='', icon="FILE_REFRESH") - split = layout.split(factor=0.7) + split = layout.split(factor=0.5) col1 = split.column() col2 = split.column() col1.operator("sequence.load") - col2.operator("bseq.load_all") + row = col2.row() + row.operator("bseq.load_all") + row.operator("bseq.load_all_recursive") # split = layout.split(factor=0.5) # col1 = split.column() diff --git a/docs/conf.py b/docs/conf.py index acfaddc..bf923be 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -7,9 +7,9 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = 'blender-sequence-loader' -copyright = '2022, InteractiveComputerGraphics' +copyright = '2024, InteractiveComputerGraphics' author = 'InteractiveComputerGraphics' -release = '0.3.1' +release = '0.3.2' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration diff --git a/template/Comparison Render.py b/template/Comparison Render.py new file mode 100644 index 0000000..f8b3e57 --- /dev/null +++ b/template/Comparison Render.py @@ -0,0 +1,64 @@ +import bpy + +# Utilities for comparison rendering +def toggle_on_single(obj): + obj.hide_render = False + if isinstance(obj, bpy.types.Object) and obj.BSEQ.init: + obj.BSEQ.enabled = True + for child in obj.children: + toggle_on_single(child) + elif isinstance(obj, bpy.types.Collection): + for child in obj.objects: + toggle_on_single(child) + for child in obj.children: + toggle_on_single(child) + +def toggle_on(objs): + if type(objs) == list: + for obj in objs: + toggle_on_single(obj) + else: + toggle_on_single(objs) + +def toggle_off_single(obj): + obj.hide_render = True + if isinstance(obj, bpy.types.Object) and obj.BSEQ.init: + obj.BSEQ.enabled = False + for child in obj.children: + toggle_off_single(child) + elif isinstance(obj, bpy.types.Collection): + for child in obj.objects: + toggle_off_single(child) + for child in obj.children: + toggle_off_single(child) + +def toggle_off(objs): + if type(objs) == list: + for obj in objs: + toggle_off_single(obj) + else: + toggle_off_single(objs) + +def toggle_off_all(): + for obj in bpy.data.objects: + toggle_off_single(obj) + +def toggle_on_all(): + for obj in bpy.data.objects: + toggle_on_single(obj) + +# Declare which collection to render comparison for +# Change this to the name of the collection you want to render +comparison_collection = "Sequences" + +# Iterate over children in the collection +comparison_objects = list(bpy.data.collections[comparison_collection].children) + list(bpy.data.collections[comparison_collection].objects) +orig_path = bpy.context.scene.render.filepath +for obj in comparison_objects: + toggle_off(comparison_objects) + toggle_on(obj) + bpy.context.scene.render.filepath = f"{orig_path}/{obj.name}/" +# bpy.ops.render.render(write_still=True) + bpy.ops.render.render(animation=True) + +bpy.context.scene.render.filepath = orig_path \ No newline at end of file