Compare commits

...

7 Commits

Author SHA1 Message Date
kaosat.dev
2470736f81 feat(blenvy): fixes & improvements to the settings handling 2024-05-26 20:09:15 +02:00
kaosat.dev
b957f0573b feat(Blenvy): settings coherency pass
* restructured component settings to be used instead of the registry
 * removed settings from registry
 * fixed data access for the above
 * added saving of component parameters
 * added component settings pointer in blenvy core
 * added loading of both auto_export & component settings in blenvy core's load_settings
2024-05-26 18:33:06 +02:00
kaosat.dev
ea982d330f refactor(Blenvy): moved components & auto export into a sub folder for clarity 2024-05-25 13:26:30 +02:00
kaosat.dev
26e75742b2 feat(Blenvy):
* fixed handling of gltf dummy file & settings storage
 * experimenting with best approach for settings diffing for auto export
 * started (wip) moving out bevy_components settings from registry to indenpendant settings
 * minor tweaks
2024-05-25 11:57:10 +02:00
kaosat.dev
4f742e7735 refactor(Blenvy): minor re-orgs 2024-05-25 11:14:13 +02:00
kaosat.dev
8b76a34bec refactor(Blenvy): renaming , moving of auto_export modules 2024-05-25 10:54:23 +02:00
kaosat.dev
c00c9908eb feat(Blenvy): a lot of verious tweaks & fixes
* fixed/ overhauld asset & blueprint scanning
 * added polling for blueprints (not 100% sure yet)
 * add-on-prefs => settings
 * removed the now obsolete auto-export operator & preperences
 * a lot of other minor changes
2024-05-25 10:46:14 +02:00
79 changed files with 584 additions and 893 deletions

View File

@ -66,16 +66,21 @@ Components:
- [ ] handle missing types in registry for keys & values
- [ ] Add correct upgrade handling from individual component to bevy_components
- [ ] Settings handling:
- [ ] move saveable settings out to a settings file
- [ ] update save & load
- [ ] add handling of polling frequency & enabling
General things to solve:
- [x] save settings
- [x] load settings
- [ ] add_blueprints_data
- [ ] add blueprints data
- [x] rename all path stuff using the old naming convention : "blueprints_path_full"
- [x] generate the full paths directly when setting them in the UI
- [x] problem : how to deal with defaults: do it on start/load ?
- [x] filter out scenes that have already been used in scenes list
General issues:
- there is no safeguard for naming collisions for naming across blender files
@ -83,6 +88,12 @@ General issues:
- "parents" can only be blueprints
- they normally need/have unique export paths (otherwise, user error, perhaps show it ?)
- perhaps a simple hashing of the parent's path would be enought
- [ ] addon-prefs => settings
- [ ] generate_gltf_export_preferences => should not use add-on prefs at all ? since we are not overriding gltf settings that way anymore ?
- [x] addon-prefs => settings
- [x] generate_gltf_export_preferences => should not use add-on prefs at all ? since we are not overriding gltf settings that way anymore ?
- [x] remove hard coded path for standard gltf settings
- [x] load settings on file load
- [x] auto_export
- [x] components
- [ ] add handling of errors when trying to load settings

View File

@ -17,23 +17,21 @@ from bpy.props import (StringProperty)
# components management
from .bevy_components.components.operators import CopyComponentOperator, Fix_Component_Operator, OT_rename_component, RemoveComponentFromAllItemsOperator, RemoveComponentOperator, GenerateComponent_From_custom_property_Operator, PasteComponentOperator, AddComponentOperator, RenameHelper, Toggle_ComponentVisibility
from .bevy_components.registry.registry import ComponentsRegistry,MissingBevyType
from .bevy_components.registry.operators import (COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_CURRENT, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_CURRENT, OT_select_component_name_to_replace, OT_select_object, ReloadRegistryOperator, OT_OpenSchemaFileBrowser)
from .bevy_components.registry.ui import (BEVY_COMPONENTS_PT_Configuration, BEVY_COMPONENTS_PT_AdvancedToolsPanel, BEVY_COMPONENTS_PT_MissingTypesPanel, MISSING_TYPES_UL_List)
from .bevy_components.components.metadata import (ComponentMetadata, ComponentsMeta)
from .bevy_components.components.lists import GENERIC_LIST_OT_actions, Generic_LIST_OT_AddItem, Generic_LIST_OT_RemoveItem, Generic_LIST_OT_SelectItem
from .bevy_components.components.maps import GENERIC_MAP_OT_actions
from .bevy_components.components.definitions_list import (ComponentDefinitionsList, ClearComponentDefinitionsList)
from .bevy_components.components.ui import (BEVY_COMPONENTS_PT_ComponentsPanel)
from .add_ons.bevy_components.components.operators import CopyComponentOperator, Fix_Component_Operator, OT_rename_component, RemoveComponentFromAllItemsOperator, RemoveComponentOperator, GenerateComponent_From_custom_property_Operator, PasteComponentOperator, AddComponentOperator, RenameHelper, Toggle_ComponentVisibility
from .add_ons.bevy_components.registry.registry import ComponentsRegistry,MissingBevyType
from .add_ons.bevy_components.registry.operators import (COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_CURRENT, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_CURRENT, OT_select_component_name_to_replace, OT_select_object, ReloadRegistryOperator, OT_OpenSchemaFileBrowser)
from .add_ons.bevy_components.registry.ui import (BEVY_COMPONENTS_PT_Configuration, BEVY_COMPONENTS_PT_AdvancedToolsPanel, BEVY_COMPONENTS_PT_MissingTypesPanel, MISSING_TYPES_UL_List)
from .add_ons.bevy_components.components.metadata import (ComponentMetadata, ComponentsMeta)
from .add_ons.bevy_components.components.lists import GENERIC_LIST_OT_actions, Generic_LIST_OT_AddItem, Generic_LIST_OT_RemoveItem, Generic_LIST_OT_SelectItem
from .add_ons.bevy_components.components.maps import GENERIC_MAP_OT_actions
from .add_ons.bevy_components.components.definitions_list import (ComponentDefinitionsList, ClearComponentDefinitionsList)
from .add_ons.bevy_components.components.ui import (BEVY_COMPONENTS_PT_ComponentsPanel)
from .add_ons.bevy_components.settings import ComponentsSettings
# auto export
from .gltf_auto_export import gltf_post_export_callback
from .gltf_auto_export.auto_export.operators import AutoExportGLTF
from .gltf_auto_export.auto_export.tracker import AutoExportTracker
from .gltf_auto_export.settings import AutoExportSettings
from .add_ons.auto_export import gltf_post_export_callback
from .add_ons.auto_export.export.tracker import AutoExportTracker
from .add_ons.auto_export.settings import AutoExportSettings
# asset management
from .assets.ui import Blenvy_assets
@ -70,6 +68,7 @@ classes = [
BLENVY_PT_SidePanel,
# bevy components
ComponentsSettings,
AddComponentOperator,
CopyComponentOperator,
PasteComponentOperator,
@ -113,8 +112,8 @@ classes = [
GENERIC_MAP_OT_actions,
# gltf auto export
AutoExportGLTF,
AutoExportTracker,
AutoExportSettings,
@ -146,9 +145,7 @@ def post_save(scene, depsgraph):
@persistent
def post_load(file_name):
registry = bpy.context.window_manager.components_registry
if registry is not None:
registry.load_settings()
print("POST LOAD")
blenvy = bpy.context.window_manager.blenvy
if blenvy is not None:
blenvy.load_settings()

View File

@ -4,7 +4,7 @@ import bpy
from .helpers.generate_complete_preferences_dict import generate_complete_preferences_dict_gltf
def cleanup_file():
gltf_filepath = "/home/ckaos/projects/bevy/Blender_bevy_components_worklflow/testing/bevy_example/assets/____dummy____.glb"
gltf_filepath = bpy.context.window_manager.auto_export_tracker.dummy_file_path
if os.path.exists(gltf_filepath):
os.remove(gltf_filepath)
return None
@ -14,38 +14,39 @@ def cleanup_file():
def gltf_post_export_callback(data):
#print("post_export", data)
blenvy = bpy.context.window_manager.blenvy
bpy.context.window_manager.auto_export_tracker.export_finished()
tracker = bpy.context.window_manager.auto_export_tracker
tracker.export_finished()
gltf_settings_backup = blenvy.auto_export.gltf_settings_backup
gltf_settings_backup = tracker.gltf_settings_backup
gltf_filepath = data["gltf_filepath"]
gltf_export_id = data['gltf_export_id']
if gltf_export_id == "gltf_auto_export":
# some more absurdity: apparently the file is not QUITE done when the export callback is called, so we have to introduce this timer to remove the temporary file correctly
bpy.context.window_manager.auto_export_tracker.dummy_file_path = gltf_filepath
tracker.dummy_file_path = gltf_filepath
try:
bpy.app.timers.unregister(cleanup_file)
except:pass
bpy.app.timers.register(cleanup_file, first_interval=1)
bpy.app.timers.register(cleanup_file, first_interval=2)
# get the parameters
scene = bpy.context.scene
if "glTF2ExportSettings" in scene:
settings = scene["glTF2ExportSettings"]
export_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings")
gltf_export_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings")
# now write new settings
export_settings.clear()
gltf_export_settings.clear()
current_gltf_settings = generate_complete_preferences_dict_gltf(dict(settings))
export_settings.write(json.dumps(current_gltf_settings))
gltf_export_settings.write(json.dumps(current_gltf_settings))
# now reset the original gltf_settings
if gltf_settings_backup != "":
scene["glTF2ExportSettings"] = json.loads(gltf_settings_backup)
else:
if "glTF2ExportSettings" in scene:
del scene["glTF2ExportSettings"]
blenvy.auto_export.gltf_settings_backup = ""
tracker.gltf_settings_backup = ""
# the absurd length one has to go through to RESET THE OPERATOR because it has global state !!!!! AAAAAHHH
last_operator = bpy.context.window_manager.auto_export_tracker.last_operator
last_operator = tracker.last_operator
last_operator.filepath = ""
last_operator.gltf_export_id = ""

View File

@ -3,23 +3,22 @@ import os
import bpy
import traceback
from ..helpers.helpers_scenes import (get_scenes, )
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
from .get_blueprints_to_export import get_blueprints_to_export
from .get_levels_to_export import get_levels_to_export
from .get_standard_exporter_settings import get_standard_exporter_settings
from .export_gltf import get_standard_exporter_settings
from .export_main_scenes import export_main_scene
from .export_blueprints import export_blueprints
from ..modules.export_materials import cleanup_materials, export_materials
from .export_materials import cleanup_materials, export_materials
from ..modules.bevy_scene_components import remove_scene_components, upsert_scene_components
from ...blueprints.blueprints_scan import blueprints_scan
from ...blueprints.blueprint_helpers import inject_export_path_into_internal_blueprints
"""this is the main 'central' function for all auto export """
def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
def auto_export(changes_per_scene, changed_export_parameters, settings):
# have the export parameters (not auto export, just gltf export) have changed: if yes (for example switch from glb to gltf, compression or not, animations or not etc), we need to re-export everything
print ("changed_export_parameters", changed_export_parameters)
try:
@ -27,41 +26,34 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
file_path = bpy.data.filepath
# Get the folder
blend_file_path = os.path.dirname(file_path)
# get the preferences for our addon
project_root_path = getattr(addon_prefs, "project_root_path")
assets_path = getattr(addon_prefs,"assets_path")
#should we use change detection or not
change_detection = getattr(addon_prefs.auto_export, "change_detection")
export_scene_settings = getattr(addon_prefs.auto_export,"export_scene_settings")
do_export_blueprints = getattr(addon_prefs.auto_export,"export_blueprints")
export_materials_library = getattr(addon_prefs.auto_export,"export_materials_library")
change_detection = getattr(settings.auto_export, "change_detection")
export_scene_settings = getattr(settings.auto_export,"export_scene_settings")
do_export_blueprints = getattr(settings.auto_export,"export_blueprints")
export_materials_library = getattr(settings.auto_export,"export_materials_library")
# standard gltf export settings are stored differently
standard_gltf_exporter_settings = get_standard_exporter_settings()
gltf_extension = standard_gltf_exporter_settings.get("export_format", 'GLB')
gltf_extension = '.glb' if gltf_extension == 'GLB' else '.gltf'
settings.export_gltf_extension = gltf_extension
# generate the actual complete output paths
"""addon_prefs.assets_path_full = os.path.join(blend_file_path, project_root_path, assets_path)
addon_prefs.blueprints_path_full = os.path.join(addon_prefs.assets_path_full, getattr(addon_prefs,"blueprints_path"))
addon_prefs.levels_path_full = os.path.join(addon_prefs.assets_path_full, getattr(addon_prefs,"levels_path"))
addon_prefs.materials_path_full = os.path.join(addon_prefs.assets_path_full, getattr(addon_prefs,"materials_path"))"""
addon_prefs.export_gltf_extension = gltf_extension
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_main_and_library_scenes(settings)
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
blueprints_data = blueprints_scan(level_scenes, library_scenes, addon_prefs)
bpy.context.window_manager.blueprints_registry.refresh_blueprints()
blueprints_data = bpy.context.window_manager.blueprints_registry.blueprints_data
blueprints_per_scene = blueprints_data.blueprints_per_scenes
internal_blueprints = [blueprint.name for blueprint in blueprints_data.internal_blueprints]
external_blueprints = [blueprint.name for blueprint in blueprints_data.external_blueprints]
# we inject the blueprints export path
blueprints_path = getattr(addon_prefs,"blueprints_path")
blueprints_path = getattr(settings,"blueprints_path")
inject_export_path_into_internal_blueprints(internal_blueprints=blueprints_data.internal_blueprints, blueprints_path=blueprints_path, gltf_extension=gltf_extension)
for blueprint in blueprints_data.blueprints:
bpy.context.window_manager.blueprints_registry.add_blueprint(blueprint)
#bpy.context.window_manager.blueprints_registry.add_blueprints_data()
#bpy.context.window_manager.blueprints_registry.refresh_blueprints()
print("YO YO")
if export_scene_settings:
# inject/ update scene components
@ -75,15 +67,15 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
if do_export_blueprints:
print("EXPORTING")
# get blueprints/collections infos
(blueprints_to_export) = get_blueprints_to_export(changes_per_scene, changed_export_parameters, blueprints_data, addon_prefs)
(blueprints_to_export) = get_blueprints_to_export(changes_per_scene, changed_export_parameters, blueprints_data, settings)
# get level/main scenes infos
(main_scenes_to_export) = get_levels_to_export(changes_per_scene, changed_export_parameters, blueprints_data, addon_prefs)
(main_scenes_to_export) = get_levels_to_export(changes_per_scene, changed_export_parameters, blueprints_data, 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, addon_prefs)
export_materials(blueprints_data.blueprint_names, 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)
@ -115,13 +107,13 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
print("export MAIN scenes")
for scene_name in main_scenes_to_export:
print(" exporting scene:", scene_name)
export_main_scene(bpy.data.scenes[scene_name], blend_file_path, addon_prefs, blueprints_data)
export_main_scene(bpy.data.scenes[scene_name], blend_file_path, settings, blueprints_data)
# now deal with blueprints/collections
do_export_library_scene = not change_detection or changed_export_parameters or len(blueprints_to_export) > 0
if do_export_library_scene:
print("export LIBRARY")
export_blueprints(blueprints_to_export, addon_prefs, blueprints_data)
export_blueprints(blueprints_to_export, settings, blueprints_data)
# reset current scene from backup
bpy.context.window.scene = old_current_scene
@ -134,7 +126,7 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
else:
for scene_name in main_scene_names:
export_main_scene(bpy.data.scenes[scene_name], blend_file_path, addon_prefs, [])
export_main_scene(bpy.data.scenes[scene_name], blend_file_path, settings, [])
@ -148,7 +140,7 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
finally:
# FIXME: error handling ? also redundant
[main_scene_names, main_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
[main_scene_names, main_scenes, library_scene_names, library_scenes] = get_main_and_library_scenes(settings)
if export_scene_settings:
# inject/ update scene components

View File

@ -7,32 +7,32 @@ from .export_gltf import (generate_gltf_export_preferences)
from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into
def export_blueprints(blueprints, addon_prefs, blueprints_data):
blueprints_path_full = getattr(addon_prefs, "blueprints_path_full")
gltf_export_preferences = generate_gltf_export_preferences(addon_prefs)
def export_blueprints(blueprints, settings, blueprints_data):
blueprints_path_full = getattr(settings, "blueprints_path_full")
gltf_export_preferences = generate_gltf_export_preferences(settings)
try:
# save current active collection
active_collection = bpy.context.view_layer.active_layer_collection
export_materials_library = getattr(addon_prefs.auto_export, "export_materials_library")
export_materials_library = getattr(settings.auto_export, "export_materials_library")
for blueprint in blueprints:
print("exporting collection", blueprint.name)
gltf_output_path = os.path.join(blueprints_path_full, blueprint.name)
export_settings = { **gltf_export_preferences, 'use_active_scene': True, 'use_active_collection': True, 'use_active_collection_with_nested':True}
gltf_export_settings = { **gltf_export_preferences, 'use_active_scene': True, 'use_active_collection': True, 'use_active_collection_with_nested':True}
# if we are using the material library option, do not export materials, use placeholder instead
if export_materials_library:
export_settings['export_materials'] = 'PLACEHOLDER'
gltf_export_settings['export_materials'] = 'PLACEHOLDER'
collection = bpy.data.collections[blueprint.name]
# do the actual export
generate_and_export(
addon_prefs,
settings,
temp_scene_name=TEMPSCENE_PREFIX+collection.name,
export_settings=export_settings,
gltf_export_settings=gltf_export_settings,
gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(collection, temp_collection, blueprints_data=blueprints_data, addon_prefs=addon_prefs),
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(collection, temp_collection, blueprints_data=blueprints_data, settings=settings),
tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=collection, temp_scene=temp_scene, **params)
)

View File

@ -2,10 +2,13 @@ import json
import os
import bpy
from .get_standard_exporter_settings import get_standard_exporter_settings
from .preferences import (AutoExportGltfPreferenceNames)
from blenvy.settings import load_settings
def generate_gltf_export_preferences(addon_prefs):
def get_standard_exporter_settings():
standard_gltf_exporter_settings = load_settings(".blenvy_gltf_settings")
return standard_gltf_exporter_settings if standard_gltf_exporter_settings is not None else {}
def generate_gltf_export_preferences(settings):
# default values
gltf_export_preferences = dict(
# export_format= 'GLB', #'GLB', 'GLTF_SEPARATE', 'GLTF_EMBEDDED'
@ -43,10 +46,10 @@ def generate_gltf_export_preferences(addon_prefs):
#export_optimize_animation_size=False
)
for key in addon_prefs.__annotations__.keys():
"""for key in settings.__annotations__.keys():
if str(key) not in AutoExportGltfPreferenceNames:
#print("overriding setting", key, "value", getattr(addon_prefs,key))
pass#gltf_export_preferences[key] = getattr(addon_prefs, key)
#print("overriding setting", key, "value", getattr(settings,key))
pass#gltf_export_preferences[key] = getattr(settings, key)"""
standard_gltf_exporter_settings = get_standard_exporter_settings()
@ -70,8 +73,8 @@ def generate_gltf_export_preferences(addon_prefs):
#https://docs.blender.org/api/current/bpy.ops.export_scene.html#bpy.ops.export_scene.gltf
def export_gltf (path, export_settings):
settings = {**export_settings, "filepath": path}
def export_gltf (path, gltf_export_settings):
settings = {**gltf_export_settings, "filepath": path}
# print("export settings",settings)
os.makedirs(os.path.dirname(path), exist_ok=True)
bpy.ops.export_scene.gltf(**settings)

View File

@ -1,23 +1,23 @@
import os
import bpy
from pathlib import Path
from blenvy.blueprints.blueprint_helpers import inject_blueprints_list_into_main_scene, remove_blueprints_list_from_main_scene
from ..constants import TEMPSCENE_PREFIX
from ..helpers.generate_and_export import generate_and_export
from .export_gltf import (generate_gltf_export_preferences, export_gltf)
from ..modules.bevy_dynamic import is_object_dynamic, is_object_static
from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into
from ...blueprints.blueprint_helpers import inject_blueprints_list_into_main_scene, remove_blueprints_list_from_main_scene
def export_main_scene(scene, blend_file_path, addon_prefs, blueprints_data):
gltf_export_preferences = generate_gltf_export_preferences(addon_prefs)
assets_path_full = getattr(addon_prefs,"assets_path_full")
levels_path_full = getattr(addon_prefs,"levels_path_full")
def export_main_scene(scene, blend_file_path, settings, blueprints_data):
gltf_export_preferences = generate_gltf_export_preferences(settings)
assets_path_full = getattr(settings,"assets_path_full")
levels_path_full = getattr(settings,"levels_path_full")
export_blueprints = getattr(addon_prefs.auto_export,"export_blueprints")
export_separate_dynamic_and_static_objects = getattr(addon_prefs.auto_export, "export_separate_dynamic_and_static_objects")
export_blueprints = getattr(settings.auto_export,"export_blueprints")
export_separate_dynamic_and_static_objects = getattr(settings.auto_export, "export_separate_dynamic_and_static_objects")
export_settings = { **gltf_export_preferences,
gltf_export_settings = { **gltf_export_preferences,
'use_active_scene': True,
'use_active_collection':True,
'use_active_collection_with_nested':True,
@ -29,45 +29,46 @@ def export_main_scene(scene, blend_file_path, addon_prefs, blueprints_data):
if export_blueprints :
gltf_output_path = os.path.join(levels_path_full, scene.name)
#inject_blueprints_list_into_main_scene(scene, blueprints_data, addon_prefs)
#inject_blueprints_list_into_main_scene(scene, blueprints_data, settings)
if export_separate_dynamic_and_static_objects:
#print("SPLIT STATIC AND DYNAMIC")
# first export static objects
generate_and_export(
addon_prefs,
settings,
temp_scene_name=TEMPSCENE_PREFIX,
export_settings=export_settings,
gltf_export_settings=gltf_export_settings,
gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, blueprints_data=blueprints_data, filter=is_object_static, addon_prefs=addon_prefs),
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, blueprints_data=blueprints_data, filter=is_object_static, settings=settings),
tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=scene.collection, temp_scene=temp_scene, **params)
)
# then export all dynamic objects
gltf_output_path = os.path.join(levels_path_full, scene.name+ "_dynamic")
generate_and_export(
addon_prefs,
settings,
temp_scene_name=TEMPSCENE_PREFIX,
export_settings=export_settings,
gltf_export_settings=gltf_export_settings,
gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, blueprints_data=blueprints_data, filter=is_object_dynamic, addon_prefs=addon_prefs),
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, blueprints_data=blueprints_data, filter=is_object_dynamic, settings=settings),
tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=scene.collection, temp_scene=temp_scene, **params)
)
else:
#print("NO SPLIT")
generate_and_export(
addon_prefs,
settings,
temp_scene_name=TEMPSCENE_PREFIX,
export_settings=export_settings,
gltf_export_settings=gltf_export_settings,
gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, blueprints_data=blueprints_data, addon_prefs=addon_prefs),
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, blueprints_data=blueprints_data, settings=settings),
tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=scene.collection, temp_scene=temp_scene, **params)
)
else:
gltf_output_path = os.path.join(assets_path_full, scene.name)
print(" exporting gltf to", gltf_output_path, ".gltf/glb")
export_gltf(gltf_output_path, export_settings)
if settings.auto_export.dry_run == "DISABLED":
export_gltf(gltf_output_path, gltf_export_settings)
remove_blueprints_list_from_main_scene(scene)

View File

@ -2,11 +2,11 @@ import os
import bpy
from pathlib import Path
from ...core.helpers_collections import (traverse_tree)
from ...core.object_makers import make_cube
from ...materials.materials_helpers import get_all_materials
from blenvy.core.helpers_collections import (traverse_tree)
from blenvy.core.object_makers import make_cube
from blenvy.materials.materials_helpers import get_all_materials
from ..helpers.generate_and_export import generate_and_export
from ..auto_export.export_gltf import (generate_gltf_export_preferences)
from .export_gltf import (generate_gltf_export_preferences)
def clear_material_info(collection_names, library_scenes):
for scene in library_scenes:
@ -59,14 +59,14 @@ def clear_materials_scene(temp_scene):
# exports the materials used inside the current project:
# the name of the output path is <materials_folder>/<name_of_your_blend_file>_materials_library.gltf/glb
def export_materials(collections, library_scenes, addon_prefs):
gltf_export_preferences = generate_gltf_export_preferences(addon_prefs)
materials_path_full = getattr(addon_prefs,"materials_path_full")
def export_materials(collections, library_scenes, settings):
gltf_export_preferences = generate_gltf_export_preferences(settings)
materials_path_full = getattr(settings,"materials_path_full")
used_material_names = get_all_materials(collections, library_scenes)
current_project_name = Path(bpy.context.blend_data.filepath).stem
export_settings = { **gltf_export_preferences,
gltf_export_settings = { **gltf_export_preferences,
'use_active_scene': True,
'use_active_collection':True,
'use_active_collection_with_nested':True,
@ -80,9 +80,9 @@ def export_materials(collections, library_scenes, addon_prefs):
print(" exporting Materials to", gltf_output_path, ".gltf/glb")
generate_and_export(
addon_prefs,
settings=settings,
gltf_export_settings=gltf_export_settings,
temp_scene_name="__materials_scene",
export_settings=export_settings,
gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: generate_materials_scene_content(temp_collection, used_material_names),
tempScene_cleaner= lambda temp_scene, params: clear_materials_scene(temp_scene=temp_scene)

View File

@ -1,16 +1,15 @@
import bpy
import os
from ..helpers.helpers_scenes import (get_scenes, )
from ...blueprints.blueprint_helpers import find_blueprints_not_on_disk
from blenvy.core.scene_helpers import get_main_and_library_scenes
from blenvy.blueprints.blueprint_helpers import find_blueprints_not_on_disk
# TODO: this should also take the split/embed mode into account: if a nested collection changes AND embed is active, its container collection should also be exported
def get_blueprints_to_export(changes_per_scene, changed_export_parameters, blueprints_data, addon_prefs):
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension", ".glb")
blueprints_path_full = getattr(addon_prefs,"blueprints_path_full", "")
change_detection = getattr(addon_prefs.auto_export, "change_detection")
collection_instances_combine_mode = getattr(addon_prefs.auto_export, "collection_instances_combine_mode")
def get_blueprints_to_export(changes_per_scene, changed_export_parameters, blueprints_data, settings):
export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb")
blueprints_path_full = getattr(settings,"blueprints_path_full", "")
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_scenes(addon_prefs)
[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

View File

@ -1,6 +1,5 @@
import bpy
from ...blueprints.blueprint_helpers import check_if_blueprint_on_disk
from ..helpers.helpers_scenes import (get_scenes, )
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
def changed_object_in_scene(scene_name, changes_per_scene, blueprints_data, collection_instances_combine_mode):
@ -36,14 +35,14 @@ def changed_object_in_scene(scene_name, changes_per_scene, blueprints_data, coll
# 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, addon_prefs):
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
levels_path_full = getattr(addon_prefs, "levels_path_full")
def get_levels_to_export(changes_per_scene, changed_export_parameters, blueprints_data, settings):
export_gltf_extension = getattr(settings, "export_gltf_extension")
levels_path_full = getattr(settings, "levels_path_full")
change_detection = getattr(addon_prefs.auto_export, "change_detection")
collection_instances_combine_mode = getattr(addon_prefs.auto_export, "collection_instances_combine_mode")
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_scenes(addon_prefs)
[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)

View File

@ -1,22 +1,21 @@
import bpy
from .project_diff import get_changes_per_scene, project_diff, serialize_current
from ...settings import are_settings_identical
from .auto_export import auto_export
from .settings_diff import get_setting_changes
# prepare export by gather the changes to the scenes & settings
def prepare_and_export():
print("prepare and export")
blenvy = bpy.context.window_manager.blenvy
bpy.context.window_manager.auto_export_tracker.disable_change_detection()
blenvy = bpy.context.window_manager.blenvy
auto_export_settings = blenvy.auto_export
if auto_export_settings.auto_export: # only do the actual exporting if auto export is actually enabled
# determine changed objects
per_scene_changes = get_changes_per_scene()
# determine changed parameters
setting_changes = get_setting_changes()
setting_changes = get_setting_changes(auto_export_settings)
# do the actual export
auto_export(per_scene_changes, setting_changes, blenvy)

View File

@ -1,9 +1,10 @@
import bpy
from ...settings import are_settings_identical, load_settings, upsert_settings
from blenvy.settings import are_settings_identical, load_settings, upsert_settings
# which settings are specific to auto_export # TODO: can we infer this ?
auto_export_parameter_names = [
# blenvy core
'project_root_path',
'assets_path',
'blueprints_path',
@ -12,6 +13,7 @@ auto_export_parameter_names = [
#'main_scene_names',
#'library_scene_names',
# auto export
'export_scene_settings',
'export_blueprints',
'export_separate_dynamic_and_static_objects',
@ -20,13 +22,14 @@ auto_export_parameter_names = [
'export_marked_assets'
]
def get_setting_changes():
def get_setting_changes(auto_export_settings):
print("get setting changes", dict(auto_export_settings))
previous_gltf_settings = load_settings(".blenvy_gltf_settings_previous")
current_gltf_settings = load_settings(".blenvy_gltf_settings")
gltf_settings_changed = not are_settings_identical(previous_gltf_settings, current_gltf_settings)
previous_export_settings = load_settings(".blenvy_export_settings_previous")
current_export_settings = load_settings(".blenvy_export_settings")
current_export_settings = dict(auto_export_settings) #load_settings(".blenvy_export_settings")
export_settings_changed = not are_settings_identical(previous_export_settings, current_export_settings)
# if there were no setting before, it is new, we need export
@ -37,7 +40,7 @@ def get_setting_changes():
# write the new settings to the old settings
upsert_settings(".blenvy_gltf_settings_previous", current_gltf_settings)
upsert_settings(".blenvy_export_settings_previous", current_gltf_settings)
upsert_settings(".blenvy_export_settings_previous", current_export_settings)
return gltf_settings_changed or export_settings_changed

View File

@ -14,9 +14,18 @@ class AutoExportTracker(PropertyGroup):
change_detection_enabled = True
export_params_changed = False
gltf_settings_backup = None
last_operator = None
dummy_file_path = ""
dummy_file_path: StringProperty()# type: ignore
# special property for gltf settings
gltf_settings_backup: StringProperty(
name="gltf settings backup",
description="backup for existing gltf settings so that we can restore them"
) # type: ignore
exports_total : IntProperty(
name='exports_total',
@ -77,7 +86,7 @@ class AutoExportTracker(PropertyGroup):
scene = bpy.context.scene
if "glTF2ExportSettings" in scene:
existing_setting = scene["glTF2ExportSettings"]
bpy.context.window_manager.gltf_settings_backup = json.dumps(dict(existing_setting))
bpy.context.window_manager.auto_export_tracker.gltf_settings_backup = json.dumps(dict(existing_setting))
# we force saving params
active_operator.will_save_settings = True

View File

@ -1,16 +1,16 @@
import bpy
from ..auto_export.export_gltf import export_gltf
from ...core.helpers_collections import (set_active_collection)
from blenvy.core.helpers_collections import (set_active_collection)
from ..export.export_gltf import export_gltf
"""
generates a temporary scene, fills it with data, cleans up after itself
* named using temp_scene_name
* filled using the tempScene_filler
* written on disk to gltf_output_path, with the gltf export parameters in export_settings
* written on disk to gltf_output_path, with the gltf export parameters in gltf_export_settings
* cleaned up using tempScene_cleaner
"""
def generate_and_export(addon_prefs, export_settings, gltf_output_path, temp_scene_name="__temp_scene", tempScene_filler=None, tempScene_cleaner=None):
def generate_and_export(settings, gltf_export_settings, gltf_output_path, temp_scene_name="__temp_scene", tempScene_filler=None, tempScene_cleaner=None):
temp_scene = bpy.data.scenes.new(name=temp_scene_name)
temp_root_collection = temp_scene.collection
@ -41,7 +41,8 @@ def generate_and_export(addon_prefs, export_settings, gltf_output_path, temp_sce
scene_filler_data = tempScene_filler(temp_root_collection)
# export the temporary scene
try:
export_gltf(gltf_output_path, export_settings)
if settings.auto_export.dry_run == "DISABLED":
export_gltf(gltf_output_path, gltf_export_settings)
except Exception as error:
print("failed to export gltf !", error)
raise error

View File

@ -1,5 +1,4 @@
from ..auto_export.preferences import AutoExportGltfAddonPreferences
from io_scene_gltf2 import (ExportGLTF2_Base)
# given the input (actual) gltf settings, filters out any invalid/useless params & params that are equal to defaults
@ -27,21 +26,3 @@ def generate_complete_preferences_dict_gltf(settings):
complete_preferences = dict(filter(filter_out, dict(complete_preferences).items()))
return complete_preferences
# given the input (actual) auto settings, filters out any invalid/useless params & params that are equal to defaults
def generate_complete_preferences_dict_auto(settings):
complete_preferences = {}
defaults = {}
for k in AutoExportGltfAddonPreferences.__annotations__:
item = AutoExportGltfAddonPreferences.__annotations__[k]
default = item.keywords.get('default', None)
#complete_preferences[k] = default
defaults[k] = default
for key in list(settings.keys()):
if key in defaults:
if settings[key] != defaults[key]: # only write out values different from defaults
complete_preferences[key] = settings[key]
else:
complete_preferences[key] = settings[key]
return complete_preferences

View File

@ -1,6 +1,6 @@
import json
import bpy
from ...core.object_makers import (make_empty)
from blenvy.core.object_makers import (make_empty)
# these are mostly for when using this add-on together with the bevy_components add-on
@ -145,8 +145,8 @@ def duplicate_object(object, parent, combine_mode, destination_collection, bluep
duplicate_object(child, copy, combine_mode, destination_collection, blueprints_data, nester+" ")
# copies the contents of a collection into another one while replacing library instances with empties
def copy_hollowed_collection_into(source_collection, destination_collection, parent_empty=None, filter=None, blueprints_data=None, addon_prefs={}):
collection_instances_combine_mode = getattr(addon_prefs.auto_export, "collection_instances_combine_mode")
def copy_hollowed_collection_into(source_collection, destination_collection, parent_empty=None, filter=None, blueprints_data=None, settings={}):
collection_instances_combine_mode = getattr(settings.auto_export, "collection_instances_combine_mode")
for object in source_collection.objects:
if object.name.endswith("____bak"): # some objects could already have been handled, ignore them
@ -172,7 +172,7 @@ def copy_hollowed_collection_into(source_collection, destination_collection, par
parent_empty = collection_placeholder,
filter = filter,
blueprints_data = blueprints_data,
addon_prefs=addon_prefs
settings=settings
)
return {}
@ -204,20 +204,3 @@ def clear_hollow_scene(temp_scene, original_root_collection):
# reset original names
restore_original_names(original_root_collection)
# convenience utility to get lists of scenes
def get_scenes(addon_prefs):
level_scene_names= getattr(addon_prefs, "main_scene_names", []) #list(map(lambda scene: scene.name, getattr(addon_prefs,"main_scenes")))
library_scene_names = getattr(addon_prefs, "library_scene_names", []) #list(map(lambda scene: scene.name, getattr(addon_prefs,"library_scenes")))
level_scene_names= list(map(lambda scene: scene.name, getattr(addon_prefs,"main_scenes")))
library_scene_names = list(map(lambda scene: scene.name, getattr(addon_prefs,"library_scenes")))
print("level_scene_names", level_scene_names)
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]

View File

@ -155,7 +155,7 @@ class glTF2ExportUserExtension:
self.Extension = Extension
self.properties = bpy.context.scene.ExampleExtensionProperties
def gather_node_hook(self, gltf2_object, blender_object, export_settings):
def gather_node_hook(self, gltf2_object, blender_object, gltf_export_settings):
if self.properties.enabled:
if gltf2_object.extensions is None:
gltf2_object.extensions = {}
@ -193,7 +193,7 @@ def did_export_parameters_change(current_params, previous_params):
bpy.context.window.scene = library_scene
with bpy.context.temp_override(scene=library_scene):
print("active scene", bpy.context.scene)
export_gltf(gltf_output_path, export_settings)
export_gltf(gltf_output_path, gltf_export_settings)
bpy.context.window.scene = original_scene"""
"""
@ -296,16 +296,16 @@ def duplicate_object2(object, original_name):
settings = scene["glTF2ExportSettings"]
formatted_settings = dict(settings)
export_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings")
gltf_export_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings")
#check if params have changed
bpy.context.window_manager.gltf_settings_changed = sorted(json.loads(export_settings.as_string()).items()) != sorted(formatted_settings.items())
bpy.context.window_manager.gltf_settings_changed = sorted(json.loads(gltf_export_settings.as_string()).items()) != sorted(formatted_settings.items())
print("gltf NEW settings", formatted_settings, "OLD settings", export_settings, "CHANGED ?", bpy.context.window_manager.gltf_settings_changed)
print("gltf NEW settings", formatted_settings, "OLD settings", gltf_export_settings, "CHANGED ?", bpy.context.window_manager.gltf_settings_changed)
# now write new settings
export_settings.clear()
export_settings.write(json.dumps(formatted_settings))
gltf_export_settings.clear()
gltf_export_settings.write(json.dumps(formatted_settings))
# now reset the original gltf_settings

View File

@ -1,6 +1,6 @@
import bpy
from ...core.object_makers import make_empty
from blenvy.core.object_makers import make_empty
# TODO: replace this with placing scene level custom properties once support for that has been added to bevy_gltf
def upsert_scene_components(main_scenes):

View File

@ -1,19 +1,35 @@
import bpy
from bpy_types import (PropertyGroup)
from bpy.props import (EnumProperty, PointerProperty, StringProperty, BoolProperty, CollectionProperty, IntProperty)
from blenvy.settings import load_settings, upsert_settings, generate_complete_preferences_dict
# list of settings we do NOT want to save
settings_black_list = ['settings_save_enabled', 'dry_run']
def save_settings(settings, context):
if settings.settings_save_enabled:
settings_dict = generate_complete_preferences_dict(settings, AutoExportSettings, [])
print("save settings", settings, context, settings_dict)
upsert_settings(settings.settings_save_path, {key: settings_dict[key] for key in settings_dict.keys() if key not in settings_black_list})
class AutoExportSettings(PropertyGroup):
settings_save_path = ".blenvy_export_settings" # where to store data in bpy.texts
settings_save_enabled = BoolProperty(name="settings save enabled", default=True)
auto_export: BoolProperty(
name='Auto export',
description='Automatically export to gltf on save',
default=False
default=False,
update=save_settings
) # type: ignore
#### general
change_detection: BoolProperty(
name='Change detection',
description='Use change detection to determine what/if should be exported',
default=True
default=True,
update=save_settings
) # type: ignore
# scenes
@ -22,14 +38,16 @@ class AutoExportSettings(PropertyGroup):
export_scene_settings: BoolProperty(
name='Export scene settings',
description='Export scene settings ie AmbientLighting, Bloom, AO etc',
default=False
default=False,
update=save_settings
) # type: ignore
# blueprint settings
export_blueprints: BoolProperty(
name='Export Blueprints',
description='Replaces collection instances with an Empty with a BlueprintName custom property, and enabled a lot more features !',
default=True
default=True,
update=save_settings
) # type: ignore
export_separate_dynamic_and_static_objects: BoolProperty(
@ -37,13 +55,15 @@ class AutoExportSettings(PropertyGroup):
description="""For MAIN scenes only (aka levels), toggle this to generate 2 files per level:
- one with all dynamic data: collection or instances marked as dynamic/ saveable
- one with all static data: anything else that is NOT marked as dynamic""",
default=False
default=False,
update=save_settings
) # type: ignore
export_materials_library: BoolProperty(
name='Export materials library',
description='remove materials from blueprints and use the material library instead',
default=False
default=False,
update=save_settings
) # type: ignore
@ -63,28 +83,39 @@ class AutoExportSettings(PropertyGroup):
('EmbedExternal', 'EmbedExternal', 'treat instances of external (not specifified in the current blend file) collections (aka assets etc) as embeded objects and do not replace them with empties'),
#('Inject', 'Inject', 'inject components from sub collection instances into the curent object')
),
default='Split'
default='Split',
update=save_settings
) # type: ignore
export_marked_assets: BoolProperty(
name='Auto export marked assets',
description='Collections that have been marked as assets will be systematically exported, even if not in use in another scene',
default=True
default=True,
update=save_settings
) # type: ignore
dry_run: EnumProperty(
name="dry run",
description="debug/ develop helper to enable everything but the actual exporting of files",
items=(
("DISABLED", "Disabled","Run exports normally (no Dry run)"),
("NO_EXPORT", "No export", "do not actually export gltf files"),
("NO_PREPARE", "No prepare", "do not actually export gltf files AND do not prepare the exports either (ie no creating fake scenes etc)"),
)
) # type: ignore
# special property for gltf settings
gltf_settings_backup: StringProperty(
name="gltf settings backup",
description="backup for existing gltf settings so that we can restore them"
),
default="DISABLED",
) # type: ignore
def load_settings(self):
settings = load_settings(self.settings_save_path)
if settings is not None:
self.settings_save_enabled = False # we disable auto_saving of our settings
try:
for setting in settings:
print("setting", setting, settings[setting])
setattr(self, setting, settings[setting])
except: pass
# TODO: remove setting if there was a failure
self.settings_save_enabled = True

View File

@ -4,14 +4,14 @@ from bpy_types import (Operator)
from bpy.props import (StringProperty)
from bpy_extras.io_utils import ImportHelper
from ...settings import upsert_settings
from blenvy.settings import upsert_settings
from ..components.metadata import apply_customProperty_values_to_item_propertyGroups, apply_propertyGroup_values_to_item_customProperties, ensure_metadata_for_all_items
from ..propGroups.prop_groups import generate_propertyGroups_for_components
class ReloadRegistryOperator(Operator):
"""Reloads registry (schema file) from disk, generates propertyGroups for components & ensures all objects have metadata """
bl_idname = "object.reload_registry"
bl_idname = "blenvy.reload_components_registry"
bl_label = "Reload Registry"
bl_options = {"UNDO"}
@ -191,10 +191,8 @@ class OT_OpenSchemaFileBrowser(Operator, ImportHelper):
folder_path = os.path.dirname(file_path)
relative_path = os.path.relpath(self.filepath, folder_path)
registry = context.window_manager.components_registry
registry.schemaPath = relative_path
blenvy = context.window_manager.blenvy
blenvy.components.schema_path = relative_path
upsert_settings(blenvy.settings_save_path, {"components_schemaPath": relative_path})
return {'FINISHED'}
@ -206,14 +204,14 @@ class OT_select_object(Operator):
bl_label = "Select object"
bl_options = {"UNDO"}
object_name: StringProperty(
name="object_name",
description="object to select's name ",
target_name: StringProperty(
name="target name",
description="target to select's name ",
) # type: ignore
def execute(self, context):
if self.object_name:
object = bpy.data.objects[self.object_name]
if self.target_name:
object = bpy.data.objects[self.target_name]
scenes_of_object = list(object.users_scene)
if len(scenes_of_object) > 0:
bpy.ops.object.select_all(action='DESELECT')

View File

@ -5,10 +5,7 @@ import uuid
from pathlib import Path
from bpy_types import (PropertyGroup)
from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty)
from ...settings import load_settings
from ..propGroups.prop_groups import generate_propertyGroups_for_components
from ..components.metadata import ComponentMetadata, ensure_metadata_for_all_items
from ..components.metadata import ComponentMetadata
# helper class to store missing bevy types information
class MissingBevyType(bpy.types.PropertyGroup):
@ -16,58 +13,9 @@ class MissingBevyType(bpy.types.PropertyGroup):
name="type",
) # type: ignore
# helper function to deal with timer
def toggle_watcher(self, context):
#print("toggling watcher", self.watcher_enabled, watch_schema, self, bpy.app.timers)
if not self.watcher_enabled:
try:
bpy.app.timers.unregister(watch_schema)
except Exception as error:
pass
else:
self.watcher_active = True
bpy.app.timers.register(watch_schema)
def watch_schema():
self = bpy.context.window_manager.components_registry
# print("watching schema file for changes")
try:
stamp = os.stat(self.schemaFullPath).st_mtime
stamp = str(stamp)
if stamp != self.schemaTimeStamp and self.schemaTimeStamp != "":
print("FILE CHANGED !!", stamp, self.schemaTimeStamp)
# see here for better ways : https://stackoverflow.com/questions/11114492/check-if-a-file-is-not-open-nor-being-used-by-another-process
"""try:
os.rename(path, path)
#return False
except OSError: # file is in use
print("in use")
#return True"""
#bpy.ops.object.reload_registry()
# we need to add an additional delay as the file might not have loaded yet
bpy.app.timers.register(lambda: bpy.ops.object.reload_registry(), first_interval=1)
self.schemaTimeStamp = stamp
except Exception as error:
pass
return self.watcher_poll_frequency if self.watcher_enabled else None
# this is where we store the information for all available components
class ComponentsRegistry(PropertyGroup):
settings_save_path = ".bevy_components_settings" # where to store data in bpy.texts
schemaPath: bpy.props.StringProperty(
name="schema path",
description="path to the registry schema file",
default="registry.json"
)# type: ignore
schemaFullPath : bpy.props.StringProperty(
name="schema full path",
description="path to the registry schema file",
)# type: ignore
registry: bpy.props. StringProperty(
name="registry",
description="component registry"
@ -80,25 +28,6 @@ class ComponentsRegistry(PropertyGroup):
disable_all_object_updates: BoolProperty(name="disable_object_updates", default=False) # type: ignore
## file watcher
watcher_enabled: BoolProperty(name="Watcher_enabled", default=True, update=toggle_watcher)# type: ignore
watcher_active: BoolProperty(name = "Flag for watcher status", default = False)# type: ignore
watcher_poll_frequency: IntProperty(
name="watcher poll frequency",
description="frequency (s) at wich to poll for changes to the registry file",
min=1,
max=10,
default=1
)# type: ignore
schemaTimeStamp: StringProperty(
name="last timestamp of schema file",
description="",
default=""
)# type: ignore
missing_types_list: CollectionProperty(name="missing types list", type=MissingBevyType)# type: ignore
missing_types_list_index: IntProperty(name = "Index for missing types list", default = 0)# type: ignore
@ -217,29 +146,22 @@ class ComponentsRegistry(PropertyGroup):
@classmethod
def register(cls):
bpy.types.WindowManager.components_registry = PointerProperty(type=ComponentsRegistry)
bpy.context.window_manager.components_registry.watcher_active = False
@classmethod
def unregister(cls):
bpy.context.window_manager.components_registry.watcher_active = False
for propgroup_name in cls.component_propertyGroups.keys():
try:
delattr(ComponentMetadata, propgroup_name)
#print("unregistered propertyGroup", propgroup_name)
except Exception as error:
pass
#print("failed to remove", error, "ComponentMetadata")
try:
bpy.app.timers.unregister(watch_schema)
except Exception as error:
pass
del bpy.types.WindowManager.components_registry
def load_schema(self):
print("load schema", self)
blenvy = bpy.context.window_manager.blenvy
component_settings = blenvy.components
# cleanup previous data if any
self.propGroupIdCounter = 0
self.long_names_to_propgroup_names.clear()
@ -251,23 +173,13 @@ class ComponentsRegistry(PropertyGroup):
self.invalid_components.clear()
# now prepare paths to load data
file_path = bpy.data.filepath
# Get the folder
folder_path = os.path.dirname(file_path)
path = os.path.join(folder_path, self.schemaPath)
self.schemaFullPath = path
f = Path(bpy.path.abspath(path)) # make a path object of abs path
with open(path) as f:
with open(component_settings.schema_path_full) as f:
data = json.load(f)
defs = data["$defs"]
self.registry = json.dumps(defs) # FIXME:meh ?
# start timer
if not self.watcher_active and self.watcher_enabled:
self.watcher_active = True
print("registering function", watch_schema)
bpy.app.timers.register(watch_schema)
component_settings.start_schema_watcher()
# we load the json once, so we do not need to do it over & over again
@ -278,17 +190,6 @@ class ComponentsRegistry(PropertyGroup):
def has_type_infos(self):
return len(self.type_infos.keys()) != 0
def load_settings(self):
print("loading settings")
settings = load_settings(self.settings_save_path)
if settings!= None:
self.schemaPath = settings["components_schemaPath"]
self.load_schema()
generate_propertyGroups_for_components()
ensure_metadata_for_all_items()
# we keep a list of component propertyGroup around
def register_component_propertyGroup(self, name, propertyGroup):
self.component_propertyGroups[name] = propertyGroup

View File

@ -3,13 +3,13 @@ import bpy
from bpy_types import (UIList)
from bpy.props import (StringProperty)
from ..components.operators import OT_rename_component, RemoveComponentFromAllItemsOperator, RemoveComponentOperator
from ..utils import get_selection_type
from ..components.operators import OT_rename_component, RemoveComponentFromAllItemsOperator
from .operators import(
COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_ALL,
COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_CURRENT,
OT_OpenSchemaFileBrowser,
OT_select_component_name_to_replace,
OT_select_object, ReloadRegistryOperator,
OT_OpenSchemaFileBrowser, ReloadRegistryOperator,
COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_ALL,
COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_CURRENT)
@ -32,23 +32,24 @@ class BEVY_COMPONENTS_PT_Configuration(bpy.types.Panel):
def draw(self, context):
layout = self.layout
registry = context.window_manager.components_registry
blenvy = context.window_manager.blenvy
component_settings = blenvy.components
row = layout.row()
col = row.column()
col.enabled = False
col.prop(registry, "schemaPath", text="Registry Schema path")
col.prop(component_settings, "schema_path", text="Registry Schema path")
col = row.column()
col.operator(OT_OpenSchemaFileBrowser.bl_idname, text="Browse for registry schema file (json)")
col.operator("blenvy.open_schemafilebrowser", text="Browse for registry schema file (json)")
layout.separator()
layout.operator(ReloadRegistryOperator.bl_idname, text="reload registry" , icon="FILE_REFRESH")
layout.operator("blenvy.reload_components_registry", text="reload registry" , icon="FILE_REFRESH")
layout.separator()
row = layout.row()
row.prop(registry, "watcher_enabled", text="enable registry file polling")
row.prop(registry, "watcher_poll_frequency", text="registry file poll frequency (s)")
row.prop(component_settings, "watcher_enabled", text="enable registry file polling")
row.prop(component_settings, "watcher_poll_frequency", text="registry file poll frequency (s)")
layout.separator()
layout.separator()
@ -78,7 +79,7 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
col.label(text=item)
def draw_invalid_or_unregistered(self, layout, status, component_name, object):
def draw_invalid_or_unregistered(self, layout, status, component_name, target):
available_components = bpy.context.window_manager.components_list
registry = bpy.context.window_manager.components_registry
registry_has_type_infos = registry.has_type_infos()
@ -89,8 +90,8 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
col.label(text=component_name)
col = row.column()
operator = col.operator(OT_select_object.bl_idname, text=object.name)
operator.object_name = object.name
operator = col.operator("object.select", text=target.name)
operator.target_name = target.name
col = row.column()
col.label(text=status)
@ -99,22 +100,24 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
col.prop(available_components, "list", text="")
col = row.column()
operator = col.operator(OT_rename_component.bl_idname, text="", icon="SHADERFX") #rename
operator = col.operator("object.rename_bevy_component", text="", icon="SHADERFX") #rename
new_name = registry.type_infos[available_components.list]['long_name'] if available_components.list in registry.type_infos else ""
operator.original_name = component_name
operator.target_objects = json.dumps([object.name])
operator.target_objects = json.dumps([target.name])
operator.new_name = new_name
col.enabled = registry_has_type_infos and component_name != "" and component_name != new_name
col = row.column()
operator = col.operator(RemoveComponentOperator.bl_idname, text="", icon="X")
operator.object_name = object.name
operator = col.operator("object.remove_bevy_component", text="", icon="X")
operator.item_name = target.name
operator.component_name = component_name
operator.item_type = get_selection_type(target)
col = row.column()
col = row.column()
operator = col.operator(OT_select_component_name_to_replace.bl_idname, text="", icon="EYEDROPPER") #text="select for rename",
operator = col.operator("object.select_component_name_to_replace", text="", icon="EYEDROPPER") #text="select for rename",
operator.component_name = component_name
def draw(self, context):

View File

@ -0,0 +1,131 @@
import os
import bpy
from bpy_types import (PropertyGroup)
from bpy.props import (EnumProperty, PointerProperty, StringProperty, BoolProperty, CollectionProperty, IntProperty)
from blenvy.settings import load_settings, upsert_settings, generate_complete_preferences_dict
from .propGroups.prop_groups import generate_propertyGroups_for_components
from .components.metadata import ensure_metadata_for_all_items
# list of settings we do NOT want to save
settings_black_list = ['settings_save_enabled', 'watcher_active']
def save_settings(settings, context):
if settings.settings_save_enabled:
settings_dict = generate_complete_preferences_dict(settings, ComponentsSettings, [])
print("save settings", settings, context,settings_dict)
upsert_settings(settings.settings_save_path, {key: settings_dict[key] for key in settings_dict.keys() if key not in settings_black_list})
# helper function to deal with timer
def toggle_watcher(self, context):
#print("toggling watcher", self.watcher_enabled, watch_schema, self, bpy.app.timers)
if not self.watcher_enabled:
try:
bpy.app.timers.unregister(watch_schema)
except Exception as error:
pass
else:
self.watcher_active = True
bpy.app.timers.register(watch_schema)
save_settings(self, context)
def watch_schema():
blenvy = bpy.context.window_manager.blenvy
component_settings = blenvy.components
#print("watching schema file for changes")
try:
stamp = os.stat(component_settings.schema_path_full).st_mtime
stamp = str(stamp)
if stamp != component_settings.schemaTimeStamp and component_settings.schemaTimeStamp != "":
print("FILE CHANGED !!", stamp, component_settings.schemaTimeStamp)
# see here for better ways : https://stackoverflow.com/questions/11114492/check-if-a-file-is-not-open-nor-being-used-by-another-process
"""try:
os.rename(path, path)
#return False
except OSError: # file is in use
print("in use")
#return True"""
#bpy.ops.object.reload_registry()
# we need to add an additional delay as the file might not have loaded yet
bpy.app.timers.register(lambda: bpy.ops.object.reload_registry(), first_interval=1)
component_settings.schemaTimeStamp = stamp
except Exception as error:
pass
return component_settings.watcher_poll_frequency if component_settings.watcher_enabled else None
class ComponentsSettings(PropertyGroup):
settings_save_path = ".blenvy_components_settings" # where to store data in bpy.texts
settings_save_enabled: BoolProperty(name="settings save enabled", default=True)# type: ignore
schema_path: StringProperty(
name="schema path",
description="path to the registry schema file",
default="registry.json",
update=save_settings
)# type: ignore
schema_path_full: StringProperty(
name="schema full path",
description="path to the registry schema file",
get=lambda self: os.path.abspath(os.path.join(os.path.dirname(bpy.data.filepath), self.schema_path))
) # type: ignore
watcher_enabled: BoolProperty(name="Watcher_enabled", default=True, update=toggle_watcher)# type: ignore
watcher_active: BoolProperty(name = "Flag for watcher status", default = False)# type: ignore
watcher_poll_frequency: IntProperty(
name="watcher poll frequency",
description="frequency (s) at wich to poll for changes to the registry file",
min=1,
max=10,
default=1,
update=save_settings
)# type: ignore
schemaTimeStamp: StringProperty(
name="last timestamp of schema file",
description="",
default="",
update=save_settings
)# type: ignore
@classmethod
def register(cls):
pass
#bpy.context.window_manager.blenvy.components.watcher_active = False
@classmethod
def unregister(cls):
bpy.context.window_manager.blenvy.components.watcher_active = False
try:
bpy.app.timers.unregister(watch_schema)
except Exception as error:
pass
def start_schema_watcher(self):
# start timer
if not self.watcher_active and self.watcher_enabled:
self.watcher_active = True
print("registering function", watch_schema)
bpy.app.timers.register(watch_schema)
def load_settings(self):
settings = load_settings(self.settings_save_path)
print("component settings", settings)
if settings is not None:
self.settings_save_enabled = False # we disable auto_saving of our settings
try:
for setting in settings:
print("setting", setting, settings[setting])
setattr(self, setting, settings[setting])
except:pass
try:
registry = bpy.context.components_registry
registry.load_schema()
generate_propertyGroups_for_components()
ensure_metadata_for_all_items()
except:pass
self.settings_save_enabled = True

View File

@ -0,0 +1,20 @@
def draw_settings_ui(layout, component_settings):
row = layout.row()
col = row.column()
col.enabled = False
col.prop(component_settings, "schema_path", text="Registry Schema path")
col = row.column()
col.operator(operator="blenvy.open_schemafilebrowser", text="Browse for registry schema file (json)")
layout.separator()
layout.operator(operator="blenvy.reload_components_registry", text="reload registry" , icon="FILE_REFRESH")
layout.separator()
row = layout.row()
row.prop(component_settings, "watcher_enabled", text="enable registry file polling")
row.prop(component_settings, "watcher_poll_frequency", text="registry file poll frequency (s)")
layout.separator()
layout.separator()

View File

@ -4,12 +4,12 @@ import bpy
from .asset_helpers import does_asset_exist, get_user_assets, get_user_assets_as_list
def scan_assets(scene, blueprints_data, addon_prefs):
project_root_path = getattr(addon_prefs, "project_root_path")
export_output_folder = getattr(addon_prefs,"export_output_folder")
levels_path = getattr(addon_prefs,"levels_path")
blueprints_path = getattr(addon_prefs, "blueprints_path")
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
def scan_assets(scene, blueprints_data, settings):
project_root_path = getattr(settings, "project_root_path")
export_output_folder = getattr(settings,"export_output_folder")
levels_path = getattr(settings,"levels_path")
blueprints_path = getattr(settings, "blueprints_path")
export_gltf_extension = getattr(settings, "export_gltf_extension")
relative_blueprints_path = os.path.relpath(blueprints_path, project_root_path)
blueprint_instance_names_for_scene = blueprints_data.blueprint_instances_per_main_scene.get(scene.name, None)
@ -61,9 +61,9 @@ def get_userTextures():
textures.extend([x.image.filepath for x in mat_slot.material.node_tree.nodes if x.type=='TEX_IMAGE'])
print("textures", textures)
def get_blueprint_assets_tree(blueprint, blueprints_data, parent, addon_prefs):
blueprints_path = getattr(addon_prefs, "blueprints_path")
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
def get_blueprint_assets_tree(blueprint, blueprints_data, parent, settings):
blueprints_path = getattr(settings, "blueprints_path")
export_gltf_extension = getattr(settings, "export_gltf_extension")
assets_list = []
@ -80,7 +80,7 @@ def get_blueprint_assets_tree(blueprint, blueprints_data, parent, addon_prefs):
assets_list.append({"name": child_blueprint.name, "path": blueprint_exported_path, "type": "MODEL", "generated": True,"internal":blueprint.local, "parent": blueprint.name})
# and add sub stuff
sub_assets_lists = get_blueprint_assets_tree(child_blueprint, blueprints_data, parent=child_blueprint.name, addon_prefs=addon_prefs)
sub_assets_lists = get_blueprint_assets_tree(child_blueprint, blueprints_data, parent=child_blueprint.name, settings=settings)
assets_list += sub_assets_lists
direct_assets = get_user_assets_as_list(blueprint.collection)
@ -90,9 +90,9 @@ def get_blueprint_assets_tree(blueprint, blueprints_data, parent, addon_prefs):
assets_list += direct_assets
return assets_list
def get_main_scene_assets_tree(main_scene, blueprints_data, addon_prefs):
blueprints_path = getattr(addon_prefs, "blueprints_path")
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
def get_main_scene_assets_tree(main_scene, blueprints_data, settings):
blueprints_path = getattr(settings, "blueprints_path")
export_gltf_extension = getattr(settings, "export_gltf_extension")
blueprint_instance_names_for_scene = blueprints_data.blueprint_instances_per_main_scene.get(main_scene.name, None)
assets_list = get_user_assets_as_list(main_scene)
@ -109,7 +109,7 @@ def get_main_scene_assets_tree(main_scene, blueprints_data, addon_prefs):
if blueprint_exported_path is not None and not does_asset_exist(assets_list, blueprint_exported_path):
assets_list.append({"name": blueprint.name, "path": blueprint_exported_path, "type": "MODEL", "generated": True, "internal":blueprint.local, "parent": None})
assets_list += get_blueprint_assets_tree(blueprint, blueprints_data, parent=blueprint.name, addon_prefs=addon_prefs)
assets_list += get_blueprint_assets_tree(blueprint, blueprints_data, parent=blueprint.name, settings=settings)
print("TOTAL ASSETS", assets_list)
return assets_list

View File

@ -52,7 +52,6 @@ class OT_add_bevy_asset(Operator):
) # type: ignore
def execute(self, context):
assets = []
blueprint_assets = self.target_type == 'BLUEPRINT'
target = None
if blueprint_assets:
@ -61,7 +60,9 @@ class OT_add_bevy_asset(Operator):
target = bpy.data.scenes[self.target_name]
assets = get_user_assets(target)
asset = {"name": self.asset_name, "type": self.asset_type, "path": self.asset_path}
print('assets', assets, target)
if not does_asset_exist(target, asset):
print("add asset", target, asset)
upsert_asset(target, asset)
#assets.append({"name": self.asset_name, "type": self.asset_type, "path": self.asset_path, "internal": False})
@ -202,7 +203,7 @@ class OT_test_bevy_assets(Operator):
blenvy = context.window_manager.blenvy
settings = blenvy
blueprints_registry = context.window_manager.blueprints_registry
blueprints_registry.add_blueprints_data()
blueprints_registry.refresh_blueprints()
blueprints_data = blueprints_registry.blueprints_data
for scene in blenvy.main_scenes:

View File

@ -74,7 +74,7 @@ class Blenvy_assets(bpy.types.Panel):
asset_registry = context.window_manager.assets_registry
blueprints_registry = context.window_manager.blueprints_registry
blueprints_registry.add_blueprints_data()
#blueprints_registry.refresh_blueprints()
blueprints_data = blueprints_registry.blueprints_data
name = "world"
@ -85,9 +85,12 @@ class Blenvy_assets(bpy.types.Panel):
settings = SimpleNamespace(**settings)
if panel:
for scene in blenvy.main_scenes:
#print("dfs")
for scene_selector in blenvy.main_scenes:
scene = bpy.data.scenes[scene_selector.name]
#get_main_scene_assets_tree(scene, blueprints_data, settings)
user_assets = get_user_assets(scene)
#print("user assets", user_assets, scene)
row = panel.row()
scene_assets_panel = draw_assets(layout=row, name=scene.name, title=f"{scene.name} Assets", asset_registry=asset_registry, user_assets=user_assets, target_type="SCENE", target_name=scene.name)
"""if scene.name in blueprints_data.blueprint_instances_per_main_scene:

View File

@ -1,19 +0,0 @@
def draw_settings_ui(layout, registry):
row = layout.row()
col = row.column()
col.enabled = False
col.prop(registry, "schemaPath", text="Registry Schema path")
col = row.column()
col.operator(operator="blenvy.open_schemafilebrowser", text="Browse for registry schema file (json)")
layout.separator()
layout.operator(operator="object.reload_registry", text="reload registry" , icon="FILE_REFRESH")
layout.separator()
row = layout.row()
row.prop(registry, "watcher_enabled", text="enable registry file polling")
row.prop(registry, "watcher_poll_frequency", text="registry file poll frequency (s)")
layout.separator()
layout.separator()

View File

@ -25,12 +25,12 @@ def inject_export_path_into_internal_blueprints(internal_blueprints, blueprints_
blueprint_exported_path = os.path.join(blueprints_path, f"{blueprint.name}{gltf_extension}")
blueprint.collection["export_path"] = blueprint_exported_path
def inject_blueprints_list_into_main_scene(scene, blueprints_data, addon_prefs):
project_root_path = getattr(addon_prefs, "project_root_path")
assets_path = getattr(addon_prefs,"assets_path")
levels_path = getattr(addon_prefs,"levels_path")
blueprints_path = getattr(addon_prefs, "blueprints_path")
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
def inject_blueprints_list_into_main_scene(scene, blueprints_data, settings):
project_root_path = getattr(settings, "project_root_path")
assets_path = getattr(settings,"assets_path")
levels_path = getattr(settings,"levels_path")
blueprints_path = getattr(settings, "blueprints_path")
export_gltf_extension = getattr(settings, "export_gltf_extension")
# print("injecting assets/blueprints data into scene")
assets_list_name = f"assets_list_{scene.name}_components"

View File

@ -8,9 +8,20 @@ from bpy_types import (PropertyGroup)
from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty)
from ..settings import load_settings
from ..gltf_auto_export.helpers.helpers_scenes import get_scenes
from ..core.scene_helpers import get_main_and_library_scenes
from .blueprints_scan import blueprints_scan
def refresh_blueprints():
try:
blueprints_registry = bpy.context.window_manager.blueprints_registry
blueprints_registry.refresh_blueprints()
#print('refresh blueprints')
except:pass
return 3
# this is where we store the information for all available Blueprints
class BlueprintsRegistry(PropertyGroup):
blueprints_data = {}
@ -40,17 +51,25 @@ class BlueprintsRegistry(PropertyGroup):
@classmethod
def register(cls):
bpy.types.WindowManager.blueprints_registry = PointerProperty(type=BlueprintsRegistry)
bpy.app.timers.register(refresh_blueprints)
@classmethod
def unregister(cls):
try:
bpy.app.timers.unregister(refresh_blueprints)
except: pass
del bpy.types.WindowManager.blueprints_registry
def add_blueprint(self, blueprint):
self.blueprints_list.append(blueprint)
def add_blueprints_data(self):
def refresh_blueprints(self):
blenvy = bpy.context.window_manager.blenvy
addon_prefs = blenvy
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
blueprints_data = blueprints_scan(level_scenes, library_scenes, addon_prefs)
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)
self.blueprints_data = blueprints_data
"""for blueprint in blueprints_data.blueprints:
self.add_blueprint(blueprint)"""

View File

@ -7,8 +7,8 @@ from .blueprint import Blueprint
# - marked as asset
# - with the "auto_export" flag
# https://blender.stackexchange.com/questions/167878/how-to-get-all-collections-of-the-current-scene
def blueprints_scan(main_scenes, library_scenes, addon_prefs):
export_marked_assets = getattr(addon_prefs.auto_export,"export_marked_assets")
def blueprints_scan(main_scenes, library_scenes, settings):
export_marked_assets = getattr(settings.auto_export, "export_marked_assets")
blueprints = {}
blueprints_from_objects = {}

View File

@ -14,15 +14,18 @@ class GLTF_PT_auto_export_blueprints_list(bpy.types.Panel):
@classmethod
def poll(cls, context):
return context.window_manager.blenvy.mode == 'BLUEPRINTS'
return context.window_manager.blenvy.mode == 'BLUEPRINTS' if 'blenvy' in context.window_manager else False
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
asset_registry = context.window_manager.assets_registry
blueprint_registry = context.window_manager.blueprints_registry
for blueprint in context.window_manager.blueprints_registry.blueprints_list:
blueprint_registry.refresh_blueprints()
for blueprint in blueprint_registry.blueprints_data.blueprints:
row = layout.row()
row.label(icon="RIGHTARROW")
row.label(text=blueprint.name)

View File

@ -1,31 +1,48 @@
import os
import bpy
from bpy_types import (PropertyGroup)
from bpy.props import (EnumProperty, PointerProperty, StringProperty, CollectionProperty, IntProperty)
from bpy.props import (BoolProperty, EnumProperty, PointerProperty, StringProperty, CollectionProperty, IntProperty)
from .scene_helpers import SceneSelector
from ..settings import upsert_settings, load_settings
import blenvy.gltf_auto_export.settings as auto_export_settings
from ..settings import upsert_settings, load_settings, generate_complete_preferences_dict
import blenvy.add_ons.auto_export.settings as auto_export_settings
import blenvy.add_ons.bevy_components.settings as component_settings
def update_scene_lists(self, context):
blenvy = self# context.window_manager.blenvy
# 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', ''
]
def save_settings(settings, context):
if settings.settings_save_enabled:
settings_dict = generate_complete_preferences_dict(settings, BlenvyManager, [])
print("save settings", settings, context, settings_dict)
# upsert_settings(settings.settings_save_path, {key: settings_dict[key] for key in settings_dict.keys() if key not in settings_black_list})
def update_scene_lists(blenvy, context):
blenvy.main_scene_names = [scene.name for scene in blenvy.main_scenes] # FIXME: unsure
blenvy.library_scene_names = [scene.name for scene in blenvy.library_scenes] # FIXME: unsure
upsert_settings(blenvy.settings_save_path, {"common_main_scene_names": [scene.name for scene in blenvy.main_scenes]})
upsert_settings(blenvy.settings_save_path, {"common_library_scene_names": [scene.name for scene in blenvy.library_scenes]})
def update_asset_folders(self, context):
blenvy = self # context.window_manager.blenvy
def update_asset_folders(blenvy, context):
asset_path_names = ['project_root_path', 'assets_path', 'blueprints_path', 'levels_path', 'materials_path']
for asset_path_name in asset_path_names:
upsert_settings(blenvy.settings_save_path, {asset_path_name: getattr(blenvy, asset_path_name)})
def update_mode(self, context):
blenvy = self
def update_mode(blenvy, context):
upsert_settings(blenvy.settings_save_path, {"mode": blenvy.mode })
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
except:
return True
class BlenvyManager(PropertyGroup):
settings_save_path = ".blenvy_settings" # where to store data in bpy.texts
settings_save_path = ".blenvy_common_settings" # where to store data in bpy.texts
settings_save_enabled = BoolProperty(name="settings save enabled", default=True)
mode: EnumProperty(
items=(
@ -101,37 +118,29 @@ class BlenvyManager(PropertyGroup):
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
#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
#library_scene_names = [] # FIXME: unsure
# sub ones
auto_export: PointerProperty(type=auto_export_settings.AutoExportSettings) # type: ignore
#components: PointerProperty(type=bevy_component_settings.ComponentSettings) # type: ignore
components: PointerProperty(type=component_settings.ComponentsSettings) # type: ignore
def is_scene_ok(self, scene):
try:
operator = bpy.context.space_data.active_operator
return scene.name not in operator.main_scenes and scene.name not in operator.library_scenes
except:
return True
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
@classmethod
def register(cls):
bpy.types.WindowManager.main_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="main scene", description="main_scene_picker", poll=cls.is_scene_ok)
bpy.types.WindowManager.library_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="library scene", description="library_scene_picker", poll=cls.is_scene_ok)
bpy.types.WindowManager.blenvy = PointerProperty(type=BlenvyManager)
@classmethod
def unregister(cls):
del bpy.types.WindowManager.blenvy
del bpy.types.WindowManager.main_scene
del bpy.types.WindowManager.library_scene
def load_settings(self):
print("LOAD SETTINGS")
settings = load_settings(self.settings_save_path)
if settings is not None:
if "mode" in settings:
@ -149,3 +158,9 @@ class BlenvyManager(PropertyGroup):
for asset_path_name in asset_path_names:
if asset_path_name in settings:
setattr(self, asset_path_name, settings[asset_path_name])
# now load auto_export settings
self.auto_export.load_settings()
# now load component settings
self.components.load_settings()

View File

@ -8,7 +8,7 @@ class OT_switch_bevy_tooling(Operator):
"""Switch bevy tooling"""
bl_idname = "bevy.tooling_switch"
bl_label = "Switch bevy tooling"
bl_options = {"UNDO"}
#bl_options = {}
tool: EnumProperty(

View File

@ -7,6 +7,23 @@ class SceneSelector(bpy.types.PropertyGroup):
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

View File

@ -95,19 +95,19 @@ class SCENES_LIST_OT_actions(Operator):
if self.action == 'ADD':
new_scene_name = None
if self.scene_type == "LEVEL":
if context.window_manager.main_scene:
new_scene_name = context.window_manager.main_scene.name
if context.window_manager.blenvy.main_scene_selector:
new_scene_name = context.window_manager.blenvy.main_scene_selector.name
else:
if context.window_manager.library_scene:
new_scene_name = context.window_manager.library_scene.name
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
if self.scene_type == "LEVEL":
context.window_manager.main_scene = None
context.window_manager.blenvy.main_scene_selector = None
else:
context.window_manager.library_scene = None
context.window_manager.blenvy.library_scene_selector = None
setattr(source, target_index, len(target) - 1)

View File

@ -1,7 +1,6 @@
import bpy
import blenvy.bevy_components.ui as components_ui
import blenvy.gltf_auto_export.ui as auto_export_ui
from blenvy.settings import load_settings
import blenvy.add_ons.bevy_components.ui as components_ui
import blenvy.add_ons.auto_export.ui as auto_export_ui
# from ...bevy_components.components import ui# as components_ui
######################################################
@ -105,7 +104,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel):
rows = 2
row = section.row()
row.label(text="main scenes")
row.prop(context.window_manager, "main_scene", text='')
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)
@ -116,7 +115,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel):
add_operator.action = 'ADD'
add_operator.scene_type = 'LEVEL'
#add_operator.operator = operator
sub_row.enabled = context.window_manager.main_scene is not None
sub_row.enabled = blenvy.main_scene_selector is not None
sub_row = col.row()
remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="")
@ -127,7 +126,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel):
# library scenes
row = section.row()
row.label(text="library scenes")
row.prop(context.window_manager, "library_scene", text='')
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)
@ -137,7 +136,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel):
add_operator = sub_row.operator("scene_list.list_action", icon='ADD', text="")
add_operator.action = 'ADD'
add_operator.scene_type = 'LIBRARY'
sub_row.enabled = context.window_manager.library_scene is not None
sub_row.enabled = blenvy.library_scene_selector is not None
sub_row = col.row()
@ -149,7 +148,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel):
header, panel = layout.panel("components", default_closed=False)
header.label(text="Components")
if panel:
components_ui.draw_settings_ui(panel, context.window_manager.components_registry)
components_ui.draw_settings_ui(panel, blenvy.components)
header, panel = layout.panel("auto_export", default_closed=False)
header.label(text="Auto Export")

View File

@ -1,14 +0,0 @@
import bpy
import json
def get_standard_exporter_settings():
standard_gltf_exporter_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else None
if standard_gltf_exporter_settings != None:
try:
standard_gltf_exporter_settings = json.loads(standard_gltf_exporter_settings.as_string())
except:
standard_gltf_exporter_settings = {}
else:
standard_gltf_exporter_settings = {}
return standard_gltf_exporter_settings

View File

@ -1,228 +0,0 @@
import json
import bpy
from bpy.types import Operator
#from ..ui.main import GLTF_PT_auto_export_general, GLTF_PT_auto_export_main, GLTF_PT_auto_export_root
from .preferences import (AutoExportGltfAddonPreferences, AutoExportGltfPreferenceNames)
from .auto_export import auto_export
from ..helpers.generate_complete_preferences_dict import generate_complete_preferences_dict_auto
class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences):#, ExportHelper):
"""auto export gltf"""
#bl_idname = "object.xxx"
bl_idname = "export_scenes.auto_gltf"
bl_label = "Apply settings"
bl_options = {'PRESET'} # we do not add UNDO otherwise it leads to an invisible operation that resets the state of the saved serialized scene, breaking compares for normal undo/redo operations
# ExportHelper mixin class uses this
#filename_ext = ''
#filepath: bpy.props.StringProperty(subtype="FILE_PATH", default="") # type: ignore
#list of settings (other than purely gltf settings) whose change should trigger a re-generation of gltf files
white_list = [
'auto_export',
'project_root_path',
'assets_path',
'change_detection',
'export_scene_settings',
'main_scene_names',
'library_scene_names',
'export_blueprints',
'blueprints_path',
'export_marked_assets',
'collection_instances_combine_mode',
'levels_path',
'export_separate_dynamic_and_static_objects',
'export_materials_library',
'materials_path',
]
@classmethod
def register(cls):
pass
@classmethod
def unregister(cls):
pass
def format_settings(self):
# find all props to save
exceptional = [
# options that don't start with 'export_'
'collection_instances_combine_mode',
]
all_props = self.properties
export_props = {
x: getattr(self, x) for x in dir(all_props)
if (x.startswith("export_") or x in exceptional) and all_props.get(x) is not None
}
# we inject all that we need, the above is not sufficient
for (k, v) in self.properties.items():
if k in self.white_list or k not in AutoExportGltfPreferenceNames:
value = v
# FIXME: really weird having to do this
if k == "collection_instances_combine_mode":
value = self.collection_instances_combine_mode
if k == "export_materials":
value = self.export_materials
export_props[k] = value
# we add main & library scene names to our preferences
return export_props
def save_settings(self, context):
print("save settings")
auto_export_settings = self.format_settings()
stored_settings = bpy.data.texts[".gltf_auto_export_settings"] if ".gltf_auto_export_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_settings")
stored_settings.clear()
auto_export_settings = generate_complete_preferences_dict_auto(auto_export_settings)
stored_settings.write(json.dumps(auto_export_settings))
print("saved settings", auto_export_settings)
#print("saving settings", bpy.data.texts[".gltf_auto_export_settings"].as_string(), "raw", json.dumps(export_props))
def load_settings(self, context):
print("loading settings")
settings = None
try:
settings = bpy.data.texts[".gltf_auto_export_settings"].as_string()
settings = json.loads(settings)
except: pass
self.will_save_settings = False
if settings:
#print("loading settings in invoke AutoExportGLTF", settings)
try:
for (k, v) in settings.items():
#print("loading setting", k, v)
setattr(self, k, v)
self.will_save_settings = True
# Update filter if user saved settings
if hasattr(self, 'export_format'):
self.filter_glob = '*.glb' if self.export_format == 'GLB' else '*.gltf'
# inject scenes data
if hasattr(self, 'main_scene_names'):
main_scenes = self.main_scenes
main_scenes.clear()
for item_name in self.main_scene_names:
item = main_scenes.add()
item.name = item_name
if hasattr(self, 'library_scene_names'):
library_scenes = self.library_scenes
library_scenes.clear()
for item_name in self.library_scene_names:
item = library_scenes.add()
item.name = item_name
except Exception as error:
print("error", error)
self.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings")
bpy.data.texts.remove(bpy.data.texts[".gltf_auto_export_settings"])
else:
self.will_save_settings = True
"""
This should ONLY be run when actually doing exports/aka calling auto_export function, because we only care about the difference in settings between EXPORTS
"""
def did_export_settings_change(self):
return True
# compare both the auto export settings & the gltf settings
previous_auto_settings = bpy.data.texts[".gltf_auto_export_settings_previous"] if ".gltf_auto_export_settings_previous" in bpy.data.texts else None
previous_gltf_settings = bpy.data.texts[".blenvy_gltf_settings_previous"] if ".blenvy_gltf_settings_previous" in bpy.data.texts else None
current_auto_settings = bpy.data.texts[".gltf_auto_export_settings"] if ".gltf_auto_export_settings" in bpy.data.texts else None
current_gltf_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else None
#check if params have changed
# if there were no setting before, it is new, we need export
changed = False
if previous_auto_settings == None:
#print("previous settings missing, exporting")
changed = True
elif previous_gltf_settings == None:
#print("previous gltf settings missing, exporting")
previous_gltf_settings = bpy.data.texts.new(".blenvy_gltf_settings_previous")
previous_gltf_settings.write(json.dumps({}))
if current_gltf_settings == None:
current_gltf_settings = bpy.data.texts.new(".blenvy_gltf_settings")
current_gltf_settings.write(json.dumps({}))
changed = True
else:
auto_settings_changed = sorted(json.loads(previous_auto_settings.as_string()).items()) != sorted(json.loads(current_auto_settings.as_string()).items()) if current_auto_settings != None else False
gltf_settings_changed = sorted(json.loads(previous_gltf_settings.as_string()).items()) != sorted(json.loads(current_gltf_settings.as_string()).items()) if current_gltf_settings != None else False
"""print("auto settings previous", sorted(json.loads(previous_auto_settings.as_string()).items()))
print("auto settings current", sorted(json.loads(current_auto_settings.as_string()).items()))
print("auto_settings_changed", auto_settings_changed)
print("gltf settings previous", sorted(json.loads(previous_gltf_settings.as_string()).items()))
print("gltf settings current", sorted(json.loads(current_gltf_settings.as_string()).items()))
print("gltf_settings_changed", gltf_settings_changed)"""
changed = auto_settings_changed or gltf_settings_changed
# now write the current settings to the "previous settings"
if current_auto_settings != None:
previous_auto_settings = bpy.data.texts[".gltf_auto_export_settings_previous"] if ".gltf_auto_export_settings_previous" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_settings_previous")
previous_auto_settings.clear()
previous_auto_settings.write(current_auto_settings.as_string()) # TODO : check if this is always valid
if current_gltf_settings != None:
previous_gltf_settings = bpy.data.texts[".blenvy_gltf_settings_previous"] if ".blenvy_gltf_settings_previous" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings_previous")
previous_gltf_settings.clear()
previous_gltf_settings.write(current_gltf_settings.as_string())
return changed
def did_objects_change(self):
# FIXME: add it back
return {}
def execute(self, context):
print("execute auto export", context.window_manager.blenvy.auto_export)
blenvy = context.window_manager.blenvy
auto_export_settings = blenvy.auto_export
bpy.context.window_manager.auto_export_tracker.disable_change_detection()
if self.direct_mode:
self.load_settings(context)
if self.will_save_settings:
self.save_settings(context)
#print("self", self.auto_export)
if auto_export_settings.auto_export: # only do the actual exporting if auto export is actually enabled
print("auto export")
#changes_per_scene = context.window_manager.auto_export_tracker.changed_objects_per_scene
#& do the export
# determine changed objects
changes_per_scene = self.did_objects_change()
# determine changed parameters
params_changed = self.did_export_settings_change()
auto_export(changes_per_scene, params_changed, blenvy)
# cleanup
# reset the list of changes in the tracker
bpy.context.window_manager.auto_export_tracker.clear_changes()
print("AUTO EXPORT DONE")
bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=0.1)
else:
print("auto export disabled, skipping")
return {'FINISHED'}
def invoke(self, context, event):
print("invoke")
bpy.context.window_manager.auto_export_tracker.disable_change_detection()
self.load_settings(context)
return context.window_manager.invoke_props_dialog(self, title="Auto export", width=640)
def cancel(self, context):
print("cancel")
#bpy.context.window_manager.auto_export_tracker.enable_change_detection()
bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)

View File

@ -1,201 +0,0 @@
import os
from bpy.types import AddonPreferences
from bpy.props import (BoolProperty,
IntProperty,
StringProperty,
EnumProperty,
CollectionProperty
)
AutoExportGltfPreferenceNames = [
'will_save_settings',
'direct_mode',# specific to main auto_export operator
'show_general_settings',
'auto_export',
'project_root_path',
'assets_path',
'export_scene_settings',
'show_change_detection_settings',
'change_detection',
'show_scene_settings',
'main_scenes',
'library_scenes',
'main_scenes_index',
'library_scenes_index',
'main_scene_names',
'library_scene_names',
'show_blueprint_settings',
'export_blueprints',
'blueprints_path',
'export_marked_assets',
'collection_instances_combine_mode',
'levels_path',
'export_separate_dynamic_and_static_objects',
'export_materials_library',
'materials_path',
]
def on_export_output_folder_updated(self, context):
#self.project_root_path = os.path.relpath(self.project_root_path)
#self.assets_path = os.path.join(self.project_root_path, self.assets_path)
print("on_foo_updated", self.project_root_path, self.assets_path)
class AutoExportGltfAddonPreferences(AddonPreferences):
# this must match the add-on name, use '__package__'
# when defining this in a submodule of a python package.
bl_idname = __package__
bl_options = {'PRESET'}
#### these are for the operator
will_save_settings: BoolProperty(
name='Remember Export Settings',
description='Store glTF export settings in the Blender project',
default=True
) # type: ignore
# use when operator is called directly, works a bit differently than inside the ui
direct_mode: BoolProperty(
default=False
) # type: ignore
auto_export: BoolProperty(
name='Auto export',
description='Automatically export to gltf on save',
default=False
) # type: ignore
#### general
# for UI only, workaround for lacking panels
show_general_settings: BoolProperty(
name="show_general settings",
description="show/hide general settings (UI only: has no impact on exports)",
default=True
) # type: ignore
project_root_path: StringProperty(
name = "Project Root Path",
description="The root folder of your (Bevy) project (not assets!)",
# subtype='DIR_PATH',
default='../'
#update=on_export_output_folder_updated) # type: ignore
)
assets_path: StringProperty(
name='Export folder',
description='The root folder for all exports(relative to the root folder/path) Defaults to "assets" ',
default='./assets',
#subtype='DIR_PATH',
options={'HIDDEN'}
# update=on_export_output_folder_updated
) # type: ignore
# for UI only, workaround for lacking panels
show_change_detection_settings: BoolProperty(
name="show change detection settings",
description="show/hide change detection settings (UI only: has no impact on exports)",
default=True
) # type: ignore
change_detection: BoolProperty(
name='Change detection',
description='Use change detection to determine what/if should be exported',
default=True
) # type: ignore
# scenes
# for UI only, workaround for lacking panels
show_scene_settings: BoolProperty(
name="show scene settings",
description="show/hide scene settings (UI only: has no impact on exports)",
default=True
) # type: ignore
# scene components
export_scene_settings: BoolProperty(
name='Export scene settings',
description='Export scene settings ie AmbientLighting, Bloom, AO etc',
default=False
) # type: ignore
# blueprint settings
# for UI only, workaround for lacking panels
show_blueprint_settings: BoolProperty(
name="show blueprint settings",
description="show/hide blueprint settings (UI only: has no impact on exports)",
default=True
) # type: ignore
export_blueprints: BoolProperty(
name='Export Blueprints',
description='Replaces collection instances with an Empty with a BlueprintName custom property, and enabled a lot more features !',
default=True
) # type: ignore
blueprints_path: StringProperty(
name='Blueprints path',
description='path to export the blueprints to (relative to the assets folder)',
default='blueprints',
#subtype='DIR_PATH'
) # type: ignore
levels_path: StringProperty(
name='Levels path',
description='path to export the levels (main scenes) to (relative to the assets folder)',
default='levels',
#subtype='DIR_PATH'
) # type: ignore
export_separate_dynamic_and_static_objects: BoolProperty(
name="Export levels' dynamic and static objects seperatly",
description="""For MAIN scenes only (aka levels), toggle this to generate 2 files per level:
- one with all dynamic data: collection or instances marked as dynamic/ saveable
- one with all static data: anything else that is NOT marked as dynamic""",
default=False
) # type: ignore
export_materials_library: BoolProperty(
name='Export materials library',
description='remove materials from blueprints and use the material library instead',
default=False
) # type: ignore
materials_path: StringProperty(
name='Materials path',
description='path to export the materials libraries to (relative to the assets folder)',
default='materials',
#subtype='DIR_PATH'
) # type: ignore
""" combine mode can be
- 'Split' (default): replace with an empty, creating links to sub blueprints
- 'Embed' : treat it as an embeded object and do not replace it with an empty
- 'EmbedExternal': embed any instance of a non local collection (ie external assets)
- 'Inject': inject components from sub collection instances into the curent object => this is now a seperate custom property that you can apply to a collecion instance
"""
collection_instances_combine_mode : EnumProperty(
name='Collection instances',
items=(
('Split', 'Split', 'replace collection instances with an empty + blueprint, creating links to sub blueprints (Default, Recomended)'),
('Embed', 'Embed', 'treat collection instances as embeded objects and do not replace them with an empty'),
('EmbedExternal', 'EmbedExternal', 'treat instances of external (not specifified in the current blend file) collections (aka assets etc) as embeded objects and do not replace them with empties'),
#('Inject', 'Inject', 'inject components from sub collection instances into the curent object')
),
default='Split'
) # type: ignore
export_marked_assets: BoolProperty(
name='Auto export marked assets',
description='Collections that have been marked as assets will be systematically exported, even if not in use in another scene',
default=True
) # type: ignore

View File

@ -2,7 +2,7 @@ import json
import bpy
def upsert_settings(name, data):
stored_settings = bpy.data.texts[name] if name in bpy.data.texts else None#bpy.data.texts.new(name)
stored_settings = bpy.data.texts[name] if name in bpy.data.texts else None
if stored_settings is None:
stored_settings = bpy.data.texts.new(name)
stored_settings.write(json.dumps(data))
@ -14,10 +14,43 @@ def upsert_settings(name, data):
def load_settings(name):
stored_settings = bpy.data.texts[name] if name in bpy.data.texts else None
if stored_settings != None:
return json.loads(stored_settings.as_string())
if stored_settings is not None:
try:
return json.loads(stored_settings.as_string())
except:
return None
return None
# given the input (actual) settings, filters out any invalid/useless params & params that are equal to defaults
def generate_complete_preferences_dict(settings, presets, ignore_list=[], preset_defaults=True):
complete_preferences = {}
defaults = {}
def filter_out(pair):
key, value = pair
if key in ignore_list:
return False
return True
for k in presets.__annotations__:
item = presets.__annotations__[k]
default = item.keywords.get('default', None)
if default is not None:
defaults[k] = default
if preset_defaults:
complete_preferences[k] = default
# print("defaults", defaults)
for key in list(settings.keys()):
if key in defaults and settings[key] != defaults[key]: # only write out values different from defaults
complete_preferences[key] = getattr(settings, key, None)
complete_preferences = dict(filter(filter_out, dict(complete_preferences).items()))
return complete_preferences
# checks if old & new settings (dicts really) are identical
def are_settings_identical(old, new, white_list=None):
if old is None and new is None:

View File

@ -5,9 +5,9 @@ import pytest
def setup_data(request):
print("\nSetting up resources...")
schemaPath = "../../testing/bevy_example/assets/registry.json"
schema_path = "../../testing/bevy_example/assets/registry.json"
yield {"schema_path": schemaPath}
yield {"schema_path": schema_path}
def finalizer():
print("\nPerforming teardown...")

View File

@ -9,7 +9,7 @@ import filecmp
from PIL import Image
from pixelmatch.contrib.PIL import pixelmatch
from blenvy.gltf_auto_export.auto_export.prepare_and_export import prepare_and_export
from blenvy.auto_export.export.prepare_and_export import prepare_and_export
@pytest.fixture
def setup_data(request):

View File

@ -11,7 +11,7 @@ from .setup_data import setup_data
def test_components_should_generate_correct_custom_properties(setup_data):
registry = bpy.context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"]
registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry()
type_infos = registry.type_infos
@ -58,7 +58,7 @@ def test_components_should_generate_correct_custom_properties(setup_data):
def test_components_should_generate_correct_custom_properties_with_randomized_values(setup_data):
registry = bpy.context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"]
registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry()
type_infos = registry.type_infos
@ -108,7 +108,7 @@ def test_components_should_generate_correct_custom_properties_with_randomized_va
def test_components_should_generate_correct_propertyGroup_values_from_custom_properties(setup_data):
registry = bpy.context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"]
registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry()
type_infos = registry.type_infos
@ -166,7 +166,7 @@ def test_components_should_generate_correct_propertyGroup_values_from_custom_pro
def test_remove_components(setup_data):
registry = bpy.context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"]
registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry()
type_infos = registry.type_infos
@ -207,7 +207,7 @@ def test_remove_components(setup_data):
def test_copy_paste_components(setup_data):
context = bpy.context
registry = context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"]
registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry()
long_name = "bevy_example::test_components::BasicTest"

View File

@ -3,7 +3,7 @@ from .setup_data import setup_data
def test_blend(setup_data):
registry = bpy.context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"]
registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry()
long_name = "bevy_example::test_components::BasicTest"

View File

@ -24,7 +24,7 @@ def get_component_propGroup(registry, component_name, component_meta):
def test_rename_component_single_unit_struct(setup_data):
registry = bpy.context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"]
registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry()
rename_component_operator = bpy.ops.object.rename_bevy_component
@ -47,7 +47,7 @@ def test_rename_component_single_unit_struct(setup_data):
def test_rename_component_single_complex_struct(setup_data):
registry = bpy.context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"]
registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry()
rename_component_operator = bpy.ops.object.rename_bevy_component
@ -70,7 +70,7 @@ def test_rename_component_single_complex_struct(setup_data):
def test_rename_component_bulk(setup_data):
registry = bpy.context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"]
registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry()
rename_component_operator = bpy.ops.object.rename_bevy_component
@ -95,7 +95,7 @@ def test_rename_component_bulk(setup_data):
def test_rename_component_single_error_handling(setup_data):
registry = bpy.context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"]
registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry()
rename_component_operator = bpy.ops.object.rename_bevy_component
@ -125,7 +125,7 @@ def test_rename_component_single_error_handling(setup_data):
def test_rename_component_single_error_handling_clean_errors(setup_data):
registry = bpy.context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"]
registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry()
rename_component_operator = bpy.ops.object.rename_bevy_component

View File

@ -5,7 +5,7 @@ from .setup_data import setup_data
def test_shuffler(setup_data):
registry = bpy.context.window_manager.components_registry
registry.schemaPath = setup_data["schema_path"]
registry.schema_path = setup_data["schema_path"]
bpy.ops.object.reload_registry()
type_infos = registry.type_infos