Compare commits

..

No commits in common. "8683a6482fb19f64035ea6f2324c60c19bafb8e5" and "64fd308fd33869c53eedbd40f363d9671d259863" have entirely different histories.

16 changed files with 63 additions and 179 deletions

View File

@ -17,8 +17,8 @@ pub struct BlueprintAnimationPlayerLink(pub Entity);
#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)]
/// storage for scene level animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations`
pub struct SceneAnimations {
/// storage for animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations`
pub struct InstanceAnimations {
pub named_animations: HashMap<String, Handle<AnimationClip>>,
}
@ -27,7 +27,7 @@ pub struct SceneAnimations {
/// so that the root entity knows which of its children contains an actualy `AnimationPlayer` component
/// this is for convenience, because currently , Bevy's gltf parsing inserts `AnimationPlayers` "one level down"
/// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid
pub struct SceneAnimationPlayerLink(pub Entity);
pub struct InstanceAnimationPlayerLink(pub Entity);
/// Stores Animation information: name, frame informations etc
#[derive(Reflect, Default, Debug)]
@ -78,8 +78,8 @@ pub fn trigger_instance_animation_markers_events(
animation_infos: Query<(
Entity,
&AnimationMarkers,
&SceneAnimationPlayerLink,
&SceneAnimations,
&InstanceAnimationPlayerLink,
&InstanceAnimations,
&AnimationInfos,
)>,
animation_players: Query<&AnimationPlayer>,

View File

@ -120,7 +120,7 @@ impl Plugin for BlueprintsPlugin {
.register_type::<MaterialInfo>()
.register_type::<SpawnHere>()
.register_type::<BlueprintAnimations>()
.register_type::<SceneAnimations>()
.register_type::<InstanceAnimations>()
.register_type::<AnimationInfo>()
.register_type::<AnimationInfos>()
.register_type::<Vec<AnimationInfo>>()

View File

@ -3676,7 +3676,7 @@
"type": "object",
"typeInfo": "Struct"
},
"bevy_gltf_blueprints::animation::SceneAnimations": {
"bevy_gltf_blueprints::animation::InstanceAnimations": {
"additionalProperties": false,
"isComponent": true,
"isResource": false,
@ -3690,8 +3690,8 @@
"required": [
"named_animations"
],
"short_name": "SceneAnimations",
"title": "bevy_gltf_blueprints::animation::SceneAnimations",
"short_name": "InstanceAnimations",
"title": "bevy_gltf_blueprints::animation::InstanceAnimations",
"type": "object",
"typeInfo": "Struct"
},

View File

@ -2,7 +2,7 @@ use std::time::Duration;
use bevy_gltf_blueprints::{
AnimationInfos, AnimationMarkerReached, BlueprintAnimationPlayerLink, BlueprintAnimations,
SceneAnimationPlayerLink, SceneAnimations,
InstanceAnimationPlayerLink, InstanceAnimations,
};
use bevy::{gltf::Gltf, prelude::*};
@ -58,7 +58,7 @@ pub fn animations(
name, entity
);
println!("Found match {:?}", gltf.named_animations);
commands.entity(entity).insert(SceneAnimations {
commands.entity(entity).insert(InstanceAnimations {
named_animations: gltf.named_animations.clone(),
});
for ancestor in parents.iter_ancestors(entity) {
@ -66,7 +66,7 @@ pub fn animations(
// println!("found match with animationPlayer !! {:?}",names.get(ancestor));
commands
.entity(entity)
.insert(SceneAnimationPlayerLink(ancestor));
.insert(InstanceAnimationPlayerLink(ancestor));
}
// info!("{:?} is an ancestor of {:?}", ancestor, player);
}
@ -77,17 +77,17 @@ pub fn animations(
pub fn play_animations(
animated_marker1: Query<
(&SceneAnimationPlayerLink, &SceneAnimations),
(&InstanceAnimationPlayerLink, &InstanceAnimations),
(With<AnimationInfos>, With<Marker1>),
>,
animated_marker2: Query<
(&SceneAnimationPlayerLink, &SceneAnimations),
(&InstanceAnimationPlayerLink, &InstanceAnimations),
(With<AnimationInfos>, With<Marker2>),
>,
animated_marker3: Query<
(
&SceneAnimationPlayerLink,
&SceneAnimations,
&InstanceAnimationPlayerLink,
&InstanceAnimations,
&BlueprintAnimationPlayerLink,
&BlueprintAnimations,
),

View File

@ -5,7 +5,6 @@ import traceback
from .export_main_scenes import export_main_scene
from .export_blueprints import check_if_blueprint_on_disk, check_if_blueprints_exist, export_blueprints_from_collections
from .get_standard_exporter_settings import get_standard_exporter_settings
from ..helpers.helpers_scenes import (get_scenes, )
from ..helpers.helpers_collections import (get_collections_in_library, get_exportable_collections, get_collections_per_scene, find_collection_ascendant_target_collection)
@ -35,8 +34,9 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
# standard gltf export settings are stored differently
standard_gltf_exporter_settings = get_standard_exporter_settings()
standard_gltf_exporter_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings")
print("standard_gltf_exporter_settings", standard_gltf_exporter_settings.as_string())
standard_gltf_exporter_settings = json.loads(standard_gltf_exporter_settings.as_string())
print("main scenes", main_scene_names, "library_scenes", library_scene_names)
print("export_output_folder", export_output_folder)

View File

@ -1,7 +1,6 @@
import os
import bpy
from ..constants import TEMPSCENE_PREFIX
from ..helpers.generate_and_export import generate_and_export
from .export_gltf import (generate_gltf_export_preferences)
from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into
@ -25,7 +24,7 @@ def export_collections(collections, folder_path, library_scene, addon_prefs, glt
collection = bpy.data.collections[collection_name]
generate_and_export(
addon_prefs,
temp_scene_name=TEMPSCENE_PREFIX+collection.name,
temp_scene_name="__temp_scene_"+collection.name,
export_settings=export_settings,
gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(collection, temp_collection, library_collections=library_collections, addon_prefs=addon_prefs),

View File

@ -2,7 +2,6 @@ import json
import os
import bpy
from .get_standard_exporter_settings import get_standard_exporter_settings
from .preferences import (AutoExportGltfPreferenceNames)
def generate_gltf_export_preferences(addon_prefs):
@ -49,7 +48,9 @@ def generate_gltf_export_preferences(addon_prefs):
gltf_export_preferences[key] = getattr(addon_prefs, key)
standard_gltf_exporter_settings = get_standard_exporter_settings()
standard_gltf_exporter_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings")
standard_gltf_exporter_settings = json.loads(standard_gltf_exporter_settings.as_string())
"""standard_gltf_exporter_settings = get_standard_exporter_settings()"""
#print("standard settings", standard_gltf_exporter_settings)
constant_keys = [

View File

@ -1,7 +1,6 @@
import os
import bpy
from ..constants import TEMPSCENE_PREFIX
from ..helpers.generate_and_export import generate_and_export
from .export_gltf import (generate_gltf_export_preferences, export_gltf)
from ..modules.bevy_dynamic import is_object_dynamic, is_object_static
@ -39,7 +38,7 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
# first export static objects
generate_and_export(
addon_prefs,
temp_scene_name=TEMPSCENE_PREFIX,
temp_scene_name="__temp_scene",
export_settings=export_settings,
gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, filter=is_object_static, addon_prefs=addon_prefs),
@ -50,7 +49,7 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
gltf_output_path = os.path.join(folder_path, export_output_folder, scene.name+ "_dynamic")
generate_and_export(
addon_prefs,
temp_scene_name=TEMPSCENE_PREFIX,
temp_scene_name="__temp_scene",
export_settings=export_settings,
gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, filter=is_object_dynamic, addon_prefs=addon_prefs),
@ -61,7 +60,7 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
#print("NO SPLIT")
generate_and_export(
addon_prefs,
temp_scene_name=TEMPSCENE_PREFIX,
temp_scene_name="__temp_scene",
export_settings=export_settings,
gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, addon_prefs=addon_prefs),

View File

@ -1,14 +0,0 @@
import bpy
import json
def get_standard_exporter_settings():
standard_gltf_exporter_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_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

@ -46,6 +46,7 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
bpy.types.WindowManager.main_scenes_list_index = IntProperty(name = "Index for main scenes list", default = 0)
bpy.types.WindowManager.library_scenes_list_index = IntProperty(name = "Index for library scenes list", default = 0)
bpy.types.WindowManager.previous_export_settings = StringProperty(default="")
cls.main_scenes_index = 0
cls.library_scenes_index = 0
@ -58,6 +59,8 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
del bpy.types.WindowManager.main_scenes_list_index
del bpy.types.WindowManager.library_scenes_list_index
del bpy.types.WindowManager.previous_export_settings
def is_scene_ok(self, scene):
try:
operator = bpy.context.space_data.active_operator
@ -158,20 +161,9 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
# if there were no setting before, it is new, we need export
changed = False
print("previous_auto_settings", previous_auto_settings, "previous_gltf_settings", previous_gltf_settings)
if previous_auto_settings == None:
if previous_auto_settings == None or previous_gltf_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(".gltf_auto_export_gltf_settings_previous")
previous_gltf_settings.write(json.dumps({}))
if current_gltf_settings == None:
current_gltf_settings = bpy.data.texts[".gltf_auto_export_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
@ -200,6 +192,7 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
def execute(self, context):
print("execute")
# disable change detection while the operator runs
bpy.context.window_manager.auto_export_tracker.disable_change_detection()
if self.direct_mode:
self.load_settings(context)
@ -210,8 +203,6 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
if self.auto_export: # only do the actual exporting if auto export is actually enabled
#& do the export
if self.direct_mode: #Do not auto export when applying settings in the menu, do it on save only
# disable change detection while the operator runs
#determine changed parameters
params_changed = self.did_export_settings_change()
auto_export(changes_per_scene, params_changed, self)
@ -226,21 +217,14 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
#bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)
else:
print("auto export disabled, skipping")
"""if not self.direct_mode:
print("enabling")
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)
return {'FINISHED'}
def invoke(self, context, event):
print("invoke")
bpy.context.window_manager.auto_export_tracker.disable_change_detection()
self.load_settings(context)
addon_prefs = self
"""[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_scenes(addon_prefs)
(collections, _) = get_exportable_collections(level_scenes, library_scenes, addon_prefs)
try:
@ -251,20 +235,15 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
ui_info = bpy.context.window_manager.exportedCollections.add()
ui_info.name = collection_name
except Exception as error:
self.report({"ERROR"}, "Failed to populate list of exported collections/blueprints")"""
self.report({"ERROR"}, "Failed to populate list of exported collections/blueprints")
wm = context.window_manager
wm.fileselect_add(self)
return {'RUNNING_MODAL'}
def draw(self, context):
pass
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,9 +1,8 @@
import json
import bpy
from bpy.types import (PropertyGroup)
from bpy.props import (PointerProperty, IntProperty, StringProperty)
from bpy.props import (PointerProperty, IntProperty)
from ..constants import TEMPSCENE_PREFIX
from .internals import CollectionsToExport
class AutoExportTracker(PropertyGroup):
@ -22,8 +21,6 @@ class AutoExportTracker(PropertyGroup):
default=0
) # type: ignore
@classmethod
def register(cls):
bpy.types.WindowManager.auto_export_tracker = PointerProperty(type=AutoExportTracker)
@ -62,15 +59,10 @@ class AutoExportTracker(PropertyGroup):
@classmethod
def deps_update_handler(cls, scene, depsgraph):
print("change detection enabled", cls.change_detection_enabled)
ops = bpy.context.window_manager.operators
print("last operators", ops)
for op in ops:
print("operator", op)
print("change detection enabled", cls.change_detection_enabled, bpy.context.window_manager.auto_export_tracker.change_detection_enabled)
active_operator = bpy.context.active_operator
if active_operator:
print("Operator", active_operator.bl_label, active_operator.bl_idname)
# print("Operator", active_operator.bl_label, active_operator.bl_idname)
if active_operator.bl_idname == "EXPORT_SCENE_OT_gltf" and active_operator.gltf_export_id == "gltf_auto_export":
# we backup any existing gltf export settings, if there were any
scene = bpy.context.scene
@ -88,21 +80,19 @@ class AutoExportTracker(PropertyGroup):
active_operator.will_save_settings = True
active_operator.auto_export = True
# only deal with changes if we are NOT in the mids of saving/exporting
if cls.change_detection_enabled:
# ignore anything going on with temporary scenes
if not scene.name.startswith(TEMPSCENE_PREFIX):
if not scene.name.startswith("__temp_scene"):
print("depsgraph_update_post", scene.name)
changed_scene = scene.name or ""
# only deal with changes if we are no in the mids of saving/exporting
if cls.change_detection_enabled:
#print("-------------")
if not changed_scene in cls.changed_objects_per_scene:
cls.changed_objects_per_scene[changed_scene] = {}
print("cls.changed_objects_per_scene", cls.changed_objects_per_scene)
depsgraph = bpy.context.evaluated_depsgraph_get()
# depsgraph = bpy.context.evaluated_depsgraph_get()
for obj in depsgraph.updates:
print("depsgraph update", obj)
# print("depsgraph update", obj)
if isinstance(obj.id, bpy.types.Object):
# get the actual object
object = bpy.data.objects[obj.id.name]
@ -110,7 +100,7 @@ class AutoExportTracker(PropertyGroup):
print("FOO","transforms", obj.is_updated_transform, "geometry", obj.is_updated_geometry)
cls.changed_objects_per_scene[scene.name][obj.id.name] = object
elif isinstance(obj.id, bpy.types.Material): # or isinstance(obj.id, bpy.types.ShaderNodeTree):
print("changed material", obj.id, "scene", scene.name,)
# print("changed material", obj.id, "scene", scene.name,)
material = bpy.data.materials[obj.id.name]
#now find which objects are using the material
for obj in bpy.data.objects:
@ -123,7 +113,7 @@ class AutoExportTracker(PropertyGroup):
items += len(cls.changed_objects_per_scene[scene_name].keys())
if items == 0:
cls.changed_objects_per_scene.clear()
print("changed_objects_per_scene", cls.changed_objects_per_scene)
#print("changed_objects_per_scene", cls.changed_objects_per_scene)
else:
cls.changed_objects_per_scene.clear()
@ -135,15 +125,13 @@ class AutoExportTracker(PropertyGroup):
print("disable change detection")
self.change_detection_enabled = False
self.__class__.change_detection_enabled = False
return None
def enable_change_detection(self):
print("enable change detection")
self.change_detection_enabled = True
self.__class__.change_detection_enabled = True
#FIXME: not sure about these
self.changed_objects_per_scene.clear()
self.__class__.changed_objects_per_scene.clear()
# bpy.context.window_manager.auto_export_tracker.change_detection_enabled = True
print("bpy.context.window_manager.auto_export_tracker.change_detection_enabled", bpy.context.window_manager.auto_export_tracker.change_detection_enabled)
return None

View File

@ -1 +0,0 @@
TEMPSCENE_PREFIX = "__temp_scene"

View File

@ -195,12 +195,11 @@ def test_export_changed_parameters(setup_data):
# now same, but move the cube in the library
print("----------------")
print("library change (blueprint) ")
print("library change")
print("----------------")
bpy.context.window_manager.auto_export_tracker.enable_change_detection() # FIXME: should not be needed, but ..
bpy.data.objects["Blueprint1_mesh"].location = [1, 2, 1]
auto_export_operator(
auto_export=True,
direct_mode=True,
@ -213,55 +212,17 @@ def test_export_changed_parameters(setup_data):
modification_times = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths + [world_file_path]))
assert modification_times != modification_times_first
# the "world" file should have changed (TODO: double check: this is since changing an instances collection changes the instance too ?)
world_file_index = mapped_files_to_timestamps_and_index["World"][1]
# and the blueprint1 file too, since that is the collection we changed
# only the "world" file should have changed
blueprint1_file_index = mapped_files_to_timestamps_and_index["Blueprint1"][1]
other_files_modification_times = [value for index, value in enumerate(modification_times) if index not in [world_file_index, blueprint1_file_index]]
other_files_modification_times_first = [value for index, value in enumerate(modification_times_first) if index not in [world_file_index, blueprint1_file_index]]
other_files_modification_times = [value for index, value in enumerate(modification_times) if index not in [blueprint1_file_index]]
other_files_modification_times_first = [value for index, value in enumerate(modification_times_first) if index not in [blueprint1_file_index]]
assert modification_times[world_file_index] != modification_times_first[world_file_index]
assert modification_times[blueprint1_file_index] != modification_times_first[blueprint1_file_index]
assert other_files_modification_times == other_files_modification_times_first
# reset the comparing
modification_times_first = modification_times
# now change something in a nested blueprint
print("----------------")
print("library change (nested blueprint) ")
print("----------------")
bpy.context.window_manager.auto_export_tracker.enable_change_detection() # FIXME: should not be needed, but ..
bpy.data.objects["Blueprint3_mesh"]["test_component"] = 42
auto_export_operator(
auto_export=True,
direct_mode=True,
export_output_folder="./models",
export_scene_settings=True,
export_blueprints=True,
export_legacy_mode=False,
export_materials_library=False
)
modification_times = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths + [world_file_path]))
assert modification_times != modification_times_first
# the "world" file should have changed (TODO: double check: this is since changing an instances collection changes the instance too ?)
world_file_index = mapped_files_to_timestamps_and_index["World"][1]
# and the blueprint1 file too, since that is the collection we changed
blueprint1_file_index = mapped_files_to_timestamps_and_index["Blueprint1"][1]
other_files_modification_times = [value for index, value in enumerate(modification_times) if index not in [world_file_index, blueprint1_file_index]]
other_files_modification_times_first = [value for index, value in enumerate(modification_times_first) if index not in [world_file_index, blueprint1_file_index]]
assert modification_times[world_file_index] != modification_times_first[world_file_index]
assert modification_times[blueprint1_file_index] != modification_times_first[blueprint1_file_index]
assert other_files_modification_times == other_files_modification_times_first
# reset the comparing
modification_times_first = modification_times
# now same, but using an operator
print("----------------")

View File

@ -47,28 +47,8 @@ def setup_data(request):
- checks if timestamps have changed
- if all worked => test is a-ok
- removes generated files
"""
def test_export_no_parameters(setup_data):
root_path = "../../testing/bevy_example"
assets_root_path = os.path.join(root_path, "assets")
models_path = os.path.join(assets_root_path, "models")
auto_export_operator = bpy.ops.export_scenes.auto_gltf
# first test exporting withouth any parameters set, this should export with default parameters gracefully
auto_export_operator(
auto_export=True,
direct_mode=True,
export_output_folder="./models",
export_legacy_mode=False,
export_materials_library=True
)
def test_export_changed_parameters(setup_data):
root_path = "../../testing/bevy_example"
assets_root_path = os.path.join(root_path, "assets")
@ -97,6 +77,11 @@ def test_export_changed_parameters(setup_data):
stored_gltf_settings.clear()
stored_gltf_settings.write(json.dumps(gltf_settings))
# move the main cube
bpy.data.objects["Cube"].location = [1, 0, 0]
# move the cube in the library
bpy.data.objects["Blueprint1_mesh"].location = [1, 2, 1]
auto_export_operator(
auto_export=True,
direct_mode=True,

View File

@ -1,4 +0,0 @@
- investigate remove_blueprints_list_from_main_scene (could be a case of changes to bpy.data not being applied immediatly)
- investigate clearing of changed_objects_per_scene
- it seems bevy_components does not trigger updates
- undo redo is ignored: ie save, do something, undo it, you still get changes

View File

@ -48,15 +48,6 @@ class GLTF_PT_auto_export_SidePanel(bpy.types.Panel):
op = layout.operator("EXPORT_SCENES_OT_auto_gltf", text="Auto Export Settings")
op.auto_export = True
layout.label(text="changes since last save:")
changed_objects_per_scene = {}
for scene in context.window_manager.auto_export_tracker.changed_objects_per_scene:
if not scene in changed_objects_per_scene.keys():
changed_objects_per_scene[scene] = []
changed_objects_per_scene[scene]+= context.window_manager.auto_export_tracker.changed_objects_per_scene[scene].keys()
layout.label(text=str(changed_objects_per_scene))
#print("GLTF_PT_export_main", GLTF_PT_export_main.bl_parent_id)
# main ui in the file => export