diff --git a/tools/blenvy/TODO.md b/tools/blenvy/TODO.md index 085e82d..33ee8e2 100644 --- a/tools/blenvy/TODO.md +++ b/tools/blenvy/TODO.md @@ -15,7 +15,7 @@ Auto export - [x] main/ library scene names - [x] paths -Data storage for custom properties: +- [ ] Data storage for custom properties: - for scenes (main scenes) - at scene level - for blueprints @@ -106,7 +106,8 @@ General issues: - [x] add ability to FORCE export specific blueprints & levels - [ ] undo after a save removes any saved "serialized scene" data ? DIG into this - [ ] handle scene renames between saves (breaks diffing) -- [ ] change scene selector to work on actual scenes aka to deal with renamed scenes +- [x] change scene selector to work on actual scenes aka to deal with renamed scenes + - [x] remove get_main_and_library_scenes as it should not be needed anymore - [x] fix asset file selection - [x] change "assets" tab to "levels"/worlds tab & modify UI accordingly - [ ] add option to 'split out' meshes from blueprints ? diff --git a/tools/blenvy/__init__.py b/tools/blenvy/__init__.py index 214a3b9..43b6309 100644 --- a/tools/blenvy/__init__.py +++ b/tools/blenvy/__init__.py @@ -50,9 +50,8 @@ from .blueprints.operators import OT_select_blueprint # blenvy core from .core.blenvy_manager import BlenvyManager from .core.operators import OT_switch_bevy_tooling -from .core.scene_helpers import (SceneSelector) from .core.ui.ui import (BLENVY_PT_SidePanel) -from .core.ui.scenes_list import SCENES_LIST_OT_actions, SCENE_UL_Blenvy +from .core.ui.scenes_list import SCENES_LIST_OT_actions from .core.ui.assets_folder_browser import OT_OpenAssetsFolderBrowser @@ -63,8 +62,6 @@ def glTF2_post_export_callback(data): classes = [ # common/core - SceneSelector, - SCENE_UL_Blenvy, SCENES_LIST_OT_actions, OT_OpenAssetsFolderBrowser, diff --git a/tools/blenvy/add_ons/auto_export/blueprints/get_blueprints_to_export.py b/tools/blenvy/add_ons/auto_export/blueprints/get_blueprints_to_export.py index 1306591..4efd0d0 100644 --- a/tools/blenvy/add_ons/auto_export/blueprints/get_blueprints_to_export.py +++ b/tools/blenvy/add_ons/auto_export/blueprints/get_blueprints_to_export.py @@ -1,5 +1,4 @@ -from blenvy.core.scene_helpers import get_main_and_library_scenes from blenvy.blueprints.blueprint_helpers import find_blueprints_not_on_disk @@ -13,7 +12,6 @@ def get_blueprints_to_export(changes_per_scene, changed_export_parameters, bluep change_detection = getattr(settings.auto_export, "change_detection") collection_instances_combine_mode = getattr(settings.auto_export, "collection_instances_combine_mode") - [main_scene_names, level_scenes, library_scene_names, library_scenes] = get_main_and_library_scenes(settings) internal_blueprints = blueprints_data.internal_blueprints blueprints_to_export = internal_blueprints # just for clarity @@ -28,7 +26,7 @@ def get_blueprints_to_export(changes_per_scene, changed_export_parameters, bluep # in your current Blender session for example) blueprints_not_on_disk = find_blueprints_not_on_disk(internal_blueprints, blueprints_path_full, export_gltf_extension) - for scene in library_scenes: + for scene in settings.library_scenes: if scene.name in changes_per_scene: changed_objects = list(changes_per_scene[scene.name].keys()) changed_blueprints = [blueprints_data.blueprints_from_objects[changed] for changed in changed_objects if changed in blueprints_data.blueprints_from_objects] diff --git a/tools/blenvy/add_ons/auto_export/common/auto_export.py b/tools/blenvy/add_ons/auto_export/common/auto_export.py index 9426995..e3bc8f0 100644 --- a/tools/blenvy/add_ons/auto_export/common/auto_export.py +++ b/tools/blenvy/add_ons/auto_export/common/auto_export.py @@ -3,7 +3,6 @@ import os import bpy import traceback -from blenvy.core.scene_helpers import get_main_and_library_scenes from blenvy.blueprints.blueprints_scan import blueprints_scan from blenvy.blueprints.blueprint_helpers import inject_export_path_into_internal_blueprints @@ -39,8 +38,6 @@ def auto_export(changes_per_scene, changed_export_parameters, settings): gltf_extension = '.glb' if gltf_extension == 'GLB' else '.gltf' settings.export_gltf_extension = gltf_extension - [main_scene_names, level_scenes, library_scene_names, library_scenes] = get_main_and_library_scenes(settings) - blueprints_data = bpy.context.window_manager.blueprints_registry.refresh_blueprints() #blueprints_data = bpy.context.window_manager.blueprints_registry.blueprints_data #print("blueprints_data", blueprints_data) @@ -58,7 +55,7 @@ def auto_export(changes_per_scene, changed_export_parameters, settings): if export_scene_settings: # inject/ update scene components - upsert_scene_components(level_scenes) + upsert_scene_components(settings.main_scenes) #inject/ update light shadow information for light in bpy.data.lights: enabled = 'true' if light.use_shadow else 'false' @@ -76,7 +73,7 @@ def auto_export(changes_per_scene, changed_export_parameters, settings): # since materials export adds components we need to call this before blueprints are exported # export materials & inject materials components into relevant objects if export_materials_library: - export_materials(blueprints_data.blueprint_names, library_scenes, settings) + export_materials(blueprints_data.blueprint_names, settings.library_scenes, settings) # update the list of tracked exports exports_total = len(blueprints_to_export) + len(main_scenes_to_export) + (1 if export_materials_library else 0) @@ -123,11 +120,11 @@ def auto_export(changes_per_scene, changed_export_parameters, settings): for obj in old_selections: obj.select_set(True) if export_materials_library: - cleanup_materials(blueprints_data.blueprint_names, library_scenes) + cleanup_materials(blueprints_data.blueprint_names, settings.library_scenes) else: - for scene_name in main_scene_names: - export_main_scene(bpy.data.scenes[scene_name], blend_file_path, settings, []) + for scene in settings.main_scenes: + export_main_scene(scene, blend_file_path, settings, []) @@ -141,9 +138,7 @@ def auto_export(changes_per_scene, changed_export_parameters, settings): finally: # FIXME: error handling ? also redundant - [main_scene_names, main_scenes, library_scene_names, library_scenes] = get_main_and_library_scenes(settings) - if export_scene_settings: # inject/ update scene components - remove_scene_components(main_scenes) + remove_scene_components(settings.main_scenes) diff --git a/tools/blenvy/add_ons/auto_export/levels/get_levels_to_export.py b/tools/blenvy/add_ons/auto_export/levels/get_levels_to_export.py index b50d45e..b5c629b 100644 --- a/tools/blenvy/add_ons/auto_export/levels/get_levels_to_export.py +++ b/tools/blenvy/add_ons/auto_export/levels/get_levels_to_export.py @@ -1,5 +1,4 @@ import bpy -from blenvy.core.scene_helpers import get_main_and_library_scenes from blenvy.blueprints.blueprint_helpers import check_if_blueprint_on_disk # IF collection_instances_combine_mode is not 'split' check for each scene if any object in changes_per_scene has an instance in the scene @@ -57,9 +56,8 @@ def should_level_be_exported(scene_name, changed_export_parameters, changes_per_ # this also takes the split/embed mode into account: if a collection instance changes AND embed is active, its container level/world should also be exported def get_levels_to_export(changes_per_scene, changed_export_parameters, blueprints_data, settings): - [main_scene_names, level_scenes, library_scene_names, library_scenes] = get_main_and_library_scenes(settings) # determine list of main scenes to export # we have more relaxed rules to determine if the main scenes have changed : any change is ok, (allows easier handling of changes, render settings etc) - main_scenes_to_export = [scene_name for scene_name in main_scene_names if should_level_be_exported(scene_name, changed_export_parameters, changes_per_scene, blueprints_data, settings)] + main_scenes_to_export = [scene_name for scene_name in settings.main_scenes_names if should_level_be_exported(scene_name, changed_export_parameters, changes_per_scene, blueprints_data, settings)] return (main_scenes_to_export) \ No newline at end of file diff --git a/tools/blenvy/assets/ui.py b/tools/blenvy/assets/ui.py index f98678c..f89ce22 100644 --- a/tools/blenvy/assets/ui.py +++ b/tools/blenvy/assets/ui.py @@ -131,9 +131,7 @@ class Blenvy_assets(bpy.types.Panel): settings = SimpleNamespace(**settings) if panel: - #print("dfs") - for scene_selector in blenvy.main_scenes: - scene = bpy.data.scenes[scene_selector.name] + for scene in blenvy.main_scenes: user_assets = get_user_assets(scene) row = panel.row() diff --git a/tools/blenvy/blueprints/blueprints_registry.py b/tools/blenvy/blueprints/blueprints_registry.py index bee3536..92a6203 100644 --- a/tools/blenvy/blueprints/blueprints_registry.py +++ b/tools/blenvy/blueprints/blueprints_registry.py @@ -8,7 +8,6 @@ from bpy_types import (PropertyGroup) from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty) from ..settings import load_settings -from ..core.scene_helpers import get_main_and_library_scenes from .blueprints_scan import blueprints_scan @@ -68,7 +67,6 @@ class BlueprintsRegistry(PropertyGroup): #print("titi", self) blenvy = bpy.context.window_manager.blenvy settings = blenvy - [main_scene_names, level_scenes, library_scene_names, library_scenes] = get_main_and_library_scenes(settings) - blueprints_data = blueprints_scan(level_scenes, library_scenes, settings) + blueprints_data = blueprints_scan(settings.main_scenes, settings.library_scenes, settings) self.blueprints_data = blueprints_data return blueprints_data diff --git a/tools/blenvy/core/blenvy_manager.py b/tools/blenvy/core/blenvy_manager.py index beae1f0..511bf68 100644 --- a/tools/blenvy/core/blenvy_manager.py +++ b/tools/blenvy/core/blenvy_manager.py @@ -2,12 +2,12 @@ import os import bpy from bpy_types import (PropertyGroup) from bpy.props import (BoolProperty, EnumProperty, PointerProperty, StringProperty, CollectionProperty, IntProperty) -from .scene_helpers import SceneSelector from ..settings import upsert_settings, load_settings, generate_complete_settings_dict import blenvy.add_ons.auto_export.settings as auto_export_settings import blenvy.add_ons.bevy_components.settings as component_settings + # list of settings we do NOT want to save settings_black_list = ['settings_save_enabled', 'main_scene_selector', 'main_scenes', 'main_scenes_index', 'library_scene_selector', 'library_scenes', 'library_scenes_index', #'project_root_path_full', 'assets_path_full', '' @@ -35,7 +35,10 @@ def update_mode(blenvy, context): def is_scene_already_in_use(self, scene): try: - return scene.name not in self.main_scenes and scene.name not in self.library_scenes + current_main_scene_names = list(map(lambda x: x.name, self.main_scenes)) + current_library_scene_names = list(map(lambda x: x.name, self.library_scenes)) + #print("scene ", scene.name, current_main_scene_names, current_library_scene_names) + return scene.name not in current_main_scene_names and scene.name not in current_library_scene_names except: return True @@ -117,14 +120,6 @@ class BlenvyManager(PropertyGroup): get=lambda self: os.path.abspath(os.path.join(os.path.dirname(bpy.data.filepath), self.project_root_path, self.assets_path, self.materials_path)) ) # type: ignore - main_scenes: CollectionProperty(name="main scenes", type=SceneSelector) # type: ignore - main_scenes_index: IntProperty(name = "Index for main scenes list", default = 0, update=update_scene_lists) # type: ignore - #main_scene_names = [] # FIXME: unsure - - library_scenes: CollectionProperty(name="library scenes", type=SceneSelector) # type: ignore - library_scenes_index: IntProperty(name = "Index for library scenes list", default = 0, update=update_scene_lists) # type: ignore - #library_scene_names = [] # FIXME: unsure - # sub ones auto_export: PointerProperty(type=auto_export_settings.AutoExportSettings) # type: ignore components: PointerProperty(type=component_settings.ComponentsSettings) # type: ignore @@ -132,6 +127,22 @@ class BlenvyManager(PropertyGroup): main_scene_selector: PointerProperty(type=bpy.types.Scene, name="main scene", description="main_scene_picker", poll=is_scene_already_in_use)# type: ignore library_scene_selector: PointerProperty(type=bpy.types.Scene, name="library scene", description="library_scene_picker", poll=is_scene_already_in_use)# type: ignore + @property + def main_scenes(self): + return [scene for scene in bpy.data.scenes if scene.blenvy_scene_type == 'Level'] + + @property + def main_scenes_names(self): + return [scene.name for scene in self.main_scenes] + + @property + def library_scenes(self): + return [scene for scene in bpy.data.scenes if scene.blenvy_scene_type == 'Library'] + + @property + def library_scenes_names(self): + return [scene.name for scene in self.library_scenes] + @classmethod def register(cls): bpy.types.WindowManager.blenvy = PointerProperty(type=BlenvyManager) @@ -139,6 +150,14 @@ class BlenvyManager(PropertyGroup): # unsure bpy.types.Collection.always_export = BoolProperty(default=False, description="always export this blueprint, regardless of changed status") # FIXME: not sure about this one bpy.types.Scene.always_export = BoolProperty(default=False, description="always export this blueprint, regardless of changed status") # FIXME: not sure about this one + bpy.types.Scene.blenvy_scene_type = EnumProperty( + items= ( + ('None', 'None', 'No blenvy type specified'), + ('Level', 'Level','Main/ Level scene'), + ('Library', 'Library', 'Library scene'), + ), + default='None' + ) @classmethod def unregister(cls): @@ -146,6 +165,7 @@ class BlenvyManager(PropertyGroup): del bpy.types.Collection.always_export del bpy.types.Scene.always_export + del bpy.types.Scene.blenvy_scene_type def load_settings(self): print("LOAD SETTINGS") @@ -153,14 +173,6 @@ class BlenvyManager(PropertyGroup): if settings is not None: if "mode" in settings: self.mode = settings["mode"] - if "main_scene_names" in settings: - for main_scene_name in settings["main_scene_names"]: - added = self.main_scenes.add() - added.name = main_scene_name - if "library_scene_names" in settings: - for main_scene_name in settings["library_scene_names"]: - added = self.library_scenes.add() - added.name = main_scene_name asset_path_names = ['project_root_path', 'assets_path', 'blueprints_path', 'levels_path', 'materials_path'] for asset_path_name in asset_path_names: diff --git a/tools/blenvy/core/scene_helpers.py b/tools/blenvy/core/scene_helpers.py index 5ee9aba..417ff44 100644 --- a/tools/blenvy/core/scene_helpers.py +++ b/tools/blenvy/core/scene_helpers.py @@ -1,29 +1,7 @@ import bpy +from bpy.props import (PointerProperty) from .object_makers import make_empty - -class SceneSelector(bpy.types.PropertyGroup): - name: bpy.props.StringProperty() # type: ignore - display: bpy.props.BoolProperty() # type: ignore - - -# convenience utility to get lists of scenes -def get_main_and_library_scenes(settings): - level_scene_names= getattr(settings, "main_scene_names", []) #list(map(lambda scene: scene.name, getattr(settings,"main_scenes"))) - library_scene_names = getattr(settings, "library_scene_names", []) #list(map(lambda scene: scene.name, getattr(settings,"library_scenes"))) - - level_scene_names= list(map(lambda scene: scene.name, getattr(settings,"main_scenes"))) - library_scene_names = list(map(lambda scene: scene.name, getattr(settings,"library_scenes"))) - - level_scene_names = list(filter(lambda name: name in bpy.data.scenes, level_scene_names)) - library_scene_names = list(filter(lambda name: name in bpy.data.scenes, library_scene_names)) - - level_scenes = list(map(lambda name: bpy.data.scenes[name], level_scene_names)) - library_scenes = list(map(lambda name: bpy.data.scenes[name], library_scene_names)) - - return [level_scene_names, level_scenes, library_scene_names, library_scenes] - - def add_scene_property(scene, scene_component_name, property_data, limit_to=None): root_collection = scene.collection scene_property = None diff --git a/tools/blenvy/core/ui/scenes_list.py b/tools/blenvy/core/ui/scenes_list.py index ea872fe..25bfecb 100644 --- a/tools/blenvy/core/ui/scenes_list.py +++ b/tools/blenvy/core/ui/scenes_list.py @@ -1,39 +1,6 @@ import bpy from bpy.types import Operator -class SCENE_UL_Blenvy(bpy.types.UIList): - # The draw_item function is called for each item of the collection that is visible in the list. - # data is the RNA object containing the collection, - # item is the current drawn item of the collection, - # icon is the "computed" icon for the item (as an integer, because some objects like materials or textures - # have custom icons ID, which are not available as enum items). - # active_data is the RNA object containing the active property for the collection (i.e. integer pointing to the - # active item of the collection). - # active_propname is the name of the active property (use 'getattr(active_data, active_propname)'). - # index is index of the current item in the collection. - # flt_flag is the result of the filtering process for this item. - # Note: as index and flt_flag are optional arguments, you do not have to use/declare them here if you don't - # need them. - def draw_item(self, context, layout, data, item, icon, active_data, active_propname): - ob = data - # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code. - if self.layout_type in {'DEFAULT', 'COMPACT'}: - # You should always start your row layout by a label (icon + text), or a non-embossed text field, - # this will also make the row easily selectable in the list! The later also enables ctrl-click rename. - # We use icon_value of label, as our given icon is an integer value, not an enum ID. - # Note "data" names should never be translated! - #if ma: - # layout.prop(ma, "name", text="", emboss=False, icon_value=icon) - #else: - # layout.label(text="", translate=False, icon_value=icon) - layout.label(text=item.name, icon_value=icon) - #layout.prop(item, "name", text="", emboss=False, icon_value=icon) - # 'GRID' layout type should be as compact as possible (typically a single icon!). - elif self.layout_type == 'GRID': - layout.alignment = 'CENTER' - layout.label(text="", icon_value=icon) - - class SCENES_LIST_OT_actions(Operator): """Move items up and down, add and remove""" bl_idname = "scene_list.list_action" @@ -55,65 +22,41 @@ class SCENES_LIST_OT_actions(Operator): ('LIBRARY', "Library", ""), ) ) # type: ignore + + scene_name : bpy.props.StringProperty(name="scene_name")# type: ignore - def invoke(self, context, event): - source = context.window_manager.blenvy - target_name = "library_scenes" - target_index = "library_scenes_index" - if self.scene_type == "LEVEL": - target_name = "main_scenes" - target_index = "main_scenes_index" - - target = getattr(source, target_name) - idx = getattr(source, target_index) - current_index = getattr(source, target_index) + def invoke(self, context, event): + if self.action == 'REMOVE': + bpy.data.scenes[self.scene_name].blenvy_scene_type = 'None' + """info = 'Item "%s" removed from list' % (target[idx].name) + target.remove(idx) - try: - item = target[idx] - except IndexError: - pass - else: - if self.action == 'DOWN' and idx < len(target) - 1: - target.move(idx, idx + 1) - setattr(source, target_index, current_index +1 ) - info = 'Item "%s" moved to position %d' % (item.name, current_index + 1) - self.report({'INFO'}, info) - - elif self.action == 'UP' and idx >= 1: - target.move(idx, idx - 1) - setattr(source, target_index, current_index -1 ) - info = 'Item "%s" moved to position %d' % (item.name, current_index + 1) - self.report({'INFO'}, info) - - elif self.action == 'REMOVE': - info = 'Item "%s" removed from list' % (target[idx].name) - target.remove(idx) - - setattr(source, target_index, current_index -1 ) - self.report({'INFO'}, info) + setattr(source, target_index, current_index -1 ) + self.report({'INFO'}, info)""" if self.action == 'ADD': - new_scene_name = None + scene_to_add = None if self.scene_type == "LEVEL": if context.window_manager.blenvy.main_scene_selector: - new_scene_name = context.window_manager.blenvy.main_scene_selector.name + scene_to_add = context.window_manager.blenvy.main_scene_selector + scene_to_add.blenvy_scene_type = "Level" else: if context.window_manager.blenvy.library_scene_selector: - new_scene_name = context.window_manager.blenvy.library_scene_selector.name - if new_scene_name: - item = target.add() - item.name = new_scene_name + scene_to_add = context.window_manager.blenvy.library_scene_selector + scene_to_add.blenvy_scene_type = "Library" + if scene_to_add is not None: + print("adding scene", scene_to_add) + if self.scene_type == "LEVEL": context.window_manager.blenvy.main_scene_selector = None else: context.window_manager.blenvy.library_scene_selector = None - setattr(source, target_index, len(target) - 1) + #setattr(source, target_index, len(target) - 1) - - - info = '"%s" added to list' % (item.name) - self.report({'INFO'}, info) + #info = '"%s" added to list' % (item.name) + #self.report({'INFO'}, info) return {"FINISHED"} + diff --git a/tools/blenvy/core/ui/ui.py b/tools/blenvy/core/ui/ui.py index 27d674d..b57a9db 100644 --- a/tools/blenvy/core/ui/ui.py +++ b/tools/blenvy/core/ui/ui.py @@ -109,44 +109,40 @@ class BLENVY_PT_SidePanel(bpy.types.Panel): row = section.row() row.label(text="main scenes") row.prop(blenvy, "main_scene_selector", text='') - - row = section.row() - row.template_list("SCENE_UL_Blenvy", "level scenes", blenvy, "main_scenes", blenvy, "main_scenes_index", rows=rows) - - col = row.column(align=True) - sub_row = col.row() - add_operator = sub_row.operator("scene_list.list_action", icon='ADD', text="") + add_operator = row.operator("scene_list.list_action", icon='ADD', text="") add_operator.action = 'ADD' add_operator.scene_type = 'LEVEL' - #add_operator.operator = operator - sub_row.enabled = blenvy.main_scene_selector is not None + #sub_row.enabled = blenvy.main_scene_selector is not None + + row = section.row() + col = row.column() + for scene in blenvy.main_scenes: + sub_row = col.box().row() + sub_row.label(text=scene.name) + remove_operator = sub_row.operator("scene_list.list_action", icon='TRASH', text="") + remove_operator.action = 'REMOVE' + remove_operator.scene_type = 'LEVEL' + remove_operator.scene_name = scene.name - sub_row = col.row() - remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="") - remove_operator.action = 'REMOVE' - remove_operator.scene_type = 'LEVEL' col.separator() # library scenes row = section.row() row.label(text="library scenes") row.prop(blenvy, "library_scene_selector", text='') - - row = section.row() - row.template_list("SCENE_UL_Blenvy", "library scenes", blenvy, "library_scenes", blenvy, "library_scenes_index", rows=rows) - - col = row.column(align=True) - sub_row = col.row() - add_operator = sub_row.operator("scene_list.list_action", icon='ADD', text="") + add_operator = row.operator("scene_list.list_action", icon='ADD', text="") add_operator.action = 'ADD' add_operator.scene_type = 'LIBRARY' - sub_row.enabled = blenvy.library_scene_selector is not None - - sub_row = col.row() - remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="") - remove_operator.action = 'REMOVE' - remove_operator.scene_type = 'LIBRARY' + row = section.row() + col = row.column() + for scene in blenvy.library_scenes: + sub_row = col.box().row() + sub_row.label(text=scene.name) + remove_operator = sub_row.operator("scene_list.list_action", icon='TRASH', text="") + remove_operator.action = 'REMOVE' + remove_operator.scene_type = 'LEVEL' + remove_operator.scene_name = scene.name col.separator() header, panel = layout.panel("components", default_closed=False) diff --git a/tools/blenvy/levels/ui.py b/tools/blenvy/levels/ui.py index a82c2a1..63d9a00 100644 --- a/tools/blenvy/levels/ui.py +++ b/tools/blenvy/levels/ui.py @@ -26,8 +26,7 @@ class Blenvy_levels(bpy.types.Panel): #blueprints_registry.refresh_blueprints() blueprints_data = blueprints_registry.blueprints_data - for scene_selector in blenvy.main_scenes: - scene = bpy.data.scenes[scene_selector.name] + for scene in blenvy.main_scenes: header, panel = layout.box().panel(f"level_assets{scene.name}", default_closed=False) if header: header.label(text=scene.name)#, icon="HIDE_OFF")