Skip to content

Commit

Permalink
New Extension Spec Compatibility and Usability Improvements (#36)
Browse files Browse the repository at this point in the history
* improve recursive import

by default it will now detect common prefixes and eliminate them. in the future it might be interesting to have an option to keep prefixes and simply use blenders naming to create a new one with an incremented name.

* show hidden option that changes the relative root path

* add blender manifest for 4.2 marketplace support

* change to relative imports to not make blender angry from changing sys.path

* update for new spec

* change maintainer
  • Loading branch information
digitalillusions authored Nov 20, 2024
1 parent d89c62d commit 46044aa
Show file tree
Hide file tree
Showing 15 changed files with 147 additions and 39 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ __pycache__/
.DS_Store
.vscode/
*.zip
*.whl

# the following ignores are used to ignore the local softlink files
# the extern folder won't be affected by this
Expand All @@ -10,4 +11,4 @@ meshio
future
fileseq

docs/_build/*
docs/_build/*
39 changes: 14 additions & 25 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,24 @@
bl_info = {
"name": "Sequence Loader",
"description": "Loader for meshio supported mesh files/ simulation sequences",
"author": "Interactive Computer Graphics",
"version": (0, 3, 2),
"blender": (4, 0, 0),
"warning": "",
"support": "COMMUNITY",
"category": "Import-Export",
}

import bpy
import os
import sys

current_folder = os.path.dirname(os.path.abspath(__file__))
if current_folder not in sys.path:
sys.path.append(current_folder)
# add paths of external libraries to sys.path
if os.path.exists(os.path.join(current_folder, "extern")):
external_libs = ["fileseq/src", "meshio/src", "python-future/src", "rich"]
for lib in external_libs:
lib_path = os.path.join(current_folder, "extern", lib)
if lib_path not in sys.path:
sys.path.append(lib_path)
# current_folder = os.path.dirname(os.path.abspath(__file__))
# if current_folder not in sys.path:
# sys.path.append(current_folder)
# # add paths of external libraries to sys.path
# if os.path.exists(os.path.join(current_folder, "extern")):
# external_libs = ["fileseq/src", "meshio/src", "python-future/src", "rich"]
# for lib in external_libs:
# lib_path = os.path.join(current_folder, "extern", lib)
# if lib_path not in sys.path:
# sys.path.append(lib_path)


if bpy.context.preferences.filepaths.use_relative_paths == True:
bpy.context.preferences.filepaths.use_relative_paths = False
# if bpy.context.preferences.filepaths.use_relative_paths == True:
# bpy.context.preferences.filepaths.use_relative_paths = False

from bseq import *
from bseq.operators import menu_func_import, add_keymap, delete_keymap
from .bseq import *
from .bseq.operators import menu_func_import, add_keymap, delete_keymap

classes = [
BSEQ_obj_property,
Expand Down
80 changes: 80 additions & 0 deletions blender_manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
schema_version = "1.0.0"

# Example of manifest file for a Blender extension
# Change the values according to your extension
id = "sequence_loader"
version = "0.3.3"
name = "Blender Sequence Loader"
tagline = "Just-in-time loader for meshio-supported mesh file sequences"
maintainer = "Stefan Rhys Jeske <[email protected]>"
# Supported types: "add-on", "theme"
type = "add-on"

# # Optional: link to documentation, support, source files, etc
website = "https://github.com/InteractiveComputerGraphics/blender-sequence-loader"

# # Optional: tag list defined by Blender and server, see:
# # https://docs.blender.org/manual/en/dev/advanced/extensions/tags.html
tags = ["Animation", "Object"]

blender_version_min = "4.2.0"
# # Optional: Blender version that the extension does not support, earlier versions are supported.
# # This can be omitted and defined later on the extensions platform if an issue is found.
# blender_version_max = "5.1.0"

# License conforming to https://spdx.org/licenses/ (use "SPDX: prefix)
# https://docs.blender.org/manual/en/dev/advanced/extensions/licenses.html
license = [
"SPDX:MIT",
]
# # Optional: required by some licenses.
# copyright = [
# "2002-2024 Developer Name",
# "1998 Company Name",
# ]

# # Optional: list of supported platforms. If omitted, the extension will be available in all operating systems.
# platforms = ["windows-x64", "macos-arm64", "linux-x64"]
# # Other supported platforms: "windows-arm64", "macos-x64"

# # Optional: bundle 3rd party Python modules.
# # https://docs.blender.org/manual/en/dev/advanced/extensions/python_wheels.html
wheels = [
"./wheels/Fileseq-1.15.2-py3-none-any.whl",
"./wheels/future-0.18.3-py3-none-any.whl",
"./wheels/meshio-5.3.4-py3-none-any.whl",
"./wheels/rich-13.7.0-py3-none-any.whl",
]

# # Optional: add-ons can list which resources they will require:
# # * files (for access of any filesystem operations)
# # * network (for internet access)
# # * clipboard (to read and/or write the system clipboard)
# # * camera (to capture photos and videos)
# # * microphone (to capture audio)
# #
# # If using network, remember to also check `bpy.app.online_access`
# # https://docs.blender.org/manual/en/dev/advanced/extensions/addons.html#internet-access
# #
# # For each permission it is important to also specify the reason why it is required.
# # Keep this a single short sentence without a period (.) at the end.
# # For longer explanations use the documentation or detail page.
#
[permissions]
files = "Core functionality to load files from disk"

# # Optional: advanced build settings.
# # https://docs.blender.org/manual/en/dev/advanced/extensions/command_line_arguments.html#command-line-args-extension-build
[build]
# These are the default build excluded patterns.
# You only need to edit them if you want different options.
paths_exclude_pattern = [
"__pycache__/",
"/.git/",
"/*.zip",
"/extern/",
"/docs/",
"/images/",
"build_addon.py",
"download_wheels.sh"
]
7 changes: 4 additions & 3 deletions bseq/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from bseq.utils import refresh_obj
from .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, 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
import bpy
from bpy.app.handlers import persistent
from .importer import update_obj
from .globals import *

import bpy
from bpy.app.handlers import persistent


@persistent
def BSEQ_initialize(scene):
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion bseq/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from mathutils import Matrix
import time
# this import is not useless
import additional_file_formats
from .additional_file_formats import *

def extract_edges(cell: meshio.CellBlock):
if cell.type == "line":
Expand Down
6 changes: 4 additions & 2 deletions bseq/messenger.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ def selected_callback():
bpy.context.scene.BSEQ.edit_obj = bpy.context.active_object

def subscribe_to_selected():
import bseq
# import bseq
bseq = __loader__

# because current implementation may subscribe twice
# so clear once to avoid duplication
Expand All @@ -37,5 +38,6 @@ def subscribe_to_selected():


def unsubscribe_to_selected():
import bseq
# import bseq
bseq = __loader__
bpy.msgbus.clear_by_owner(bseq)
40 changes: 33 additions & 7 deletions bseq/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ def draw(self, context):
# layout.prop(importer_prop, "root_path", text="Root Directory")

class BSEQ_addon_preferences(bpy.types.AddonPreferences):
bl_idname = addon_name
bl_idname = __package__

zips_folder: bpy.props.StringProperty(
name="Zips Folder",
Expand Down Expand Up @@ -556,6 +556,9 @@ def execute(self, context):
return relative_path_error()

root_dir = importer_prop.path
root_coll = bpy.context.scene.collection
root_layer_collection = bpy.context.view_layer.layer_collection
unlinked_collections = []
# Recurse through subdirectories
for root, dirs, files in os.walk(bpy.path.abspath(root_dir)):
for dir in sorted(dirs):
Expand All @@ -570,14 +573,33 @@ def execute(self, context):
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
last_coll = root_coll
layer_collection = root_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:
# If it already exists and is not in the children of the last collection, then the prefix has changed
cur_coll = bpy.data.collections.get(coll)
if cur_coll is not None and last_coll is not None:
if cur_coll.name not in last_coll.children:
# Get the old parent of the existing collection and move the children to the old parent
parent = [c for c in bpy.data.collections if bpy.context.scene.user_of_id(cur_coll) and cur_coll.name in c.children]
if len(parent) > 0:
for child in cur_coll.children:
parent[0].children.link(child)
for obj in cur_coll.objects:
parent[0].objects.link(obj)
parent[0].children.unlink(cur_coll)
unlinked_collections.append(cur_coll)
else:
layer_collection = layer_collection.children[cur_coll.name]
last_coll = cur_coll


# If it was newly created, link it to the last collection
if cur_coll is None and last_coll is not None:
cur_coll = bpy.data.collections.new(coll)
last_coll.children.link(cur_coll)
layer_collection = layer_collection.children[cur_coll.name]
last_coll = 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
Expand All @@ -587,6 +609,10 @@ def execute(self, context):

for s in seqs:
create_obj_wrapper(s, importer_prop)

# Make sure unused datablocks are freed
for coll in unlinked_collections:
bpy.data.collections.remove(coll)
return {'FINISHED'}


Expand Down
5 changes: 5 additions & 0 deletions bseq/panels.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,11 @@ def draw(self, context):
col1.label(text="Relative Paths")
col2.prop(importer_prop, "use_relative", text="")

if importer_prop.use_relative:
col1.label(text="Relative Root")
col2.prop(importer_prop, "root_path", text="")


col1.label(text="Import Normals")
col2.prop(importer_prop, "use_imported_normals", text="")

Expand Down
4 changes: 4 additions & 0 deletions download_wheels.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pip wheel fileseq==1.15.2 -w ./wheels --no-deps
pip wheel meshio==5.3.4 -w ./wheels --no-deps
pip wheel future==0.18.3 -w ./wheels --no-deps
pip wheel rich==13.7.0 -w ./wheels --no-deps

0 comments on commit 46044aa

Please sign in to comment.