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 - [ ] handle missing types in registry for keys & values
- [ ] Add correct upgrade handling from individual component to bevy_components - [ ] 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: General things to solve:
- [x] save settings - [x] save settings
- [x] load settings - [x] load settings
- [ ] add_blueprints_data - [ ] add blueprints data
- [x] rename all path stuff using the old naming convention : "blueprints_path_full" - [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] generate the full paths directly when setting them in the UI
- [x] problem : how to deal with defaults: do it on start/load ? - [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: General issues:
- there is no safeguard for naming collisions for naming across blender files - there is no safeguard for naming collisions for naming across blender files
@ -83,6 +88,12 @@ General issues:
- "parents" can only be blueprints - "parents" can only be blueprints
- they normally need/have unique export paths (otherwise, user error, perhaps show it ?) - 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 - 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 # 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 .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 .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 .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 .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 .bevy_components.components.metadata import (ComponentMetadata, ComponentsMeta) from .add_ons.bevy_components.components.maps import GENERIC_MAP_OT_actions
from .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.definitions_list import (ComponentDefinitionsList, ClearComponentDefinitionsList)
from .bevy_components.components.maps import GENERIC_MAP_OT_actions from .add_ons.bevy_components.components.ui import (BEVY_COMPONENTS_PT_ComponentsPanel)
from .bevy_components.components.definitions_list import (ComponentDefinitionsList, ClearComponentDefinitionsList) from .add_ons.bevy_components.settings import ComponentsSettings
from .bevy_components.components.ui import (BEVY_COMPONENTS_PT_ComponentsPanel)
# auto export # auto export
from .gltf_auto_export import gltf_post_export_callback from .add_ons.auto_export import gltf_post_export_callback
from .gltf_auto_export.auto_export.operators import AutoExportGLTF from .add_ons.auto_export.export.tracker import AutoExportTracker
from .gltf_auto_export.auto_export.tracker import AutoExportTracker from .add_ons.auto_export.settings import AutoExportSettings
from .gltf_auto_export.settings import AutoExportSettings
# asset management # asset management
from .assets.ui import Blenvy_assets from .assets.ui import Blenvy_assets
@ -70,6 +68,7 @@ classes = [
BLENVY_PT_SidePanel, BLENVY_PT_SidePanel,
# bevy components # bevy components
ComponentsSettings,
AddComponentOperator, AddComponentOperator,
CopyComponentOperator, CopyComponentOperator,
PasteComponentOperator, PasteComponentOperator,
@ -113,8 +112,8 @@ classes = [
GENERIC_MAP_OT_actions, GENERIC_MAP_OT_actions,
# gltf auto export # gltf auto export
AutoExportGLTF,
AutoExportTracker, AutoExportTracker,
AutoExportSettings, AutoExportSettings,
@ -146,9 +145,7 @@ def post_save(scene, depsgraph):
@persistent @persistent
def post_load(file_name): def post_load(file_name):
registry = bpy.context.window_manager.components_registry print("POST LOAD")
if registry is not None:
registry.load_settings()
blenvy = bpy.context.window_manager.blenvy blenvy = bpy.context.window_manager.blenvy
if blenvy is not None: if blenvy is not None:
blenvy.load_settings() blenvy.load_settings()

View File

@ -4,7 +4,7 @@ import bpy
from .helpers.generate_complete_preferences_dict import generate_complete_preferences_dict_gltf from .helpers.generate_complete_preferences_dict import generate_complete_preferences_dict_gltf
def cleanup_file(): 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): if os.path.exists(gltf_filepath):
os.remove(gltf_filepath) os.remove(gltf_filepath)
return None return None
@ -14,38 +14,39 @@ def cleanup_file():
def gltf_post_export_callback(data): def gltf_post_export_callback(data):
#print("post_export", data) #print("post_export", data)
blenvy = bpy.context.window_manager.blenvy 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_filepath = data["gltf_filepath"]
gltf_export_id = data['gltf_export_id'] gltf_export_id = data['gltf_export_id']
if gltf_export_id == "gltf_auto_export": 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 # 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: try:
bpy.app.timers.unregister(cleanup_file) bpy.app.timers.unregister(cleanup_file)
except:pass except:pass
bpy.app.timers.register(cleanup_file, first_interval=1) bpy.app.timers.register(cleanup_file, first_interval=2)
# get the parameters # get the parameters
scene = bpy.context.scene scene = bpy.context.scene
if "glTF2ExportSettings" in scene: if "glTF2ExportSettings" in scene:
settings = scene["glTF2ExportSettings"] 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 # now write new settings
export_settings.clear() gltf_export_settings.clear()
current_gltf_settings = generate_complete_preferences_dict_gltf(dict(settings)) 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 # now reset the original gltf_settings
if gltf_settings_backup != "": if gltf_settings_backup != "":
scene["glTF2ExportSettings"] = json.loads(gltf_settings_backup) scene["glTF2ExportSettings"] = json.loads(gltf_settings_backup)
else: else:
if "glTF2ExportSettings" in scene: if "glTF2ExportSettings" in scene:
del scene["glTF2ExportSettings"] 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 # 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.filepath = ""
last_operator.gltf_export_id = "" last_operator.gltf_export_id = ""

View File

@ -3,23 +3,22 @@ import os
import bpy import bpy
import traceback 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_blueprints_to_export import get_blueprints_to_export
from .get_levels_to_export import get_levels_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_main_scenes import export_main_scene
from .export_blueprints import export_blueprints 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 ..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 """ """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 # 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) print ("changed_export_parameters", changed_export_parameters)
try: try:
@ -27,41 +26,34 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
file_path = bpy.data.filepath file_path = bpy.data.filepath
# Get the folder # Get the folder
blend_file_path = os.path.dirname(file_path) 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 #should we use change detection or not
change_detection = getattr(addon_prefs.auto_export, "change_detection") change_detection = getattr(settings.auto_export, "change_detection")
export_scene_settings = getattr(addon_prefs.auto_export,"export_scene_settings") export_scene_settings = getattr(settings.auto_export,"export_scene_settings")
do_export_blueprints = getattr(addon_prefs.auto_export,"export_blueprints") do_export_blueprints = getattr(settings.auto_export,"export_blueprints")
export_materials_library = getattr(addon_prefs.auto_export,"export_materials_library") export_materials_library = getattr(settings.auto_export,"export_materials_library")
# standard gltf export settings are stored differently # standard gltf export settings are stored differently
standard_gltf_exporter_settings = get_standard_exporter_settings() standard_gltf_exporter_settings = get_standard_exporter_settings()
gltf_extension = standard_gltf_exporter_settings.get("export_format", 'GLB') gltf_extension = standard_gltf_exporter_settings.get("export_format", 'GLB')
gltf_extension = '.glb' if gltf_extension == 'GLB' else '.gltf' 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_scenes(addon_prefs) [main_scene_names, level_scenes, library_scene_names, library_scenes] = get_main_and_library_scenes(settings)
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 blueprints_per_scene = blueprints_data.blueprints_per_scenes
internal_blueprints = [blueprint.name for blueprint in blueprints_data.internal_blueprints] internal_blueprints = [blueprint.name for blueprint in blueprints_data.internal_blueprints]
external_blueprints = [blueprint.name for blueprint in blueprints_data.external_blueprints] external_blueprints = [blueprint.name for blueprint in blueprints_data.external_blueprints]
# we inject the blueprints export path # 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) 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: for blueprint in blueprints_data.blueprints:
bpy.context.window_manager.blueprints_registry.add_blueprint(blueprint) 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: if export_scene_settings:
# inject/ update scene components # inject/ update scene components
@ -75,15 +67,15 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
if do_export_blueprints: if do_export_blueprints:
print("EXPORTING") print("EXPORTING")
# get blueprints/collections infos # 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 # 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 # since materials export adds components we need to call this before blueprints are exported
# export materials & inject materials components into relevant objects # export materials & inject materials components into relevant objects
if export_materials_library: 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 # update the list of tracked exports
exports_total = len(blueprints_to_export) + len(main_scenes_to_export) + (1 if export_materials_library else 0) 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") print("export MAIN scenes")
for scene_name in main_scenes_to_export: for scene_name in main_scenes_to_export:
print(" exporting scene:", scene_name) 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 # now deal with blueprints/collections
do_export_library_scene = not change_detection or changed_export_parameters or len(blueprints_to_export) > 0 do_export_library_scene = not change_detection or changed_export_parameters or len(blueprints_to_export) > 0
if do_export_library_scene: if do_export_library_scene:
print("export LIBRARY") 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 # reset current scene from backup
bpy.context.window.scene = old_current_scene bpy.context.window.scene = old_current_scene
@ -134,7 +126,7 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
else: else:
for scene_name in main_scene_names: 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: finally:
# FIXME: error handling ? also redundant # 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: if export_scene_settings:
# inject/ update scene components # 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 from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into
def export_blueprints(blueprints, addon_prefs, blueprints_data): def export_blueprints(blueprints, settings, blueprints_data):
blueprints_path_full = getattr(addon_prefs, "blueprints_path_full") blueprints_path_full = getattr(settings, "blueprints_path_full")
gltf_export_preferences = generate_gltf_export_preferences(addon_prefs) gltf_export_preferences = generate_gltf_export_preferences(settings)
try: try:
# save current active collection # save current active collection
active_collection = bpy.context.view_layer.active_layer_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: for blueprint in blueprints:
print("exporting collection", blueprint.name) print("exporting collection", blueprint.name)
gltf_output_path = os.path.join(blueprints_path_full, 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 we are using the material library option, do not export materials, use placeholder instead
if export_materials_library: if export_materials_library:
export_settings['export_materials'] = 'PLACEHOLDER' gltf_export_settings['export_materials'] = 'PLACEHOLDER'
collection = bpy.data.collections[blueprint.name] collection = bpy.data.collections[blueprint.name]
# do the actual export # do the actual export
generate_and_export( generate_and_export(
addon_prefs, settings,
temp_scene_name=TEMPSCENE_PREFIX+collection.name, temp_scene_name=TEMPSCENE_PREFIX+collection.name,
export_settings=export_settings, gltf_export_settings=gltf_export_settings,
gltf_output_path=gltf_output_path, 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) 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 os
import bpy import bpy
from .get_standard_exporter_settings import get_standard_exporter_settings from blenvy.settings import load_settings
from .preferences import (AutoExportGltfPreferenceNames)
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 # default values
gltf_export_preferences = dict( gltf_export_preferences = dict(
# export_format= 'GLB', #'GLB', 'GLTF_SEPARATE', 'GLTF_EMBEDDED' # export_format= 'GLB', #'GLB', 'GLTF_SEPARATE', 'GLTF_EMBEDDED'
@ -43,10 +46,10 @@ def generate_gltf_export_preferences(addon_prefs):
#export_optimize_animation_size=False #export_optimize_animation_size=False
) )
for key in addon_prefs.__annotations__.keys(): """for key in settings.__annotations__.keys():
if str(key) not in AutoExportGltfPreferenceNames: if str(key) not in AutoExportGltfPreferenceNames:
#print("overriding setting", key, "value", getattr(addon_prefs,key)) #print("overriding setting", key, "value", getattr(settings,key))
pass#gltf_export_preferences[key] = getattr(addon_prefs, key) pass#gltf_export_preferences[key] = getattr(settings, key)"""
standard_gltf_exporter_settings = get_standard_exporter_settings() 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 #https://docs.blender.org/api/current/bpy.ops.export_scene.html#bpy.ops.export_scene.gltf
def export_gltf (path, export_settings): def export_gltf (path, gltf_export_settings):
settings = {**export_settings, "filepath": path} settings = {**gltf_export_settings, "filepath": path}
# print("export settings",settings) # print("export settings",settings)
os.makedirs(os.path.dirname(path), exist_ok=True) os.makedirs(os.path.dirname(path), exist_ok=True)
bpy.ops.export_scene.gltf(**settings) bpy.ops.export_scene.gltf(**settings)

View File

@ -1,23 +1,23 @@
import os import os
import bpy import bpy
from pathlib import Path 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 ..constants import TEMPSCENE_PREFIX
from ..helpers.generate_and_export import generate_and_export from ..helpers.generate_and_export import generate_and_export
from .export_gltf import (generate_gltf_export_preferences, export_gltf) from .export_gltf import (generate_gltf_export_preferences, export_gltf)
from ..modules.bevy_dynamic import is_object_dynamic, is_object_static from ..modules.bevy_dynamic import is_object_dynamic, is_object_static
from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into 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): def export_main_scene(scene, blend_file_path, settings, blueprints_data):
gltf_export_preferences = generate_gltf_export_preferences(addon_prefs) gltf_export_preferences = generate_gltf_export_preferences(settings)
assets_path_full = getattr(addon_prefs,"assets_path_full") assets_path_full = getattr(settings,"assets_path_full")
levels_path_full = getattr(addon_prefs,"levels_path_full") levels_path_full = getattr(settings,"levels_path_full")
export_blueprints = getattr(addon_prefs.auto_export,"export_blueprints") export_blueprints = getattr(settings.auto_export,"export_blueprints")
export_separate_dynamic_and_static_objects = getattr(addon_prefs.auto_export, "export_separate_dynamic_and_static_objects") 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_scene': True,
'use_active_collection':True, 'use_active_collection':True,
'use_active_collection_with_nested':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 : if export_blueprints :
gltf_output_path = os.path.join(levels_path_full, scene.name) 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: if export_separate_dynamic_and_static_objects:
#print("SPLIT STATIC AND DYNAMIC") #print("SPLIT STATIC AND DYNAMIC")
# first export static objects # first export static objects
generate_and_export( generate_and_export(
addon_prefs, settings,
temp_scene_name=TEMPSCENE_PREFIX, temp_scene_name=TEMPSCENE_PREFIX,
export_settings=export_settings, gltf_export_settings=gltf_export_settings,
gltf_output_path=gltf_output_path, 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) tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=scene.collection, temp_scene=temp_scene, **params)
) )
# then export all dynamic objects # then export all dynamic objects
gltf_output_path = os.path.join(levels_path_full, scene.name+ "_dynamic") gltf_output_path = os.path.join(levels_path_full, scene.name+ "_dynamic")
generate_and_export( generate_and_export(
addon_prefs, settings,
temp_scene_name=TEMPSCENE_PREFIX, temp_scene_name=TEMPSCENE_PREFIX,
export_settings=export_settings, gltf_export_settings=gltf_export_settings,
gltf_output_path=gltf_output_path, 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) tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=scene.collection, temp_scene=temp_scene, **params)
) )
else: else:
#print("NO SPLIT") #print("NO SPLIT")
generate_and_export( generate_and_export(
addon_prefs, settings,
temp_scene_name=TEMPSCENE_PREFIX, temp_scene_name=TEMPSCENE_PREFIX,
export_settings=export_settings, gltf_export_settings=gltf_export_settings,
gltf_output_path=gltf_output_path, 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) tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=scene.collection, temp_scene=temp_scene, **params)
) )
else: else:
gltf_output_path = os.path.join(assets_path_full, scene.name) gltf_output_path = os.path.join(assets_path_full, scene.name)
print(" exporting gltf to", gltf_output_path, ".gltf/glb") 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) remove_blueprints_list_from_main_scene(scene)

View File

@ -2,11 +2,11 @@ import os
import bpy import bpy
from pathlib import Path from pathlib import Path
from ...core.helpers_collections import (traverse_tree) from blenvy.core.helpers_collections import (traverse_tree)
from ...core.object_makers import make_cube from blenvy.core.object_makers import make_cube
from ...materials.materials_helpers import get_all_materials from blenvy.materials.materials_helpers import get_all_materials
from ..helpers.generate_and_export import generate_and_export 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): def clear_material_info(collection_names, library_scenes):
for scene in 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: # 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 # 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): def export_materials(collections, library_scenes, settings):
gltf_export_preferences = generate_gltf_export_preferences(addon_prefs) gltf_export_preferences = generate_gltf_export_preferences(settings)
materials_path_full = getattr(addon_prefs,"materials_path_full") materials_path_full = getattr(settings,"materials_path_full")
used_material_names = get_all_materials(collections, library_scenes) used_material_names = get_all_materials(collections, library_scenes)
current_project_name = Path(bpy.context.blend_data.filepath).stem 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_scene': True,
'use_active_collection':True, 'use_active_collection':True,
'use_active_collection_with_nested':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") print(" exporting Materials to", gltf_output_path, ".gltf/glb")
generate_and_export( generate_and_export(
addon_prefs, settings=settings,
gltf_export_settings=gltf_export_settings,
temp_scene_name="__materials_scene", temp_scene_name="__materials_scene",
export_settings=export_settings,
gltf_output_path=gltf_output_path, gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: generate_materials_scene_content(temp_collection, used_material_names), 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) tempScene_cleaner= lambda temp_scene, params: clear_materials_scene(temp_scene=temp_scene)

View File

@ -1,16 +1,15 @@
import bpy
import os from blenvy.core.scene_helpers import get_main_and_library_scenes
from ..helpers.helpers_scenes import (get_scenes, ) from blenvy.blueprints.blueprint_helpers import find_blueprints_not_on_disk
from ...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 # 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): def get_blueprints_to_export(changes_per_scene, changed_export_parameters, blueprints_data, settings):
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension", ".glb") export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb")
blueprints_path_full = getattr(addon_prefs,"blueprints_path_full", "") blueprints_path_full = getattr(settings,"blueprints_path_full", "")
change_detection = getattr(addon_prefs.auto_export, "change_detection") change_detection = getattr(settings.auto_export, "change_detection")
collection_instances_combine_mode = getattr(addon_prefs.auto_export, "collection_instances_combine_mode") 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 internal_blueprints = blueprints_data.internal_blueprints
blueprints_to_export = internal_blueprints # just for clarity blueprints_to_export = internal_blueprints # just for clarity

View File

@ -1,6 +1,5 @@
import bpy from blenvy.core.scene_helpers import get_main_and_library_scenes
from ...blueprints.blueprint_helpers import check_if_blueprint_on_disk from blenvy.blueprints.blueprint_helpers import check_if_blueprint_on_disk
from ..helpers.helpers_scenes import (get_scenes, )
# 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 # 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): 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 # 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): def get_levels_to_export(changes_per_scene, changed_export_parameters, blueprints_data, settings):
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension") export_gltf_extension = getattr(settings, "export_gltf_extension")
levels_path_full = getattr(addon_prefs, "levels_path_full") levels_path_full = getattr(settings, "levels_path_full")
change_detection = getattr(addon_prefs.auto_export, "change_detection") change_detection = getattr(settings.auto_export, "change_detection")
collection_instances_combine_mode = getattr(addon_prefs.auto_export, "collection_instances_combine_mode") 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 # 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) # 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 import bpy
from .project_diff import get_changes_per_scene, project_diff, serialize_current 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 .auto_export import auto_export
from .settings_diff import get_setting_changes from .settings_diff import get_setting_changes
# prepare export by gather the changes to the scenes & settings # prepare export by gather the changes to the scenes & settings
def prepare_and_export(): def prepare_and_export():
print("prepare and export") print("prepare and export")
blenvy = bpy.context.window_manager.blenvy
bpy.context.window_manager.auto_export_tracker.disable_change_detection() bpy.context.window_manager.auto_export_tracker.disable_change_detection()
blenvy = bpy.context.window_manager.blenvy
auto_export_settings = blenvy.auto_export auto_export_settings = blenvy.auto_export
if auto_export_settings.auto_export: # only do the actual exporting if auto export is actually enabled if auto_export_settings.auto_export: # only do the actual exporting if auto export is actually enabled
# determine changed objects # determine changed objects
per_scene_changes = get_changes_per_scene() per_scene_changes = get_changes_per_scene()
# determine changed parameters # determine changed parameters
setting_changes = get_setting_changes() setting_changes = get_setting_changes(auto_export_settings)
# do the actual export # do the actual export
auto_export(per_scene_changes, setting_changes, blenvy) auto_export(per_scene_changes, setting_changes, blenvy)

View File

@ -1,9 +1,10 @@
import bpy 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 ? # which settings are specific to auto_export # TODO: can we infer this ?
auto_export_parameter_names = [ auto_export_parameter_names = [
# blenvy core
'project_root_path', 'project_root_path',
'assets_path', 'assets_path',
'blueprints_path', 'blueprints_path',
@ -12,6 +13,7 @@ auto_export_parameter_names = [
#'main_scene_names', #'main_scene_names',
#'library_scene_names', #'library_scene_names',
# auto export
'export_scene_settings', 'export_scene_settings',
'export_blueprints', 'export_blueprints',
'export_separate_dynamic_and_static_objects', 'export_separate_dynamic_and_static_objects',
@ -20,13 +22,14 @@ auto_export_parameter_names = [
'export_marked_assets' '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") previous_gltf_settings = load_settings(".blenvy_gltf_settings_previous")
current_gltf_settings = load_settings(".blenvy_gltf_settings") current_gltf_settings = load_settings(".blenvy_gltf_settings")
gltf_settings_changed = not are_settings_identical(previous_gltf_settings, current_gltf_settings) gltf_settings_changed = not are_settings_identical(previous_gltf_settings, current_gltf_settings)
previous_export_settings = load_settings(".blenvy_export_settings_previous") 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) 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 # 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 # write the new settings to the old settings
upsert_settings(".blenvy_gltf_settings_previous", current_gltf_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 return gltf_settings_changed or export_settings_changed

View File

@ -14,9 +14,18 @@ class AutoExportTracker(PropertyGroup):
change_detection_enabled = True change_detection_enabled = True
export_params_changed = False export_params_changed = False
gltf_settings_backup = None
last_operator = 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( exports_total : IntProperty(
name='exports_total', name='exports_total',
@ -77,7 +86,7 @@ class AutoExportTracker(PropertyGroup):
scene = bpy.context.scene scene = bpy.context.scene
if "glTF2ExportSettings" in scene: if "glTF2ExportSettings" in scene:
existing_setting = scene["glTF2ExportSettings"] 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 # we force saving params
active_operator.will_save_settings = True active_operator.will_save_settings = True

View File

@ -1,16 +1,16 @@
import bpy import bpy
from ..auto_export.export_gltf import export_gltf from blenvy.core.helpers_collections import (set_active_collection)
from ...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 generates a temporary scene, fills it with data, cleans up after itself
* named using temp_scene_name * named using temp_scene_name
* filled using the tempScene_filler * 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 * 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_scene = bpy.data.scenes.new(name=temp_scene_name)
temp_root_collection = temp_scene.collection 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) scene_filler_data = tempScene_filler(temp_root_collection)
# export the temporary scene # export the temporary scene
try: 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: except Exception as error:
print("failed to export gltf !", error) print("failed to export gltf !", error)
raise error raise error

View File

@ -1,5 +1,4 @@
from ..auto_export.preferences import AutoExportGltfAddonPreferences
from io_scene_gltf2 import (ExportGLTF2_Base) 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 # 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())) complete_preferences = dict(filter(filter_out, dict(complete_preferences).items()))
return complete_preferences 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 json
import bpy 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 # 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+" ") 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 # 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={}): def copy_hollowed_collection_into(source_collection, destination_collection, parent_empty=None, filter=None, blueprints_data=None, settings={}):
collection_instances_combine_mode = getattr(addon_prefs.auto_export, "collection_instances_combine_mode") collection_instances_combine_mode = getattr(settings.auto_export, "collection_instances_combine_mode")
for object in source_collection.objects: for object in source_collection.objects:
if object.name.endswith("____bak"): # some objects could already have been handled, ignore them 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, parent_empty = collection_placeholder,
filter = filter, filter = filter,
blueprints_data = blueprints_data, blueprints_data = blueprints_data,
addon_prefs=addon_prefs settings=settings
) )
return {} return {}
@ -204,20 +204,3 @@ def clear_hollow_scene(temp_scene, original_root_collection):
# reset original names # reset original names
restore_original_names(original_root_collection) 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.Extension = Extension
self.properties = bpy.context.scene.ExampleExtensionProperties 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 self.properties.enabled:
if gltf2_object.extensions is None: if gltf2_object.extensions is None:
gltf2_object.extensions = {} gltf2_object.extensions = {}
@ -193,7 +193,7 @@ def did_export_parameters_change(current_params, previous_params):
bpy.context.window.scene = library_scene bpy.context.window.scene = library_scene
with bpy.context.temp_override(scene=library_scene): with bpy.context.temp_override(scene=library_scene):
print("active scene", bpy.context.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""" bpy.context.window.scene = original_scene"""
""" """
@ -296,16 +296,16 @@ def duplicate_object2(object, original_name):
settings = scene["glTF2ExportSettings"] settings = scene["glTF2ExportSettings"]
formatted_settings = dict(settings) 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 #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 # now write new settings
export_settings.clear() gltf_export_settings.clear()
export_settings.write(json.dumps(formatted_settings)) gltf_export_settings.write(json.dumps(formatted_settings))
# now reset the original gltf_settings # now reset the original gltf_settings

View File

@ -1,6 +1,6 @@
import bpy 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 # 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): def upsert_scene_components(main_scenes):

View File

@ -1,19 +1,35 @@
import bpy import bpy
from bpy_types import (PropertyGroup) from bpy_types import (PropertyGroup)
from bpy.props import (EnumProperty, PointerProperty, StringProperty, BoolProperty, CollectionProperty, IntProperty) 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): 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( auto_export: BoolProperty(
name='Auto export', name='Auto export',
description='Automatically export to gltf on save', description='Automatically export to gltf on save',
default=False default=False,
update=save_settings
) # type: ignore ) # type: ignore
#### general #### general
change_detection: BoolProperty( change_detection: BoolProperty(
name='Change detection', name='Change detection',
description='Use change detection to determine what/if should be exported', description='Use change detection to determine what/if should be exported',
default=True default=True,
update=save_settings
) # type: ignore ) # type: ignore
# scenes # scenes
@ -22,14 +38,16 @@ class AutoExportSettings(PropertyGroup):
export_scene_settings: BoolProperty( export_scene_settings: BoolProperty(
name='Export scene settings', name='Export scene settings',
description='Export scene settings ie AmbientLighting, Bloom, AO etc', description='Export scene settings ie AmbientLighting, Bloom, AO etc',
default=False default=False,
update=save_settings
) # type: ignore ) # type: ignore
# blueprint settings # blueprint settings
export_blueprints: BoolProperty( export_blueprints: BoolProperty(
name='Export Blueprints', name='Export Blueprints',
description='Replaces collection instances with an Empty with a BlueprintName custom property, and enabled a lot more features !', 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 ) # type: ignore
export_separate_dynamic_and_static_objects: BoolProperty( 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: 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 dynamic data: collection or instances marked as dynamic/ saveable
- one with all static data: anything else that is NOT marked as dynamic""", - one with all static data: anything else that is NOT marked as dynamic""",
default=False default=False,
update=save_settings
) # type: ignore ) # type: ignore
export_materials_library: BoolProperty( export_materials_library: BoolProperty(
name='Export materials library', name='Export materials library',
description='remove materials from blueprints and use the material library instead', description='remove materials from blueprints and use the material library instead',
default=False default=False,
update=save_settings
) # type: ignore ) # 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'), ('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') #('Inject', 'Inject', 'inject components from sub collection instances into the curent object')
), ),
default='Split' default='Split',
update=save_settings
) # type: ignore ) # type: ignore
export_marked_assets: BoolProperty( export_marked_assets: BoolProperty(
name='Auto export marked assets', 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', 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 ) # type: ignore
dry_run: EnumProperty( dry_run: EnumProperty(
name="dry run", name="dry run",
description="debug/ develop helper to enable everything but the actual exporting of files", description="debug/ develop helper to enable everything but the actual exporting of files",
items=( items=(
("DISABLED", "Disabled","Run exports normally (no Dry run)"),
("NO_EXPORT", "No export", "do not actually export gltf files"), ("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)"), ("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 default="DISABLED",
# 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 ) # 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.props import (StringProperty)
from bpy_extras.io_utils import ImportHelper 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 ..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 from ..propGroups.prop_groups import generate_propertyGroups_for_components
class ReloadRegistryOperator(Operator): class ReloadRegistryOperator(Operator):
"""Reloads registry (schema file) from disk, generates propertyGroups for components & ensures all objects have metadata """ """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_label = "Reload Registry"
bl_options = {"UNDO"} bl_options = {"UNDO"}
@ -191,10 +191,8 @@ class OT_OpenSchemaFileBrowser(Operator, ImportHelper):
folder_path = os.path.dirname(file_path) folder_path = os.path.dirname(file_path)
relative_path = os.path.relpath(self.filepath, folder_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 = context.window_manager.blenvy
blenvy.components.schema_path = relative_path
upsert_settings(blenvy.settings_save_path, {"components_schemaPath": relative_path}) upsert_settings(blenvy.settings_save_path, {"components_schemaPath": relative_path})
return {'FINISHED'} return {'FINISHED'}
@ -206,14 +204,14 @@ class OT_select_object(Operator):
bl_label = "Select object" bl_label = "Select object"
bl_options = {"UNDO"} bl_options = {"UNDO"}
object_name: StringProperty( target_name: StringProperty(
name="object_name", name="target name",
description="object to select's name ", description="target to select's name ",
) # type: ignore ) # type: ignore
def execute(self, context): def execute(self, context):
if self.object_name: if self.target_name:
object = bpy.data.objects[self.object_name] object = bpy.data.objects[self.target_name]
scenes_of_object = list(object.users_scene) scenes_of_object = list(object.users_scene)
if len(scenes_of_object) > 0: if len(scenes_of_object) > 0:
bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.select_all(action='DESELECT')

View File

@ -5,10 +5,7 @@ import uuid
from pathlib import Path from pathlib import Path
from bpy_types import (PropertyGroup) from bpy_types import (PropertyGroup)
from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty) from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty)
from ..components.metadata import ComponentMetadata
from ...settings import load_settings
from ..propGroups.prop_groups import generate_propertyGroups_for_components
from ..components.metadata import ComponentMetadata, ensure_metadata_for_all_items
# helper class to store missing bevy types information # helper class to store missing bevy types information
class MissingBevyType(bpy.types.PropertyGroup): class MissingBevyType(bpy.types.PropertyGroup):
@ -16,58 +13,9 @@ class MissingBevyType(bpy.types.PropertyGroup):
name="type", name="type",
) # type: ignore ) # 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 # this is where we store the information for all available components
class ComponentsRegistry(PropertyGroup): 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( registry: bpy.props. StringProperty(
name="registry", name="registry",
description="component registry" description="component registry"
@ -80,25 +28,6 @@ class ComponentsRegistry(PropertyGroup):
disable_all_object_updates: BoolProperty(name="disable_object_updates", default=False) # type: ignore 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: CollectionProperty(name="missing types list", type=MissingBevyType)# type: ignore
missing_types_list_index: IntProperty(name = "Index for missing types list", default = 0)# 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 @classmethod
def register(cls): def register(cls):
bpy.types.WindowManager.components_registry = PointerProperty(type=ComponentsRegistry) bpy.types.WindowManager.components_registry = PointerProperty(type=ComponentsRegistry)
bpy.context.window_manager.components_registry.watcher_active = False
@classmethod @classmethod
def unregister(cls): def unregister(cls):
bpy.context.window_manager.components_registry.watcher_active = False
for propgroup_name in cls.component_propertyGroups.keys(): for propgroup_name in cls.component_propertyGroups.keys():
try: try:
delattr(ComponentMetadata, propgroup_name) delattr(ComponentMetadata, propgroup_name)
#print("unregistered propertyGroup", propgroup_name)
except Exception as error: except Exception as error:
pass 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 del bpy.types.WindowManager.components_registry
def load_schema(self): def load_schema(self):
print("load schema", self) print("load schema", self)
blenvy = bpy.context.window_manager.blenvy
component_settings = blenvy.components
# cleanup previous data if any # cleanup previous data if any
self.propGroupIdCounter = 0 self.propGroupIdCounter = 0
self.long_names_to_propgroup_names.clear() self.long_names_to_propgroup_names.clear()
@ -251,23 +173,13 @@ class ComponentsRegistry(PropertyGroup):
self.invalid_components.clear() self.invalid_components.clear()
# now prepare paths to load data # 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(component_settings.schema_path_full) as f:
with open(path) as f:
data = json.load(f) data = json.load(f)
defs = data["$defs"] defs = data["$defs"]
self.registry = json.dumps(defs) # FIXME:meh ? self.registry = json.dumps(defs) # FIXME:meh ?
# start timer component_settings.start_schema_watcher()
if not self.watcher_active and self.watcher_enabled:
self.watcher_active = True
print("registering function", watch_schema)
bpy.app.timers.register(watch_schema)
# we load the json once, so we do not need to do it over & over again # 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): def has_type_infos(self):
return len(self.type_infos.keys()) != 0 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 # we keep a list of component propertyGroup around
def register_component_propertyGroup(self, name, propertyGroup): def register_component_propertyGroup(self, name, propertyGroup):
self.component_propertyGroups[name] = propertyGroup self.component_propertyGroups[name] = propertyGroup

View File

@ -3,13 +3,13 @@ import bpy
from bpy_types import (UIList) from bpy_types import (UIList)
from bpy.props import (StringProperty) 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( from .operators import(
COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_ALL,
COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_CURRENT, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_CURRENT,
OT_OpenSchemaFileBrowser, OT_OpenSchemaFileBrowser, ReloadRegistryOperator,
OT_select_component_name_to_replace,
OT_select_object, ReloadRegistryOperator,
COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_ALL,
COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_CURRENT) COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_CURRENT)
@ -32,23 +32,24 @@ class BEVY_COMPONENTS_PT_Configuration(bpy.types.Panel):
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
registry = context.window_manager.components_registry registry = context.window_manager.components_registry
blenvy = context.window_manager.blenvy
component_settings = blenvy.components
row = layout.row() row = layout.row()
col = row.column() col = row.column()
col.enabled = False 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 = 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.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() layout.separator()
row = layout.row() row = layout.row()
row.prop(registry, "watcher_enabled", text="enable registry file polling") row.prop(component_settings, "watcher_enabled", text="enable registry file polling")
row.prop(registry, "watcher_poll_frequency", text="registry file poll frequency (s)") row.prop(component_settings, "watcher_poll_frequency", text="registry file poll frequency (s)")
layout.separator() layout.separator()
layout.separator() layout.separator()
@ -78,7 +79,7 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
col.label(text=item) 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 available_components = bpy.context.window_manager.components_list
registry = bpy.context.window_manager.components_registry registry = bpy.context.window_manager.components_registry
registry_has_type_infos = registry.has_type_infos() 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.label(text=component_name)
col = row.column() col = row.column()
operator = col.operator(OT_select_object.bl_idname, text=object.name) operator = col.operator("object.select", text=target.name)
operator.object_name = object.name operator.target_name = target.name
col = row.column() col = row.column()
col.label(text=status) col.label(text=status)
@ -99,22 +100,24 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
col.prop(available_components, "list", text="") col.prop(available_components, "list", text="")
col = row.column() 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 "" 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.original_name = component_name
operator.target_objects = json.dumps([object.name]) operator.target_objects = json.dumps([target.name])
operator.new_name = new_name operator.new_name = new_name
col.enabled = registry_has_type_infos and component_name != "" and component_name != new_name col.enabled = registry_has_type_infos and component_name != "" and component_name != new_name
col = row.column() col = row.column()
operator = col.operator(RemoveComponentOperator.bl_idname, text="", icon="X") operator = col.operator("object.remove_bevy_component", text="", icon="X")
operator.object_name = object.name operator.item_name = target.name
operator.component_name = component_name operator.component_name = component_name
operator.item_type = get_selection_type(target)
col = row.column() col = row.column()
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 operator.component_name = component_name
def draw(self, context): 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 from .asset_helpers import does_asset_exist, get_user_assets, get_user_assets_as_list
def scan_assets(scene, blueprints_data, addon_prefs): def scan_assets(scene, blueprints_data, settings):
project_root_path = getattr(addon_prefs, "project_root_path") project_root_path = getattr(settings, "project_root_path")
export_output_folder = getattr(addon_prefs,"export_output_folder") export_output_folder = getattr(settings,"export_output_folder")
levels_path = getattr(addon_prefs,"levels_path") levels_path = getattr(settings,"levels_path")
blueprints_path = getattr(addon_prefs, "blueprints_path") blueprints_path = getattr(settings, "blueprints_path")
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension") export_gltf_extension = getattr(settings, "export_gltf_extension")
relative_blueprints_path = os.path.relpath(blueprints_path, project_root_path) 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) 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']) textures.extend([x.image.filepath for x in mat_slot.material.node_tree.nodes if x.type=='TEX_IMAGE'])
print("textures", textures) print("textures", textures)
def get_blueprint_assets_tree(blueprint, blueprints_data, parent, addon_prefs): def get_blueprint_assets_tree(blueprint, blueprints_data, parent, settings):
blueprints_path = getattr(addon_prefs, "blueprints_path") blueprints_path = getattr(settings, "blueprints_path")
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension") export_gltf_extension = getattr(settings, "export_gltf_extension")
assets_list = [] 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}) 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 # 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 assets_list += sub_assets_lists
direct_assets = get_user_assets_as_list(blueprint.collection) 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 assets_list += direct_assets
return assets_list return assets_list
def get_main_scene_assets_tree(main_scene, blueprints_data, addon_prefs): def get_main_scene_assets_tree(main_scene, blueprints_data, settings):
blueprints_path = getattr(addon_prefs, "blueprints_path") blueprints_path = getattr(settings, "blueprints_path")
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension") 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) 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) 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): 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.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) print("TOTAL ASSETS", assets_list)
return assets_list return assets_list

View File

@ -52,7 +52,6 @@ class OT_add_bevy_asset(Operator):
) # type: ignore ) # type: ignore
def execute(self, context): def execute(self, context):
assets = []
blueprint_assets = self.target_type == 'BLUEPRINT' blueprint_assets = self.target_type == 'BLUEPRINT'
target = None target = None
if blueprint_assets: if blueprint_assets:
@ -61,7 +60,9 @@ class OT_add_bevy_asset(Operator):
target = bpy.data.scenes[self.target_name] target = bpy.data.scenes[self.target_name]
assets = get_user_assets(target) assets = get_user_assets(target)
asset = {"name": self.asset_name, "type": self.asset_type, "path": self.asset_path} asset = {"name": self.asset_name, "type": self.asset_type, "path": self.asset_path}
print('assets', assets, target)
if not does_asset_exist(target, asset): if not does_asset_exist(target, asset):
print("add asset", target, asset)
upsert_asset(target, asset) upsert_asset(target, asset)
#assets.append({"name": self.asset_name, "type": self.asset_type, "path": self.asset_path, "internal": False}) #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 blenvy = context.window_manager.blenvy
settings = blenvy settings = blenvy
blueprints_registry = context.window_manager.blueprints_registry blueprints_registry = context.window_manager.blueprints_registry
blueprints_registry.add_blueprints_data() blueprints_registry.refresh_blueprints()
blueprints_data = blueprints_registry.blueprints_data blueprints_data = blueprints_registry.blueprints_data
for scene in blenvy.main_scenes: 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 asset_registry = context.window_manager.assets_registry
blueprints_registry = context.window_manager.blueprints_registry blueprints_registry = context.window_manager.blueprints_registry
blueprints_registry.add_blueprints_data() #blueprints_registry.refresh_blueprints()
blueprints_data = blueprints_registry.blueprints_data blueprints_data = blueprints_registry.blueprints_data
name = "world" name = "world"
@ -85,9 +85,12 @@ class Blenvy_assets(bpy.types.Panel):
settings = SimpleNamespace(**settings) settings = SimpleNamespace(**settings)
if panel: 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) #get_main_scene_assets_tree(scene, blueprints_data, settings)
user_assets = get_user_assets(scene) user_assets = get_user_assets(scene)
#print("user assets", user_assets, scene)
row = panel.row() 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) 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: """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_exported_path = os.path.join(blueprints_path, f"{blueprint.name}{gltf_extension}")
blueprint.collection["export_path"] = blueprint_exported_path blueprint.collection["export_path"] = blueprint_exported_path
def inject_blueprints_list_into_main_scene(scene, blueprints_data, addon_prefs): def inject_blueprints_list_into_main_scene(scene, blueprints_data, settings):
project_root_path = getattr(addon_prefs, "project_root_path") project_root_path = getattr(settings, "project_root_path")
assets_path = getattr(addon_prefs,"assets_path") assets_path = getattr(settings,"assets_path")
levels_path = getattr(addon_prefs,"levels_path") levels_path = getattr(settings,"levels_path")
blueprints_path = getattr(addon_prefs, "blueprints_path") blueprints_path = getattr(settings, "blueprints_path")
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension") export_gltf_extension = getattr(settings, "export_gltf_extension")
# print("injecting assets/blueprints data into scene") # print("injecting assets/blueprints data into scene")
assets_list_name = f"assets_list_{scene.name}_components" 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 bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty)
from ..settings import load_settings 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 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 # this is where we store the information for all available Blueprints
class BlueprintsRegistry(PropertyGroup): class BlueprintsRegistry(PropertyGroup):
blueprints_data = {} blueprints_data = {}
@ -40,17 +51,25 @@ class BlueprintsRegistry(PropertyGroup):
@classmethod @classmethod
def register(cls): def register(cls):
bpy.types.WindowManager.blueprints_registry = PointerProperty(type=BlueprintsRegistry) bpy.types.WindowManager.blueprints_registry = PointerProperty(type=BlueprintsRegistry)
bpy.app.timers.register(refresh_blueprints)
@classmethod @classmethod
def unregister(cls): def unregister(cls):
try:
bpy.app.timers.unregister(refresh_blueprints)
except: pass
del bpy.types.WindowManager.blueprints_registry del bpy.types.WindowManager.blueprints_registry
def add_blueprint(self, blueprint): def add_blueprint(self, blueprint):
self.blueprints_list.append(blueprint) self.blueprints_list.append(blueprint)
def add_blueprints_data(self): def refresh_blueprints(self):
blenvy = bpy.context.window_manager.blenvy blenvy = bpy.context.window_manager.blenvy
addon_prefs = blenvy settings = blenvy
[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)
blueprints_data = blueprints_scan(level_scenes, library_scenes, addon_prefs) blueprints_data = blueprints_scan(level_scenes, library_scenes, settings)
self.blueprints_data = blueprints_data 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 # - marked as asset
# - with the "auto_export" flag # - with the "auto_export" flag
# https://blender.stackexchange.com/questions/167878/how-to-get-all-collections-of-the-current-scene # https://blender.stackexchange.com/questions/167878/how-to-get-all-collections-of-the-current-scene
def blueprints_scan(main_scenes, library_scenes, addon_prefs): def blueprints_scan(main_scenes, library_scenes, settings):
export_marked_assets = getattr(addon_prefs.auto_export,"export_marked_assets") export_marked_assets = getattr(settings.auto_export, "export_marked_assets")
blueprints = {} blueprints = {}
blueprints_from_objects = {} blueprints_from_objects = {}

View File

@ -14,15 +14,18 @@ class GLTF_PT_auto_export_blueprints_list(bpy.types.Panel):
@classmethod @classmethod
def poll(cls, context): 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): def draw(self, context):
layout = self.layout layout = self.layout
layout.use_property_split = True layout.use_property_split = True
layout.use_property_decorate = False # No animation. layout.use_property_decorate = False # No animation.
asset_registry = context.window_manager.assets_registry 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 = layout.row()
row.label(icon="RIGHTARROW") row.label(icon="RIGHTARROW")
row.label(text=blueprint.name) row.label(text=blueprint.name)

View File

@ -1,31 +1,48 @@
import os import os
import bpy import bpy
from bpy_types import (PropertyGroup) 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 .scene_helpers import SceneSelector
from ..settings import upsert_settings, load_settings from ..settings import upsert_settings, load_settings, generate_complete_preferences_dict
import blenvy.gltf_auto_export.settings as auto_export_settings 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.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 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_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]}) upsert_settings(blenvy.settings_save_path, {"common_library_scene_names": [scene.name for scene in blenvy.library_scenes]})
def update_asset_folders(self, context): def update_asset_folders(blenvy, context):
blenvy = self # context.window_manager.blenvy
asset_path_names = ['project_root_path', 'assets_path', 'blueprints_path', 'levels_path', 'materials_path'] asset_path_names = ['project_root_path', 'assets_path', 'blueprints_path', 'levels_path', 'materials_path']
for asset_path_name in asset_path_names: for asset_path_name in asset_path_names:
upsert_settings(blenvy.settings_save_path, {asset_path_name: getattr(blenvy, asset_path_name)}) upsert_settings(blenvy.settings_save_path, {asset_path_name: getattr(blenvy, asset_path_name)})
def update_mode(self, context): def update_mode(blenvy, context):
blenvy = self
upsert_settings(blenvy.settings_save_path, {"mode": blenvy.mode }) 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): 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( mode: EnumProperty(
items=( items=(
@ -101,37 +118,29 @@ class BlenvyManager(PropertyGroup):
main_scenes: CollectionProperty(name="main scenes", type=SceneSelector) # type: ignore main_scenes: CollectionProperty(name="main scenes", type=SceneSelector) # type: ignore
main_scenes_index: IntProperty(name = "Index for main scenes list", default = 0, update=update_scene_lists) # type: ignore main_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: 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_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 # sub ones
auto_export: PointerProperty(type=auto_export_settings.AutoExportSettings) # type: ignore 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
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
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
@classmethod @classmethod
def register(cls): 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) bpy.types.WindowManager.blenvy = PointerProperty(type=BlenvyManager)
@classmethod @classmethod
def unregister(cls): def unregister(cls):
del bpy.types.WindowManager.blenvy del bpy.types.WindowManager.blenvy
del bpy.types.WindowManager.main_scene
del bpy.types.WindowManager.library_scene
def load_settings(self): def load_settings(self):
print("LOAD SETTINGS")
settings = load_settings(self.settings_save_path) settings = load_settings(self.settings_save_path)
if settings is not None: if settings is not None:
if "mode" in settings: if "mode" in settings:
@ -149,3 +158,9 @@ class BlenvyManager(PropertyGroup):
for asset_path_name in asset_path_names: for asset_path_name in asset_path_names:
if asset_path_name in settings: if asset_path_name in settings:
setattr(self, asset_path_name, settings[asset_path_name]) 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""" """Switch bevy tooling"""
bl_idname = "bevy.tooling_switch" bl_idname = "bevy.tooling_switch"
bl_label = "Switch bevy tooling" bl_label = "Switch bevy tooling"
bl_options = {"UNDO"} #bl_options = {}
tool: EnumProperty( tool: EnumProperty(

View File

@ -7,6 +7,23 @@ class SceneSelector(bpy.types.PropertyGroup):
display: bpy.props.BoolProperty() # type: ignore display: bpy.props.BoolProperty() # type: ignore
# convenience utility to get lists of scenes
def get_main_and_library_scenes(settings):
level_scene_names= getattr(settings, "main_scene_names", []) #list(map(lambda scene: scene.name, getattr(settings,"main_scenes")))
library_scene_names = getattr(settings, "library_scene_names", []) #list(map(lambda scene: scene.name, getattr(settings,"library_scenes")))
level_scene_names= list(map(lambda scene: scene.name, getattr(settings,"main_scenes")))
library_scene_names = list(map(lambda scene: scene.name, getattr(settings,"library_scenes")))
level_scene_names = list(filter(lambda name: name in bpy.data.scenes, level_scene_names))
library_scene_names = list(filter(lambda name: name in bpy.data.scenes, library_scene_names))
level_scenes = list(map(lambda name: bpy.data.scenes[name], level_scene_names))
library_scenes = list(map(lambda name: bpy.data.scenes[name], library_scene_names))
return [level_scene_names, level_scenes, library_scene_names, library_scenes]
def add_scene_property(scene, scene_component_name, property_data, limit_to=None): def add_scene_property(scene, scene_component_name, property_data, limit_to=None):
root_collection = scene.collection root_collection = scene.collection
scene_property = None scene_property = None

View File

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

View File

@ -1,7 +1,6 @@
import bpy import bpy
import blenvy.bevy_components.ui as components_ui import blenvy.add_ons.bevy_components.ui as components_ui
import blenvy.gltf_auto_export.ui as auto_export_ui import blenvy.add_ons.auto_export.ui as auto_export_ui
from blenvy.settings import load_settings
# from ...bevy_components.components import ui# as components_ui # from ...bevy_components.components import ui# as components_ui
###################################################### ######################################################
@ -105,7 +104,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel):
rows = 2 rows = 2
row = section.row() row = section.row()
row.label(text="main scenes") row.label(text="main scenes")
row.prop(context.window_manager, "main_scene", text='') row.prop(blenvy, "main_scene_selector", text='')
row = section.row() row = section.row()
row.template_list("SCENE_UL_Blenvy", "level scenes", blenvy, "main_scenes", blenvy, "main_scenes_index", rows=rows) 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.action = 'ADD'
add_operator.scene_type = 'LEVEL' add_operator.scene_type = 'LEVEL'
#add_operator.operator = operator #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() sub_row = col.row()
remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="") 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 # library scenes
row = section.row() row = section.row()
row.label(text="library scenes") row.label(text="library scenes")
row.prop(context.window_manager, "library_scene", text='') row.prop(blenvy, "library_scene_selector", text='')
row = section.row() row = section.row()
row.template_list("SCENE_UL_Blenvy", "library scenes", blenvy, "library_scenes", blenvy, "library_scenes_index", rows=rows) 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 = sub_row.operator("scene_list.list_action", icon='ADD', text="")
add_operator.action = 'ADD' add_operator.action = 'ADD'
add_operator.scene_type = 'LIBRARY' 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() sub_row = col.row()
@ -149,7 +148,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel):
header, panel = layout.panel("components", default_closed=False) header, panel = layout.panel("components", default_closed=False)
header.label(text="Components") header.label(text="Components")
if panel: 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, panel = layout.panel("auto_export", default_closed=False)
header.label(text="Auto Export") 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 import bpy
def upsert_settings(name, data): 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: if stored_settings is None:
stored_settings = bpy.data.texts.new(name) stored_settings = bpy.data.texts.new(name)
stored_settings.write(json.dumps(data)) stored_settings.write(json.dumps(data))
@ -14,10 +14,43 @@ def upsert_settings(name, data):
def load_settings(name): def load_settings(name):
stored_settings = bpy.data.texts[name] if name in bpy.data.texts else None stored_settings = bpy.data.texts[name] if name in bpy.data.texts else None
if stored_settings != None: if stored_settings is not None:
return json.loads(stored_settings.as_string()) try:
return json.loads(stored_settings.as_string())
except:
return None
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 # checks if old & new settings (dicts really) are identical
def are_settings_identical(old, new, white_list=None): def are_settings_identical(old, new, white_list=None):
if old is None and new is None: if old is None and new is None:

View File

@ -5,9 +5,9 @@ import pytest
def setup_data(request): def setup_data(request):
print("\nSetting up resources...") 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(): def finalizer():
print("\nPerforming teardown...") print("\nPerforming teardown...")

View File

@ -9,7 +9,7 @@ import filecmp
from PIL import Image from PIL import Image
from pixelmatch.contrib.PIL import pixelmatch 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 @pytest.fixture
def setup_data(request): 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): def test_components_should_generate_correct_custom_properties(setup_data):
registry = bpy.context.window_manager.components_registry 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() bpy.ops.object.reload_registry()
type_infos = registry.type_infos 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): def test_components_should_generate_correct_custom_properties_with_randomized_values(setup_data):
registry = bpy.context.window_manager.components_registry 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() bpy.ops.object.reload_registry()
type_infos = registry.type_infos 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): def test_components_should_generate_correct_propertyGroup_values_from_custom_properties(setup_data):
registry = bpy.context.window_manager.components_registry 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() bpy.ops.object.reload_registry()
type_infos = registry.type_infos 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): def test_remove_components(setup_data):
registry = bpy.context.window_manager.components_registry 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() bpy.ops.object.reload_registry()
type_infos = registry.type_infos type_infos = registry.type_infos
@ -207,7 +207,7 @@ def test_remove_components(setup_data):
def test_copy_paste_components(setup_data): def test_copy_paste_components(setup_data):
context = bpy.context context = bpy.context
registry = context.window_manager.components_registry registry = context.window_manager.components_registry
registry.schemaPath = setup_data["components_schemaPath"] registry.schema_path = setup_data["components_schemaPath"]
bpy.ops.object.reload_registry() bpy.ops.object.reload_registry()
long_name = "bevy_example::test_components::BasicTest" long_name = "bevy_example::test_components::BasicTest"

View File

@ -3,7 +3,7 @@ from .setup_data import setup_data
def test_blend(setup_data): def test_blend(setup_data):
registry = bpy.context.window_manager.components_registry 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() bpy.ops.object.reload_registry()
long_name = "bevy_example::test_components::BasicTest" 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): def test_rename_component_single_unit_struct(setup_data):
registry = bpy.context.window_manager.components_registry 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() bpy.ops.object.reload_registry()
rename_component_operator = bpy.ops.object.rename_bevy_component 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): def test_rename_component_single_complex_struct(setup_data):
registry = bpy.context.window_manager.components_registry 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() bpy.ops.object.reload_registry()
rename_component_operator = bpy.ops.object.rename_bevy_component 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): def test_rename_component_bulk(setup_data):
registry = bpy.context.window_manager.components_registry 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() bpy.ops.object.reload_registry()
rename_component_operator = bpy.ops.object.rename_bevy_component 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): def test_rename_component_single_error_handling(setup_data):
registry = bpy.context.window_manager.components_registry 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() bpy.ops.object.reload_registry()
rename_component_operator = bpy.ops.object.rename_bevy_component 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): def test_rename_component_single_error_handling_clean_errors(setup_data):
registry = bpy.context.window_manager.components_registry 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() bpy.ops.object.reload_registry()
rename_component_operator = bpy.ops.object.rename_bevy_component 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): def test_shuffler(setup_data):
registry = bpy.context.window_manager.components_registry 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() bpy.ops.object.reload_registry()
type_infos = registry.type_infos type_infos = registry.type_infos