diff --git a/examples/bevy_gltf_blueprints/animation/assets/animation.blend b/examples/bevy_gltf_blueprints/animation/assets/animation.blend index aaa6a1c..b142524 100644 Binary files a/examples/bevy_gltf_blueprints/animation/assets/animation.blend and b/examples/bevy_gltf_blueprints/animation/assets/animation.blend differ diff --git a/examples/bevy_gltf_blueprints/animation/assets/models/Level1.glb b/examples/bevy_gltf_blueprints/animation/assets/models/Level1.glb index 58d5d87..7ed4887 100644 Binary files a/examples/bevy_gltf_blueprints/animation/assets/models/Level1.glb and b/examples/bevy_gltf_blueprints/animation/assets/models/Level1.glb differ diff --git a/examples/bevy_gltf_blueprints/animation/assets/models/library/Container.glb b/examples/bevy_gltf_blueprints/animation/assets/models/library/Container.glb index d6ff100..e0078e7 100644 Binary files a/examples/bevy_gltf_blueprints/animation/assets/models/library/Container.glb and b/examples/bevy_gltf_blueprints/animation/assets/models/library/Container.glb differ diff --git a/examples/bevy_gltf_blueprints/animation/assets/models/library/Fox.glb b/examples/bevy_gltf_blueprints/animation/assets/models/library/Fox.glb index 1730d16..e30ac35 100644 Binary files a/examples/bevy_gltf_blueprints/animation/assets/models/library/Fox.glb and b/examples/bevy_gltf_blueprints/animation/assets/models/library/Fox.glb differ diff --git a/examples/bevy_gltf_blueprints/animation/assets/models/library/Health_Pickup.glb b/examples/bevy_gltf_blueprints/animation/assets/models/library/Health_Pickup.glb index b6ef6e7..c88b00d 100644 Binary files a/examples/bevy_gltf_blueprints/animation/assets/models/library/Health_Pickup.glb and b/examples/bevy_gltf_blueprints/animation/assets/models/library/Health_Pickup.glb differ diff --git a/examples/bevy_gltf_blueprints/animation/assets/models/library/MagicTeapot.glb b/examples/bevy_gltf_blueprints/animation/assets/models/library/MagicTeapot.glb index ac33ac0..b757818 100644 Binary files a/examples/bevy_gltf_blueprints/animation/assets/models/library/MagicTeapot.glb and b/examples/bevy_gltf_blueprints/animation/assets/models/library/MagicTeapot.glb differ diff --git a/examples/bevy_gltf_blueprints/animation/assets/models/library/Pillar.glb b/examples/bevy_gltf_blueprints/animation/assets/models/library/Pillar.glb index a3a3b1f..891122c 100644 Binary files a/examples/bevy_gltf_blueprints/animation/assets/models/library/Pillar.glb and b/examples/bevy_gltf_blueprints/animation/assets/models/library/Pillar.glb differ diff --git a/examples/bevy_gltf_blueprints/animation/assets/models/library/Player.glb b/examples/bevy_gltf_blueprints/animation/assets/models/library/Player.glb index 7fbc58c..139ac30 100644 Binary files a/examples/bevy_gltf_blueprints/animation/assets/models/library/Player.glb and b/examples/bevy_gltf_blueprints/animation/assets/models/library/Player.glb differ diff --git a/examples/bevy_gltf_blueprints/animation/assets/models/library/Wheelbot.glb b/examples/bevy_gltf_blueprints/animation/assets/models/library/Wheelbot.glb index a3fb60e..25c8168 100644 Binary files a/examples/bevy_gltf_blueprints/animation/assets/models/library/Wheelbot.glb and b/examples/bevy_gltf_blueprints/animation/assets/models/library/Wheelbot.glb differ diff --git a/examples/bevy_gltf_blueprints/basic/assets/advanced.blend b/examples/bevy_gltf_blueprints/basic/assets/advanced.blend index 6ce38c0..3f711e3 100644 Binary files a/examples/bevy_gltf_blueprints/basic/assets/advanced.blend and b/examples/bevy_gltf_blueprints/basic/assets/advanced.blend differ diff --git a/examples/bevy_gltf_blueprints/basic/assets/models/World.glb b/examples/bevy_gltf_blueprints/basic/assets/models/World.glb index 8918e96..b71d240 100644 Binary files a/examples/bevy_gltf_blueprints/basic/assets/models/World.glb and b/examples/bevy_gltf_blueprints/basic/assets/models/World.glb differ diff --git a/examples/bevy_gltf_blueprints/basic/assets/models/library/Container.glb b/examples/bevy_gltf_blueprints/basic/assets/models/library/Container.glb index 9bf40cc..72ff5ca 100644 Binary files a/examples/bevy_gltf_blueprints/basic/assets/models/library/Container.glb and b/examples/bevy_gltf_blueprints/basic/assets/models/library/Container.glb differ diff --git a/examples/bevy_gltf_blueprints/basic/assets/models/library/Health_Pickup.glb b/examples/bevy_gltf_blueprints/basic/assets/models/library/Health_Pickup.glb index 16bf2aa..4643320 100644 Binary files a/examples/bevy_gltf_blueprints/basic/assets/models/library/Health_Pickup.glb and b/examples/bevy_gltf_blueprints/basic/assets/models/library/Health_Pickup.glb differ diff --git a/examples/bevy_gltf_blueprints/basic/assets/models/library/MagicTeapot.glb b/examples/bevy_gltf_blueprints/basic/assets/models/library/MagicTeapot.glb index 63dc035..7a7020b 100644 Binary files a/examples/bevy_gltf_blueprints/basic/assets/models/library/MagicTeapot.glb and b/examples/bevy_gltf_blueprints/basic/assets/models/library/MagicTeapot.glb differ diff --git a/examples/bevy_gltf_blueprints/basic/assets/models/library/Pillar.glb b/examples/bevy_gltf_blueprints/basic/assets/models/library/Pillar.glb index 617b863..891122c 100644 Binary files a/examples/bevy_gltf_blueprints/basic/assets/models/library/Pillar.glb and b/examples/bevy_gltf_blueprints/basic/assets/models/library/Pillar.glb differ diff --git a/examples/bevy_gltf_blueprints/basic/assets/models/library/Player.glb b/examples/bevy_gltf_blueprints/basic/assets/models/library/Player.glb index 986b7da..a7ef15f 100644 Binary files a/examples/bevy_gltf_blueprints/basic/assets/models/library/Player.glb and b/examples/bevy_gltf_blueprints/basic/assets/models/library/Player.glb differ diff --git a/examples/bevy_gltf_blueprints/basic/assets/models/library/Unused_in_level_test.glb b/examples/bevy_gltf_blueprints/basic/assets/models/library/Unused_in_level_test.glb index dff3f87..b5937bb 100644 Binary files a/examples/bevy_gltf_blueprints/basic/assets/models/library/Unused_in_level_test.glb and b/examples/bevy_gltf_blueprints/basic/assets/models/library/Unused_in_level_test.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/World.glb b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/World.glb index e73bc9f..3ecc7c2 100644 Binary files a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/World.glb and b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/World.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Container.glb b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Container.glb index 21cfd54..72ff5ca 100644 Binary files a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Container.glb and b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Container.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Health_Pickup.glb b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Health_Pickup.glb index c9653e6..4643320 100644 Binary files a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Health_Pickup.glb and b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Health_Pickup.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/MagicTeapot.glb b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/MagicTeapot.glb index 22e5e16..7a7020b 100644 Binary files a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/MagicTeapot.glb and b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/MagicTeapot.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Pillar.glb b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Pillar.glb index 13a5b7d..891122c 100644 Binary files a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Pillar.glb and b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Pillar.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Player.glb b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Player.glb index 1546e5f..a7ef15f 100644 Binary files a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Player.glb and b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Player.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Unused_in_level_test.glb b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Unused_in_level_test.glb index dff3f87..b5937bb 100644 Binary files a/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Unused_in_level_test.glb and b/examples/bevy_gltf_blueprints/basic_scene_components/assets/models/library/Unused_in_level_test.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_scene_components/assets/scene_components.blend b/examples/bevy_gltf_blueprints/basic_scene_components/assets/scene_components.blend index d76780e..96f0b19 100644 Binary files a/examples/bevy_gltf_blueprints/basic_scene_components/assets/scene_components.blend and b/examples/bevy_gltf_blueprints/basic_scene_components/assets/scene_components.blend differ diff --git a/examples/bevy_gltf_blueprints/basic_wasm/assets/advanced.blend b/examples/bevy_gltf_blueprints/basic_wasm/assets/advanced.blend index 6ce38c0..0c555de 100644 Binary files a/examples/bevy_gltf_blueprints/basic_wasm/assets/advanced.blend and b/examples/bevy_gltf_blueprints/basic_wasm/assets/advanced.blend differ diff --git a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/World.glb b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/World.glb index 8918e96..b71d240 100644 Binary files a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/World.glb and b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/World.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Container.glb b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Container.glb index 9bf40cc..72ff5ca 100644 Binary files a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Container.glb and b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Container.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Health_Pickup.glb b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Health_Pickup.glb index 16bf2aa..4643320 100644 Binary files a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Health_Pickup.glb and b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Health_Pickup.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/MagicTeapot.glb b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/MagicTeapot.glb index 63dc035..7a7020b 100644 Binary files a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/MagicTeapot.glb and b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/MagicTeapot.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Pillar.glb b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Pillar.glb index 617b863..891122c 100644 Binary files a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Pillar.glb and b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Pillar.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Player.glb b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Player.glb index 986b7da..a7ef15f 100644 Binary files a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Player.glb and b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Player.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Unused_in_level_test.glb b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Unused_in_level_test.glb index dff3f87..b5937bb 100644 Binary files a/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Unused_in_level_test.glb and b/examples/bevy_gltf_blueprints/basic_wasm/assets/models/library/Unused_in_level_test.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/advanced.blend b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/advanced.blend index e0bf557..17f54bd 100644 Binary files a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/advanced.blend and b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/advanced.blend differ diff --git a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/World.glb b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/World.glb index 7af87fc..8ccee31 100644 Binary files a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/World.glb and b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/World.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Container.glb b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Container.glb index d1690af..6d57403 100644 Binary files a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Container.glb and b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Container.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Health_Pickup.glb b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Health_Pickup.glb index b073501..4643320 100644 Binary files a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Health_Pickup.glb and b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Health_Pickup.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/MagicTeapot.glb b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/MagicTeapot.glb index 0cde830..7a7020b 100644 Binary files a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/MagicTeapot.glb and b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/MagicTeapot.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Pillar.glb b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Pillar.glb index 8b4dd8a..24c17ac 100644 Binary files a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Pillar.glb and b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Pillar.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Player.glb b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Player.glb index 7240cb4..a7ef15f 100644 Binary files a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Player.glb and b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Player.glb differ diff --git a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Unused_in_level_test.glb b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Unused_in_level_test.glb index dff3f87..b5937bb 100644 Binary files a/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Unused_in_level_test.glb and b/examples/bevy_gltf_blueprints/basic_xpbd_physics/assets/models/library/Unused_in_level_test.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/materials.blend b/examples/bevy_gltf_blueprints/materials/assets/materials.blend index 7aaa027..c901e0c 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/materials.blend and b/examples/bevy_gltf_blueprints/materials/assets/materials.blend differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/materials/materials_materials_library.glb b/examples/bevy_gltf_blueprints/materials/assets/materials/materials_materials_library.glb index d266f0c..deb7aa8 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/materials/materials_materials_library.glb and b/examples/bevy_gltf_blueprints/materials/assets/materials/materials_materials_library.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/models/Level1.glb b/examples/bevy_gltf_blueprints/materials/assets/models/Level1.glb index 1091164..2206d69 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/models/Level1.glb and b/examples/bevy_gltf_blueprints/materials/assets/models/Level1.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/models/library/Container.glb b/examples/bevy_gltf_blueprints/materials/assets/models/library/Container.glb index 07b90c4..a84ecda 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/models/library/Container.glb and b/examples/bevy_gltf_blueprints/materials/assets/models/library/Container.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/models/library/Health_Pickup.glb b/examples/bevy_gltf_blueprints/materials/assets/models/library/Health_Pickup.glb index abd707c..89ed450 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/models/library/Health_Pickup.glb and b/examples/bevy_gltf_blueprints/materials/assets/models/library/Health_Pickup.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/models/library/Magic Sphere.glb b/examples/bevy_gltf_blueprints/materials/assets/models/library/Magic Sphere.glb index 288b862..a1db7d1 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/models/library/Magic Sphere.glb and b/examples/bevy_gltf_blueprints/materials/assets/models/library/Magic Sphere.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/models/library/MagicTeapot.glb b/examples/bevy_gltf_blueprints/materials/assets/models/library/MagicTeapot.glb index f8d4609..df5a8de 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/models/library/MagicTeapot.glb and b/examples/bevy_gltf_blueprints/materials/assets/models/library/MagicTeapot.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/models/library/Pillar.glb b/examples/bevy_gltf_blueprints/materials/assets/models/library/Pillar.glb index e2f4838..27beba2 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/models/library/Pillar.glb and b/examples/bevy_gltf_blueprints/materials/assets/models/library/Pillar.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/models/library/Pillar2.glb b/examples/bevy_gltf_blueprints/materials/assets/models/library/Pillar2.glb index 564b20b..c4d6ab5 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/models/library/Pillar2.glb and b/examples/bevy_gltf_blueprints/materials/assets/models/library/Pillar2.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/models/library/Player.glb b/examples/bevy_gltf_blueprints/materials/assets/models/library/Player.glb index 5fa615b..984be4c 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/models/library/Player.glb and b/examples/bevy_gltf_blueprints/materials/assets/models/library/Player.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon cut.glb b/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon cut.glb index 880c4dd..1582295 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon cut.glb and b/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon cut.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon.glb b/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon.glb index 0a3455c..79da62b 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon.glb and b/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon.glb differ diff --git a/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon2.glb b/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon2.glb index b2f2c0e..bae980b 100644 Binary files a/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon2.glb and b/examples/bevy_gltf_blueprints/materials/assets/models/library/Watermelon2.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/Level1.glb b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/Level1.glb index e793600..e92ef5e 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/Level1.glb and b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/Level1.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/Level2.glb b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/Level2.glb index 5d10ec2..19e30e7 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/Level2.glb and b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/Level2.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/StartLevel.glb b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/StartLevel.glb index 01232e8..b4899f5 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/StartLevel.glb and b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/StartLevel.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Health_Pickup.glb b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Health_Pickup.glb index 16bf2aa..4643320 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Health_Pickup.glb and b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Health_Pickup.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/LevelTransition.glb b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/LevelTransition.glb index aa95a41..99e7325 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/LevelTransition.glb and b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/LevelTransition.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Pillar.glb b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Pillar.glb index 398c04e..891122c 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Pillar.glb and b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Pillar.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Player.glb b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Player.glb index 7240cb4..a7ef15f 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Player.glb and b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Player.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Unused_in_level_test.glb b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Unused_in_level_test.glb index dff3f87..b5937bb 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Unused_in_level_test.glb and b/examples/bevy_gltf_blueprints/multiple_levels/assets/models/library/Unused_in_level_test.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels/assets/multiple_levels.blend b/examples/bevy_gltf_blueprints/multiple_levels/assets/multiple_levels.blend index d1f88f1..7148411 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels/assets/multiple_levels.blend and b/examples/bevy_gltf_blueprints/multiple_levels/assets/multiple_levels.blend differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/common.blend b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/common.blend index dfc02b9..bf43cf0 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/common.blend and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/common.blend differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/level1.blend b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/level1.blend index 89d3afc..5ff26b8 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/level1.blend and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/level1.blend differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/level2.blend b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/level2.blend index 594a3e4..d2412f8 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/level2.blend and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/level2.blend differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/start_level.blend b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/start_level.blend index 70ccb35..4c36a78 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/start_level.blend and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/art/start_level.blend differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/materials/common_materials_library.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/materials/common_materials_library.glb index fa2dffe..4227c4e 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/materials/common_materials_library.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/materials/common_materials_library.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/Level1.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/Level1.glb index 7759b9c..25a1707 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/Level1.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/Level1.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/Level2.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/Level2.glb index 08bb437..5309d8a 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/Level2.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/Level2.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/StartLevel.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/StartLevel.glb index c9d5777..30b813a 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/StartLevel.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/StartLevel.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Container.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Container.glb index 871cdf2..dddd157 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Container.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Container.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Crystal.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Crystal.glb index 9c66c93..40bc7ac 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Crystal.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Crystal.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Health_Pickup.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Health_Pickup.glb index d5a824a..1fac637 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Health_Pickup.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Health_Pickup.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Interactible.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Interactible.glb index 26c6f46..4797649 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Interactible.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Interactible.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/LevelTransition.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/LevelTransition.glb index 669d592..5065163 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/LevelTransition.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/LevelTransition.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/MagicTeapot.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/MagicTeapot.glb index f780bf8..f6e2313 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/MagicTeapot.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/MagicTeapot.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Nest_test.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Nest_test.glb index f274004..14eface 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Nest_test.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Nest_test.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Pillar.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Pillar.glb index 2d5b48c..0735c7f 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Pillar.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Pillar.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Player.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Player.glb index 0dc04a6..0fc1bd4 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Player.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Player.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Portal.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Portal.glb index a94db38..4fa20ae 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Portal.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Portal.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Rock Pile.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Rock Pile.glb index 380f6f6..9c52f1e 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Rock Pile.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Rock Pile.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Rock.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Rock.glb index cb72cc0..1b2df92 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Rock.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Rock.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Sub_blueprint.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Sub_blueprint.glb index b7d476c..02ad4d5 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Sub_blueprint.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Sub_blueprint.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Template_Demo.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Template_Demo.glb index 9427b0b..33a8bfc 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Template_Demo.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Template_Demo.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Unused_in_level_test.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Unused_in_level_test.glb index df9fee4..36b6ed4 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Unused_in_level_test.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Unused_in_level_test.glb differ diff --git a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Wall.glb b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Wall.glb index 0481cfe..9218f08 100644 Binary files a/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Wall.glb and b/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles/assets/models/library/Wall.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/World.glb b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/World.glb index fbd0e66..be19a70 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/World.glb and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/World.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Container.glb b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Container.glb index b54dbc3..72ff5ca 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Container.glb and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Container.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Enemy.glb b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Enemy.glb index 2d9f365..1a139bf 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Enemy.glb and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Enemy.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Finger.glb b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Finger.glb index 32d40e6..4ff291b 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Finger.glb and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Finger.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Hand.glb b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Hand.glb index 747e2fc..cf02f86 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Hand.glb and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Hand.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Health_Pickup.glb b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Health_Pickup.glb index d02828b..4643320 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Health_Pickup.glb and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Health_Pickup.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Humanoid_cactus.glb b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Humanoid_cactus.glb index 1e758be..3d5736b 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Humanoid_cactus.glb and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Humanoid_cactus.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/MagicTeapot.glb b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/MagicTeapot.glb index b65a4a3..7a7020b 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/MagicTeapot.glb and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/MagicTeapot.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Pillar.glb b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Pillar.glb index 5ef0918..891122c 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Pillar.glb and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Pillar.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Player 2.glb b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Player 2.glb index d5705b3..6eaccc6 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Player 2.glb and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Player 2.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Unused_in_level_test.glb b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Unused_in_level_test.glb index 4c007d0..b5937bb 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Unused_in_level_test.glb and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/models/library/Unused_in_level_test.glb differ diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/assets/nested.blend b/examples/bevy_gltf_blueprints/nested_blueprints/assets/nested.blend index c7a58ec..17d66dd 100644 Binary files a/examples/bevy_gltf_blueprints/nested_blueprints/assets/nested.blend and b/examples/bevy_gltf_blueprints/nested_blueprints/assets/nested.blend differ diff --git a/examples/bevy_gltf_components/basic/assets/basic.blend b/examples/bevy_gltf_components/basic/assets/basic.blend index 883d15d..fcdc6cd 100644 Binary files a/examples/bevy_gltf_components/basic/assets/basic.blend and b/examples/bevy_gltf_components/basic/assets/basic.blend differ diff --git a/examples/bevy_gltf_components/basic/assets/models/level1.glb b/examples/bevy_gltf_components/basic/assets/models/Level1.glb similarity index 67% rename from examples/bevy_gltf_components/basic/assets/models/level1.glb rename to examples/bevy_gltf_components/basic/assets/models/Level1.glb index abcf170..3779945 100644 Binary files a/examples/bevy_gltf_components/basic/assets/models/level1.glb and b/examples/bevy_gltf_components/basic/assets/models/Level1.glb differ diff --git a/examples/bevy_gltf_components/basic/src/main.rs b/examples/bevy_gltf_components/basic/src/main.rs index c296997..4795411 100644 --- a/examples/bevy_gltf_components/basic/src/main.rs +++ b/examples/bevy_gltf_components/basic/src/main.rs @@ -53,7 +53,7 @@ pub struct MyGltf(pub Handle); // MyGltf is also just for the same purpose, you do not need it in a real scenario // the states here are also for demo purposes only, fn setup(mut commands: Commands, asset_server: Res) { - commands.insert_resource(MyGltf(asset_server.load("models/level1.glb"))); + commands.insert_resource(MyGltf(asset_server.load("models/Level1.glb"))); } fn spawn_level( diff --git a/examples/bevy_gltf_components/basic_wasm/assets/basic.blend b/examples/bevy_gltf_components/basic_wasm/assets/basic.blend index 883d15d..593df09 100644 Binary files a/examples/bevy_gltf_components/basic_wasm/assets/basic.blend and b/examples/bevy_gltf_components/basic_wasm/assets/basic.blend differ diff --git a/examples/bevy_gltf_components/basic_wasm/assets/models/level1.glb b/examples/bevy_gltf_components/basic_wasm/assets/models/Level1.glb similarity index 67% rename from examples/bevy_gltf_components/basic_wasm/assets/models/level1.glb rename to examples/bevy_gltf_components/basic_wasm/assets/models/Level1.glb index abcf170..3779945 100644 Binary files a/examples/bevy_gltf_components/basic_wasm/assets/models/level1.glb and b/examples/bevy_gltf_components/basic_wasm/assets/models/Level1.glb differ diff --git a/examples/bevy_gltf_components/basic_wasm/src/main.rs b/examples/bevy_gltf_components/basic_wasm/src/main.rs index c296997..4795411 100644 --- a/examples/bevy_gltf_components/basic_wasm/src/main.rs +++ b/examples/bevy_gltf_components/basic_wasm/src/main.rs @@ -53,7 +53,7 @@ pub struct MyGltf(pub Handle); // MyGltf is also just for the same purpose, you do not need it in a real scenario // the states here are also for demo purposes only, fn setup(mut commands: Commands, asset_server: Res) { - commands.insert_resource(MyGltf(asset_server.load("models/level1.glb"))); + commands.insert_resource(MyGltf(asset_server.load("models/Level1.glb"))); } fn spawn_level( diff --git a/examples/bevy_gltf_save_load/basic/assets/basic.blend b/examples/bevy_gltf_save_load/basic/assets/basic.blend index 3538a2a..df63f50 100644 Binary files a/examples/bevy_gltf_save_load/basic/assets/basic.blend and b/examples/bevy_gltf_save_load/basic/assets/basic.blend differ diff --git a/examples/bevy_gltf_save_load/basic/assets/models/World.glb b/examples/bevy_gltf_save_load/basic/assets/models/World.glb index 6366b82..71b7e11 100644 Binary files a/examples/bevy_gltf_save_load/basic/assets/models/World.glb and b/examples/bevy_gltf_save_load/basic/assets/models/World.glb differ diff --git a/examples/bevy_gltf_save_load/basic/assets/models/World_dynamic.glb b/examples/bevy_gltf_save_load/basic/assets/models/World_dynamic.glb index fc51c4e..524308d 100644 Binary files a/examples/bevy_gltf_save_load/basic/assets/models/World_dynamic.glb and b/examples/bevy_gltf_save_load/basic/assets/models/World_dynamic.glb differ diff --git a/examples/bevy_gltf_save_load/basic/assets/models/library/Ground.glb b/examples/bevy_gltf_save_load/basic/assets/models/library/Ground.glb index 5f6247a..5561c51 100644 Binary files a/examples/bevy_gltf_save_load/basic/assets/models/library/Ground.glb and b/examples/bevy_gltf_save_load/basic/assets/models/library/Ground.glb differ diff --git a/examples/bevy_gltf_save_load/basic/assets/models/library/Health_Pickup.glb b/examples/bevy_gltf_save_load/basic/assets/models/library/Health_Pickup.glb index 01e9081..bd92ab9 100644 Binary files a/examples/bevy_gltf_save_load/basic/assets/models/library/Health_Pickup.glb and b/examples/bevy_gltf_save_load/basic/assets/models/library/Health_Pickup.glb differ diff --git a/examples/bevy_gltf_save_load/basic/assets/models/library/MagicTeapot.glb b/examples/bevy_gltf_save_load/basic/assets/models/library/MagicTeapot.glb index d572b13..6693b12 100644 Binary files a/examples/bevy_gltf_save_load/basic/assets/models/library/MagicTeapot.glb and b/examples/bevy_gltf_save_load/basic/assets/models/library/MagicTeapot.glb differ diff --git a/examples/bevy_gltf_save_load/basic/assets/models/library/Pillar.glb b/examples/bevy_gltf_save_load/basic/assets/models/library/Pillar.glb index 6ce36be..891122c 100644 Binary files a/examples/bevy_gltf_save_load/basic/assets/models/library/Pillar.glb and b/examples/bevy_gltf_save_load/basic/assets/models/library/Pillar.glb differ diff --git a/examples/bevy_gltf_save_load/basic/assets/models/library/Player.glb b/examples/bevy_gltf_save_load/basic/assets/models/library/Player.glb index b9f3149..8d2a7a8 100644 Binary files a/examples/bevy_gltf_save_load/basic/assets/models/library/Player.glb and b/examples/bevy_gltf_save_load/basic/assets/models/library/Player.glb differ diff --git a/examples/bevy_gltf_save_load/basic/assets/models/library/Sphero.glb b/examples/bevy_gltf_save_load/basic/assets/models/library/Sphero.glb index 9477a17..8a0046b 100644 Binary files a/examples/bevy_gltf_save_load/basic/assets/models/library/Sphero.glb and b/examples/bevy_gltf_save_load/basic/assets/models/library/Sphero.glb differ diff --git a/examples/bevy_gltf_save_load/basic/assets/models/library/Unused_in_level_test.glb b/examples/bevy_gltf_save_load/basic/assets/models/library/Unused_in_level_test.glb index 001340f..0cfda63 100644 Binary files a/examples/bevy_gltf_save_load/basic/assets/models/library/Unused_in_level_test.glb and b/examples/bevy_gltf_save_load/basic/assets/models/library/Unused_in_level_test.glb differ diff --git a/tools/gltf_auto_export/__init__.py b/tools/gltf_auto_export/__init__.py index a9eceeb..ace09ee 100644 --- a/tools/gltf_auto_export/__init__.py +++ b/tools/gltf_auto_export/__init__.py @@ -11,39 +11,26 @@ bl_info = { "category": "Import-Export" } import bpy -import os -from bpy.app.handlers import persistent -from bpy.props import (IntProperty) +from .auto_export.operators import AutoExportGLTF +from .auto_export.tracker import AutoExportTracker +from .auto_export.preferences import (AutoExportGltfAddonPreferences) - -from . import helpers -from .internals import (SceneLink, +from .auto_export.internals import (SceneLink, SceneLinks, CollectionToExport, CollectionsToExport, CUSTOM_PG_sceneName ) -from .auto_export import auto_export -from .preferences import (AutoExportGltfPreferenceNames, - AutoExportGltfAddonPreferences - ) from .ui.main import (GLTF_PT_auto_export_main, GLTF_PT_auto_export_root, GLTF_PT_auto_export_blueprints, GLTF_PT_auto_export_collections_list, GLTF_PT_auto_export_gltf, SCENE_UL_GLTF_auto_export, - AutoExportGLTF ) -from .ui.various import (SCENES_LIST_OT_actions) -from .helpers_scenes import (is_scene_ok) +from .ui.operators import (SCENES_LIST_OT_actions) -bpy.context.window_manager['changed_objects_per_scene'] = {} -bpy.context.window_manager['previous_params'] = {} -bpy.context.window_manager['__gltf_auto_export_initialized'] = False -bpy.context.window_manager['__gltf_auto_export_gltf_params_changed'] = False -bpy.context.window_manager['__gltf_auto_export_saving'] = False ###################################################### """ there are two places where we load settings for auto_export from: @@ -54,95 +41,6 @@ This is a workaround needed because of the way the settings are stored , perhaps #see here for original gltf exporter infos https://github.com/KhronosGroup/glTF-Blender-IO/blob/main/addons/io_scene_gltf2/__init__.py -@persistent -def deps_update_handler(scene, depsgraph): - if scene.name != "temp_scene": # actually do we care about anything else than the main scene(s) ? - #print("depsgraph_update_post", scene.name) - print("-------------") - changed = scene.name or "" - - # only deal with changes if we are no in the mids of saving/exporting - #if not bpy.context.window_manager['__gltf_auto_export_saving']: - - # depsgraph = bpy.context.evaluated_depsgraph_get() - if not 'changed_objects_per_scene' in bpy.context.window_manager: - bpy.context.window_manager['changed_objects_per_scene'] = {} - - if not changed in bpy.context.window_manager['changed_objects_per_scene']: - bpy.context.window_manager['changed_objects_per_scene'][changed] = {} - - for obj in depsgraph.updates: - if isinstance(obj.id, bpy.types.Object): - # get the actual object - object = bpy.data.objects[obj.id.name] - print("changed object", obj.id.name) - bpy.context.window_manager['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,) - material = bpy.data.materials[obj.id.name] - #now find which objects are using the material - for obj in bpy.data.objects: - for slot in obj.material_slots: - if slot.material == material: - bpy.context.window_manager['changed_objects_per_scene'][scene.name][obj.name] = obj - - bpy.context.window_manager.changedScene = changed - -@persistent -def save_handler(dummy): - print("-------------") - print("saved", bpy.data.filepath) - # mark saving as in progress, this is needed to ignore any changes from the depsgraph done during saving - # bpy.context.window_manager['__gltf_auto_export_saving'] = True - - if not 'changed_objects_per_scene' in bpy.context.window_manager: - bpy.context.window_manager['changed_objects_per_scene'] = {} - changes_per_scene = bpy.context.window_manager['changed_objects_per_scene'] - - if not 'previous_params' in bpy.context.window_manager: - bpy.context.window_manager['previous_params'] = {} - - #determine changed parameters - addon_prefs = bpy.context.preferences.addons["gltf_auto_export"].preferences - - prefs = {} - for (k,v) in addon_prefs.items(): - if k not in AutoExportGltfPreferenceNames: - prefs[k] = v - - previous_params = bpy.context.window_manager['previous_params'] if 'previous_params' in bpy.context.window_manager else {} - set1 = set(previous_params.items()) - set2 = set(prefs.items()) - difference = dict(set1 ^ set2) - - changed_param_names = list(set(difference.keys())- set(AutoExportGltfPreferenceNames)) - changed_parameters = len(changed_param_names) > 0 - # do the export - auto_export(changes_per_scene, changed_parameters) - - - # save the parameters - # todo add back - for (k, v) in prefs.items(): - bpy.context.window_manager['previous_params'][k] = v - - # reset a few things after exporting - # reset wether the gltf export paramters were changed since the last save - bpy.context.window_manager['__gltf_auto_export_gltf_params_changed'] = False - # reset whether there have been changed objects since the last save - bpy.context.window_manager['changed_objects_per_scene'] = {} - - # all our logic is done, mark this as done - #bpy.context.window_manager['__gltf_auto_export_saving'] = False - print("EXPORT DONE") - - -def get_changedScene(self): - return self["changedScene"] - -def set_changedScene(self, value): - self["changedScene"] = value - classes = [ SceneLink, SceneLinks, @@ -151,7 +49,7 @@ classes = [ SCENES_LIST_OT_actions, AutoExportGLTF, - AutoExportGltfAddonPreferences, + #AutoExportGltfAddonPreferences, CollectionToExport, CollectionsToExport, @@ -160,69 +58,44 @@ classes = [ GLTF_PT_auto_export_root, GLTF_PT_auto_export_blueprints, GLTF_PT_auto_export_collections_list, - GLTF_PT_auto_export_gltf + GLTF_PT_auto_export_gltf, + + AutoExportTracker ] def menu_func_import(self, context): self.layout.operator(AutoExportGLTF.bl_idname, text="glTF auto Export (.glb/gltf)") +from bpy.app.handlers import persistent + +@persistent +def post_update(scene, depsgraph): + bpy.context.window_manager.auto_export_tracker.deps_update_handler( scene, depsgraph) + +@persistent +def post_save(scene, depsgraph): + bpy.context.window_manager.auto_export_tracker.save_handler( scene, depsgraph) + def register(): + print("registering") for cls in classes: bpy.utils.register_class(cls) - - bpy.types.Scene.main_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="main scene", description="main_scene_chooser", poll=is_scene_ok) - bpy.types.Scene.library_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="library scene", description="library_scene_picker", poll=is_scene_ok) - - # setup handlers for updates & saving - bpy.app.handlers.depsgraph_update_post.append(deps_update_handler) - bpy.app.handlers.save_post.append(save_handler) - - - bpy.types.WindowManager.changedScene = bpy.props.StringProperty(get=get_changedScene, set=set_changedScene) - bpy.types.WindowManager.exportedCollections = bpy.props.CollectionProperty(type=CollectionsToExport) + # for some reason, adding these directly to the tracker class in register() do not work reliably + bpy.app.handlers.depsgraph_update_post.append(post_update) + bpy.app.handlers.save_post.append(post_save) # add our addon to the toolbar bpy.types.TOPBAR_MT_file_export.append(menu_func_import) - ## just experiments - bpy.types.Scene.main_scenes_list_index = IntProperty(name = "Index for main scenes list", default = 0) - bpy.types.Scene.library_scenes_list_index = IntProperty(name = "Index for library scenes list", default = 0) - - """ - mock_main_scenes = [] - main_scenes = bpy.context.preferences.addons["gltf_auto_export"].preferences.main_scenes - for item_name in mock_main_scenes: - item = main_scenes.add() - item.name = item_name - - mock_library_scenes = [] - library_scenes = bpy.context.preferences.addons["gltf_auto_export"].preferences.library_scenes - for item_name in mock_library_scenes: - item = library_scenes.add() - item.name = item_name""" - - bpy.context.preferences.addons["gltf_auto_export"].preferences.main_scenes_index = 0 - bpy.context.preferences.addons["gltf_auto_export"].preferences.library_scenes_index = 0 - def unregister(): for cls in classes: bpy.utils.unregister_class(cls) - bpy.types.TOPBAR_MT_file_export.remove(menu_func_import) - # remove handlers & co - bpy.app.handlers.depsgraph_update_post.remove(deps_update_handler) - bpy.app.handlers.save_post.remove(save_handler) - - del bpy.types.WindowManager.changedScene - del bpy.types.WindowManager.exportedCollections - - del bpy.types.Scene.main_scene - del bpy.types.Scene.library_scene - - del bpy.types.Scene.main_scenes_list_index - del bpy.types.Scene.library_scenes_list_index + bpy.app.handlers.depsgraph_update_post.remove(post_update) + bpy.app.handlers.save_post.remove(post_save) if "gltf_auto_export" == "__main__": + print("foo") register() \ No newline at end of file diff --git a/tools/gltf_auto_export/auto_export/__init__.py b/tools/gltf_auto_export/auto_export/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tools/gltf_auto_export/auto_export.py b/tools/gltf_auto_export/auto_export/auto_export.py similarity index 75% rename from tools/gltf_auto_export/auto_export.py rename to tools/gltf_auto_export/auto_export/auto_export.py index 5cb6450..dcef1cf 100644 --- a/tools/gltf_auto_export/auto_export.py +++ b/tools/gltf_auto_export/auto_export/auto_export.py @@ -2,52 +2,17 @@ import os import bpy import traceback -from .helpers_scenes import (get_scenes, ) -from .helpers_collections import (get_collections_in_library, get_exportable_collections, get_collections_per_scene, find_collection_ascendant_target_collection) -from .helpers_export import (export_main_scene, export_blueprints_from_collections) -from .helpers import (check_if_blueprints_exist, check_if_blueprint_on_disk) -from .materials import cleanup_materials, clear_material_info, clear_materials_scene, export_materials, generate_materials_scenes, get_all_materials -from .scene_components import upsert_scene_components +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 ..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) +from ..modules.export_materials import cleanup_materials, export_materials +from ..modules.bevy_scene_components import upsert_scene_components -from .config import scene_key """Main function""" -def auto_export(changes_per_scene, changed_export_parameters): - addon_prefs = bpy.context.preferences.addons["gltf_auto_export"].preferences - - # a semi_hack to ensure we have the latest version of the settings - initialized = bpy.context.window_manager['__gltf_auto_export_initialized'] if '__gltf_auto_export_initialized' in bpy.context.window_manager else False - if not initialized: - print("not initialized, fetching settings if any") - # semi_hack to restore the correct settings if the add_on was installed before - settings = bpy.context.scene.get(scene_key) - if settings: - print("loading settings in main function") - try: - # Update filter if user saved settings - #if hasattr(self, 'export_format'): - # self.filter_glob = '*.glb' if self.export_format == 'GLB' else '*.gltf' - for (k, v) in settings.items(): - setattr(addon_prefs, k, v) - # inject scenes data - if k == 'main_scene_names': - main_scenes = addon_prefs.main_scenes - for item_name in v: - item = main_scenes.add() - item.name = item_name - - if k == 'library_scene_names': - library_scenes = addon_prefs.library_scenes - for item_name in v: - item = library_scenes.add() - item.name = item_name - - - - except Exception as error: - print("error setting preferences from saved settings", error) - bpy.context.window_manager['__gltf_auto_export_initialized'] = True - +def auto_export(changes_per_scene, changed_export_parameters, addon_prefs): # have the export parameters (not auto export, just gltf export) have changed: if yes (for example switch from glb to gltf, compression or not, animations or not etc), we need to re-export everything print ("changed_export_parameters", changed_export_parameters) try: @@ -69,7 +34,7 @@ def auto_export(changes_per_scene, changed_export_parameters): if export_scene_settings: # inject/ update scene components - upsert_scene_components(bpy.context.scene, world = bpy.context.scene.world) + upsert_scene_components(bpy.context.scene, bpy.context.scene.world, main_scene_names) # export if export_blueprints: @@ -168,13 +133,12 @@ def auto_export(changes_per_scene, changed_export_parameters): # reset selections for obj in old_selections: obj.select_set(True) - if export_materials_library: cleanup_materials(collections, library_scenes) else: for scene_name in main_scene_names: - export_main_scene(bpy.data.scenes[scene_name], folder_path, addon_prefs) + export_main_scene(bpy.data.scenes[scene_name], folder_path, addon_prefs, []) except Exception as error: print(traceback.format_exc()) diff --git a/tools/gltf_auto_export/auto_export/export_blueprints.py b/tools/gltf_auto_export/auto_export/export_blueprints.py new file mode 100644 index 0000000..1ad7ba2 --- /dev/null +++ b/tools/gltf_auto_export/auto_export/export_blueprints.py @@ -0,0 +1,82 @@ +import os +import bpy + +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 + +# export collections: all the collections that have an instance in the main scene AND any marked collections, even if they do not have instances +def export_collections(collections, folder_path, library_scene, addon_prefs, gltf_export_preferences, blueprint_hierarchy, library_collections): + + # save current active collection + active_collection = bpy.context.view_layer.active_layer_collection + export_materials_library = getattr(addon_prefs,"export_materials_library") + + for collection_name in collections: + print("exporting collection", collection_name) + gltf_output_path = os.path.join(folder_path, collection_name) + export_settings = { **gltf_export_preferences, 'use_active_scene': True, 'use_active_collection': True, 'use_active_collection_with_nested':True} + + # if we are using the material library option, do not export materials, use placeholder instead + if export_materials_library: + export_settings['export_materials'] = 'PLACEHOLDER' + + collection = bpy.data.collections[collection_name] + collection_instances_combine_mode = getattr(addon_prefs, "collection_instances_combine_mode") + generate_and_export( + addon_prefs, + 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, collection_instances_combine_mode= collection_instances_combine_mode), + tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=collection, temp_scene=temp_scene, **params) + ) + # reset active collection to the one we save before + bpy.context.view_layer.active_layer_collection = active_collection + + +def export_blueprints_from_collections(collections, library_scene, folder_path, addon_prefs, blueprint_hierarchy, library_collections): + export_output_folder = getattr(addon_prefs,"export_output_folder") + gltf_export_preferences = generate_gltf_export_preferences(addon_prefs) + export_blueprints_path = os.path.join(folder_path, export_output_folder, getattr(addon_prefs,"export_blueprints_path")) if getattr(addon_prefs,"export_blueprints_path") != '' else folder_path + + try: + export_collections(collections, export_blueprints_path, library_scene, addon_prefs, gltf_export_preferences, blueprint_hierarchy, library_collections) + except Exception as error: + print("failed to export collections to gltf: ", error) + raise error + +# TODO : add a flag to also search of deeply nested components +def get_nested_components(object): + if object.instance_type == 'COLLECTION': + collection_name = object.instance_collection.name + collection = bpy.data.collections[collection_name] + all_objects = collection.all_objects + result = [] + for object in all_objects: + components = dict(object) + if len(components.keys()) > 0: + result += [(object, components)] + return result + return [] + #for collection in traverse_tree(collection): + # for object in collection.all_objects + + +def check_if_blueprints_exist(collections, folder_path, extension): + not_found_blueprints = [] + for collection_name in collections: + gltf_output_path = os.path.join(folder_path, collection_name + extension) + # print("gltf_output_path", gltf_output_path) + found = os.path.exists(gltf_output_path) and os.path.isfile(gltf_output_path) + if not found: + not_found_blueprints.append(collection_name) + return not_found_blueprints + + +def check_if_blueprint_on_disk(scene_name, folder_path, extension): + gltf_output_path = os.path.join(folder_path, scene_name + extension) + found = os.path.exists(gltf_output_path) and os.path.isfile(gltf_output_path) + print("level", scene_name, "found", found, "path", gltf_output_path) + return found + diff --git a/tools/gltf_auto_export/auto_export/export_gltf.py b/tools/gltf_auto_export/auto_export/export_gltf.py new file mode 100644 index 0000000..bc76f28 --- /dev/null +++ b/tools/gltf_auto_export/auto_export/export_gltf.py @@ -0,0 +1,52 @@ +import os +import bpy +from .preferences import (AutoExportGltfPreferenceNames) + +def generate_gltf_export_preferences(addon_prefs): + # default values + gltf_export_preferences = dict( + export_format= 'GLB', #'GLB', 'GLTF_SEPARATE', 'GLTF_EMBEDDED' + check_existing=False, + + use_selection=False, + use_visible=True, # Export visible and hidden objects. See Object/Batch Export to skip. + use_renderable=False, + use_active_collection= False, + use_active_collection_with_nested=False, + use_active_scene = False, + + export_texcoords=True, + export_normals=True, + # here add draco settings + export_draco_mesh_compression_enable = False, + + export_tangents=False, + #export_materials + export_colors=True, + export_attributes=True, + #use_mesh_edges + #use_mesh_vertices + export_cameras=True, + export_extras=True, # For custom exported properties. + export_lights=True, + export_yup=True, + export_skins=True, + export_morph=False, + export_apply=False, + export_animations=False + ) + + for key in addon_prefs.__annotations__.keys(): + if str(key) not in AutoExportGltfPreferenceNames: + #print("overriding setting", key, "value", getattr(addon_prefs,key)) + gltf_export_preferences[key] = getattr(addon_prefs,key) + + return gltf_export_preferences + + +#https://docs.blender.org/api/current/bpy.ops.export_scene.html#bpy.ops.export_scene.gltf +def export_gltf (path, export_settings): + settings = {**export_settings, "filepath": path} + # print("export settings",settings) + os.makedirs(os.path.dirname(path), exist_ok=True) + bpy.ops.export_scene.gltf(**settings) diff --git a/tools/gltf_auto_export/auto_export/export_main_scenes.py b/tools/gltf_auto_export/auto_export/export_main_scenes.py new file mode 100644 index 0000000..78a8271 --- /dev/null +++ b/tools/gltf_auto_export/auto_export/export_main_scenes.py @@ -0,0 +1,72 @@ +import os +import bpy + +from ..helpers.generate_and_export import generate_and_export +from .export_gltf import (generate_gltf_export_preferences, export_gltf) +from ..modules.bevy_dynamic import is_object_dynamic, is_object_static +from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into + + +# export all main scenes +def export_main_scenes(scenes, folder_path, addon_prefs): + for scene in scenes: + export_main_scene(scene, folder_path, addon_prefs) + +def export_main_scene(scene, folder_path, addon_prefs, library_collections): + gltf_export_preferences = generate_gltf_export_preferences(addon_prefs) + export_output_folder = getattr(addon_prefs,"export_output_folder") + export_blueprints = getattr(addon_prefs,"export_blueprints") + export_separate_dynamic_and_static_objects = getattr(addon_prefs, "export_separate_dynamic_and_static_objects") + collection_instances_combine_mode = getattr(addon_prefs, "collection_instances_combine_mode") + + gltf_output_path = os.path.join(folder_path, export_output_folder, scene.name) + export_settings = { **gltf_export_preferences, + 'use_active_scene': True, + 'use_active_collection':True, + 'use_active_collection_with_nested':True, + 'use_visible': False, + 'use_renderable': False, + 'export_apply':True + } + + if export_blueprints : + if export_separate_dynamic_and_static_objects: + #print("SPLIT STATIC AND DYNAMIC") + # first export static objects + generate_and_export( + addon_prefs, + 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, collection_instances_combine_mode= collection_instances_combine_mode, filter=is_object_static), + tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=scene.collection, temp_scene=temp_scene, **params) + ) + + # then export all dynamic objects + gltf_output_path = os.path.join(folder_path, export_output_folder, scene.name+ "_dynamic") + generate_and_export( + addon_prefs, + 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, collection_instances_combine_mode= collection_instances_combine_mode, filter=is_object_dynamic), + tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=scene.collection, temp_scene=temp_scene, **params) + ) + + else: + #print("NO SPLIT") + generate_and_export( + addon_prefs, + 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, collection_instances_combine_mode= collection_instances_combine_mode), + tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=scene.collection, temp_scene=temp_scene, **params) + ) + + else: + print(" exporting gltf to", gltf_output_path, ".gltf/glb") + export_gltf(gltf_output_path, export_settings) + + + diff --git a/tools/gltf_auto_export/internals.py b/tools/gltf_auto_export/auto_export/internals.py similarity index 100% rename from tools/gltf_auto_export/internals.py rename to tools/gltf_auto_export/auto_export/internals.py diff --git a/tools/gltf_auto_export/auto_export/operators.py b/tools/gltf_auto_export/auto_export/operators.py new file mode 100644 index 0000000..bed7d28 --- /dev/null +++ b/tools/gltf_auto_export/auto_export/operators.py @@ -0,0 +1,208 @@ +import json +import bpy +from bpy.types import Operator +from bpy_extras.io_utils import ExportHelper +from bpy.props import (IntProperty, StringProperty) +from .preferences import (AutoExportGltfAddonPreferences, AutoExportGltfPreferenceNames) +from ..helpers.helpers_scenes import (get_scenes) +from ..helpers.helpers_collections import (get_exportable_collections) +from .auto_export import auto_export + +class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper): + """test""" + bl_idname = "export_scenes.auto_gltf" + bl_label = "Apply settings" + bl_options = {'PRESET', 'UNDO'} + # ExportHelper mixin class uses this + filename_ext = '' + + #list of settings (other than purely gltf settings) whose change should trigger a re-generation of gltf files + white_list = ['auto_export', + 'export_main_scene_name', + 'export_output_folder', + 'export_library_scene_name', + + 'export_blueprints', + 'export_blueprints_path', + + 'export_marked_assets', + 'collection_instances_combine_mode', + 'export_separate_dynamic_and_static_objects', + + 'export_materials_library', + 'export_materials_path', + + 'export_scene_settings'] + + @classmethod + def register(cls): + bpy.types.WindowManager.main_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="main scene", description="main_scene_picker", poll=cls.is_scene_ok) + bpy.types.WindowManager.library_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="library scene", description="library_scene_picker", poll=cls.is_scene_ok) + + bpy.types.WindowManager.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 + + @classmethod + def unregister(cls): + del bpy.types.WindowManager.main_scene + del bpy.types.WindowManager.library_scene + + 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 + return scene.name not in operator.main_scenes and scene.name not in operator.library_scenes + except: + return True + + def save_settings(self, context): + # 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: + export_props[k] = v + # we add main & library scene names to our preferences + + export_props['main_scene_names'] = list(map(lambda scene_data: scene_data.name, getattr(self,"main_scenes"))) + export_props['library_scene_names'] = list(map(lambda scene_data: scene_data.name, getattr(self,"library_scenes"))) + self.properties['main_scene_names'] = export_props['main_scene_names'] + self.properties['library_scene_names'] = export_props['library_scene_names'] + + 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() + stored_settings.write(json.dumps(export_props)) + #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 (AttributeError, TypeError): + self.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings") + bpy.data.texts.remove(bpy.data.texts[".gltf_auto_export_settings"]) + + def did_export_settings_change(self): + previous_export_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else None + + # if there was no setting before, it is new, we need export + if previous_export_settings == None: + export_settings = {} + for (k, v) in self.properties.items(): + if k not in AutoExportGltfPreferenceNames: + export_settings[k] = v + export_settings = str(export_settings) + # the actual gltf export settings, not those of auto export + stored_export_settings = bpy.data.texts.new(".gltf_auto_export_gltf_settings") + stored_export_settings.write(export_settings) + return True + else: + export_settings = {} + for (k, v) in self.properties.items(): + if k in self.white_list or k not in AutoExportGltfPreferenceNames: + export_settings[k] = v + + if len(export_settings.keys()) == 0: # first time after we already used the addon, since we already have export settings, but they have not yet been applied + return False + + export_settings = str(export_settings) + changed = export_settings != previous_export_settings.as_string() + + previous_export_settings.clear() + previous_export_settings.write(export_settings) + return changed + + def execute(self, context): + # 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) + if self.will_save_settings: + self.save_settings(context) + + changes_per_scene = context.window_manager.auto_export_tracker.changed_objects_per_scene + #determine changed parameters + params_changed = self.did_export_settings_change() + #& do the export + if self.direct_mode: #Do not auto export when applying settings in the menu, do it on save only + auto_export(changes_per_scene, params_changed, self) + # cleanup + bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1) + return {'FINISHED'} + + def invoke(self, context, event): + 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) + (collections, _) = get_exportable_collections(level_scenes, library_scenes, addon_prefs) + + try: + # we save this list of collections in the context + bpy.context.window_manager.exportedCollections.clear() + #TODO: add error handling for this + for collection_name in collections: + 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") + + wm = context.window_manager + wm.fileselect_add(self) + + return {'RUNNING_MODAL'} + + def draw(self, context): + pass + + def cancel(self, context): + bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1) diff --git a/tools/gltf_auto_export/preferences.py b/tools/gltf_auto_export/auto_export/preferences.py similarity index 94% rename from tools/gltf_auto_export/preferences.py rename to tools/gltf_auto_export/auto_export/preferences.py index b86e5d4..1b566f2 100644 --- a/tools/gltf_auto_export/preferences.py +++ b/tools/gltf_auto_export/auto_export/preferences.py @@ -31,7 +31,14 @@ AutoExportGltfPreferenceNames = [ 'main_scenes', 'library_scenes', 'main_scenes_index', - 'library_scenes_index' + 'library_scenes_index', + + 'direct_mode',# specific to main auto_export operator + 'main_scene_names', + 'library_scene_names', + 'previous_export_settings', + 'filter_glob', + 'will_save_settings' ] class AutoExportGltfAddonPreferences(AddonPreferences): @@ -40,6 +47,24 @@ class AutoExportGltfAddonPreferences(AddonPreferences): bl_idname = __package__ bl_options = {'PRESET'} + #### these are for the operator + filter_glob: StringProperty( + default='*.glb;*.gltf', + options={'HIDDEN'} + ) + + will_save_settings: BoolProperty( + name='Remember Export Settings', + description='Store glTF export settings in the Blender project', + default=True + ) + + # use when operator is called directly, works a bit differently than inside the ui + direct_mode: BoolProperty( + default=False + ) + + #### auto_export: BoolProperty( name='Auto export', description='Automatically export to gltf on save', @@ -120,7 +145,7 @@ class AutoExportGltfAddonPreferences(AddonPreferences): 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=True + default=False ) diff --git a/tools/gltf_auto_export/auto_export/tracker.py b/tools/gltf_auto_export/auto_export/tracker.py new file mode 100644 index 0000000..f281106 --- /dev/null +++ b/tools/gltf_auto_export/auto_export/tracker.py @@ -0,0 +1,94 @@ +import bpy +from bpy.types import (PropertyGroup) +from bpy.props import (PointerProperty) + +from .internals import CollectionsToExport + +class AutoExportTracker(PropertyGroup): + + changed_objects_per_scene = {} + change_detection_enabled = True + export_params_changed = False + + @classmethod + def register(cls): + bpy.types.WindowManager.auto_export_tracker = PointerProperty(type=AutoExportTracker) + # register list of exportable collections + bpy.types.WindowManager.exportedCollections = bpy.props.CollectionProperty(type=CollectionsToExport) + + # setup handlers for updates & saving + #bpy.app.handlers.save_post.append(cls.save_handler) + #bpy.app.handlers.depsgraph_update_post.append(cls.deps_update_handler) + + @classmethod + def unregister(cls): + # remove handlers & co + """try: + bpy.app.handlers.depsgraph_update_post.remove(cls.deps_update_handler) + except:pass + try: + bpy.app.handlers.save_post.remove(cls.save_handler) + except:pass""" + del bpy.types.WindowManager.auto_export_tracker + del bpy.types.WindowManager.exportedCollections + + @classmethod + def save_handler(cls, scene, depsgraph): + print("-------------") + print("saved", bpy.data.filepath) + # auto_export(changes_per_scene, export_parameters_changed) + bpy.ops.export_scenes.auto_gltf(direct_mode= True) + + # (re)set a few things after exporting + # reset wether the gltf export paramters were changed since the last save + cls.export_params_changed = False + # reset whether there have been changed objects since the last save + cls.changed_objects_per_scene.clear() + # all our logic is done, mark this as done + print("EXPORT DONE") + + @classmethod + def deps_update_handler(cls, scene, depsgraph): + # print("change detection enabled", cls.change_detection_enabled) + if scene.name != "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] = {} + + # depsgraph = bpy.context.evaluated_depsgraph_get() + for obj in depsgraph.updates: + if isinstance(obj.id, bpy.types.Object): + # get the actual object + object = bpy.data.objects[obj.id.name] + # print("changed object", obj.id.name) + 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,) + material = bpy.data.materials[obj.id.name] + #now find which objects are using the material + for obj in bpy.data.objects: + for slot in obj.material_slots: + if slot.material == material: + cls.changed_objects_per_scene[scene.name][obj.name] = obj + + items = 0 + for scene_name in cls.changed_objects_per_scene: + 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) + else: + cls.changed_objects_per_scene.clear() + + def disable_change_detection(self,): + self.change_detection_enabled = False + self.__class__.change_detection_enabled = False + def enable_change_detection(self): + self.change_detection_enabled = True + self.__class__.change_detection_enabled = True + diff --git a/tools/gltf_auto_export/blueprints.py b/tools/gltf_auto_export/blueprints.py deleted file mode 100644 index 48524c0..0000000 --- a/tools/gltf_auto_export/blueprints.py +++ /dev/null @@ -1,175 +0,0 @@ -import bpy -from .helpers_collections import (find_layer_collection_recursive) -from .helpers import (make_empty3, traverse_tree) - - -def generate_blueprint_hollow_scene(blueprint_collection, library_collections, addon_prefs): - collection_instances_combine_mode = getattr(addon_prefs, "collection_instances_combine_mode") - - temp_scene = bpy.data.scenes.new(name="temp_scene_"+blueprint_collection.name) - temp_scene_root_collection = temp_scene.collection - - # we set our active scene to be this one : this is needed otherwise the stand-in empties get generated in the wrong scene - bpy.context.window.scene = temp_scene - found = find_layer_collection_recursive(temp_scene_root_collection, bpy.context.view_layer.layer_collection) - if found: - # once it's found, set the active layer collection to the one we found - bpy.context.view_layer.active_layer_collection = found - - original_names = [] - temporary_collections = [] - root_objects = [] - special_properties= { # to be able to reset any special property afterwards - "combine": [], - } - - # TODO also add the handling for "template" flags, so that instead of creating empties we link the data from the sub collection INTO the parent collection - # copies the contents of a collection into another one while replacing blueprint instances with empties - # if we have combine_mode set to "Inject", we take all the custom attributed of the nested (1 level only ! unless we use 'deepMerge') custom attributes and copy them to this level - def copy_hollowed_collection_into(source_collection, destination_collection, parent_empty=None): - for object in source_collection.objects: - combine_mode = object['_combine'] if '_combine' in object else collection_instances_combine_mode - - if object.instance_type == 'COLLECTION' and (combine_mode == 'Split' or (combine_mode == 'EmbedExternal' and (object.instance_collection.name in library_collections)) ): - - # get the name of the collection this is an instance of - collection_name = object.instance_collection.name - """ - blueprint_template = object['Template'] if 'Template' in object else False - if blueprint_template and parent_empty is None: # ONLY WORKS AT ROOT LEVEL - print("BLUEPRINT TEMPLATE", blueprint_template, destination_collection, parent_empty) - for object in source_collection.objects: - if object.type == 'EMPTY' and object.name.endswith("components"): - original_collection = bpy.data.collections[collection_name] - components_holder = object - print("WE CAN INJECT into", object, "data from", original_collection) - - # now we look for components inside the collection - components = {} - for object in original_collection.objects: - if object.type == 'EMPTY' and object.name.endswith("components"): - for component_name in object.keys(): - if component_name not in '_RNA_UI': - print( component_name , "-" , object[component_name] ) - components[component_name] = object[component_name] - - # copy template components into target object - for key in components: - print("copying ", key,"to", components_holder) - if not key in components_holder: - components_holder[key] = components[key] - """ - - original_name = object.name - original_names.append(original_name) - - object.name = original_name + "____bak" - empty_obj = make_empty3(original_name, object.location, object.rotation_euler, object.scale, destination_collection) - """we inject the collection/blueprint name, as a component called 'BlueprintName', but we only do this in the empty, not the original object""" - empty_obj['BlueprintName'] = '"'+collection_name+'"' - empty_obj['SpawnHere'] = '' - - - for k, v in object.items(): - if k != 'template' or k != '_combine': # do not copy these properties - empty_obj[k] = v - - if parent_empty is not None: - empty_obj.parent = parent_empty - else: - # we backup special properties that we do not want to export, and remove them - if '_combine' in object: - special_properties["combine"].append((object, object['_combine'])) - del object['_combine'] - - if parent_empty is not None: - object.parent = parent_empty - destination_collection.objects.link(object) - else: - root_objects.append(object) - destination_collection.objects.link(object) - - # for every sub-collection of the source, copy its content into a new sub-collection of the destination - for collection in source_collection.children: - original_name = collection.name - collection.name = original_name + "____bak" - collection_placeholder = make_empty3(original_name, [0,0,0], [0,0,0], [1,1,1], destination_collection) - - if parent_empty is not None: - collection_placeholder.parent = parent_empty - - copy_hollowed_collection_into(collection, destination_collection, collection_placeholder) - - """ - copy_collection = bpy.data.collections.new(collection.name + "____collection_export") - # save the newly created collection for later reuse - temporary_collections.append(copy_collection) - - # copy & link objects - copy_hollowed_collection_into(collection, copy_collection) - destination_collection.children.link(copy_collection)""" - - copy_hollowed_collection_into(blueprint_collection, temp_scene_root_collection) - - return (temp_scene, temporary_collections, root_objects, special_properties) - - - - -# clear & remove "hollow scene" -def clear_blueprint_hollow_scene(temp_scene, original_collection, temporary_collections, root_objects, special_properties): - - def restore_original_names(collection): - if collection.name.endswith("____bak"): - collection.name = collection.name.replace("____bak", "") - for object in collection.objects: - if object.instance_type == 'COLLECTION': - if object.name.endswith("____bak"): - object.name = object.name.replace("____bak", "") - for child_collection in collection.children: - restore_original_names(child_collection) - - restore_original_names(original_collection) - - # remove empties (only needed when we go via ops ????) - temp_root_collection = temp_scene.collection - temp_scene_objects = [o for o in temp_root_collection.objects] - for object in temp_scene_objects: - if object.type == 'EMPTY': - if hasattr(object, "SpawnHere"): - bpy.data.objects.remove(object, do_unlink=True) - else: - bpy.context.scene.collection.objects.unlink(object) - if object in root_objects: - pass - else: - bpy.data.objects.remove(object, do_unlink=True) - else: - bpy.context.scene.collection.objects.unlink(object) - - # put back special properties - for (object, value) in special_properties["combine"]: - object['_combine'] = value - - # remove temporary collections - for collection in temporary_collections: - bpy.data.collections.remove(collection) - - bpy.data.scenes.remove(temp_scene) - - -# TODO : add a flag to also search of deeply nested components -def get_nested_components(object): - if object.instance_type == 'COLLECTION': - collection_name = object.instance_collection.name - collection = bpy.data.collections[collection_name] - all_objects = collection.all_objects - result = [] - for object in all_objects: - components = dict(object) - if len(components.keys()) > 0: - result += [(object, components)] - return result - return [] - #for collection in traverse_tree(collection): - # for object in collection.all_objects diff --git a/tools/gltf_auto_export/config.py b/tools/gltf_auto_export/config.py deleted file mode 100644 index 05e4911..0000000 --- a/tools/gltf_auto_export/config.py +++ /dev/null @@ -1 +0,0 @@ -scene_key = "auto_gltfExportSettings" diff --git a/tools/gltf_auto_export/helpers.py b/tools/gltf_auto_export/helpers.py deleted file mode 100644 index 2cfa659..0000000 --- a/tools/gltf_auto_export/helpers.py +++ /dev/null @@ -1,63 +0,0 @@ -import os -import bpy - -##################################################### -#### Helpers #### - - - -# Makes an empty, at location, stores it in existing collection, from https://blender.stackexchange.com/questions/51290/how-to-add-empty-object-not-using-bpy-ops -def make_empty(name, location, coll_name): #string, vector, string of existing coll - empty_obj = bpy.data.objects.new( "empty", None, ) - empty_obj.name = name - empty_obj.empty_display_size = 1 - bpy.data.collections[coll_name].objects.link(empty_obj) - empty_obj.location = location - return empty_obj - - -def make_empty2(name, location, collection): - object_data = None #bpy.data.meshes.new("NewMesh") #None - empty_obj = bpy.data.objects.new( name, object_data ) - empty_obj.name = name - empty_obj.location = location - - - empty_obj.empty_display_size = 2 - empty_obj.empty_display_type = 'PLAIN_AXES' - collection.objects.link( empty_obj ) - return empty_obj - -def make_empty3(name, location, rotation, scale, collection): - original_active_object = bpy.context.active_object - bpy.ops.object.empty_add(type='PLAIN_AXES', location=location, rotation=rotation, scale=scale) - empty_obj = bpy.context.active_object - empty_obj.name = name - empty_obj.scale = scale # scale is not set correctly ????? - bpy.context.view_layer.objects.active = original_active_object - return empty_obj - -# traverse all collections -def traverse_tree(t): - yield t - for child in t.children: - yield from traverse_tree(child) - - -def check_if_blueprints_exist(collections, folder_path, extension): - not_found_blueprints = [] - for collection_name in collections: - gltf_output_path = os.path.join(folder_path, collection_name + extension) - # print("gltf_output_path", gltf_output_path) - found = os.path.exists(gltf_output_path) and os.path.isfile(gltf_output_path) - if not found: - not_found_blueprints.append(collection_name) - return not_found_blueprints - - -def check_if_blueprint_on_disk(scene_name, folder_path, extension): - gltf_output_path = os.path.join(folder_path, scene_name + extension) - found = os.path.exists(gltf_output_path) and os.path.isfile(gltf_output_path) - print("level", scene_name, "found", found, "path", gltf_output_path) - return found - diff --git a/tools/gltf_auto_export/helpers/__init__.py b/tools/gltf_auto_export/helpers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tools/gltf_auto_export/helpers/generate_and_export.py b/tools/gltf_auto_export/helpers/generate_and_export.py new file mode 100644 index 0000000..d99c610 --- /dev/null +++ b/tools/gltf_auto_export/helpers/generate_and_export.py @@ -0,0 +1,58 @@ +import bpy +from ..auto_export.export_gltf import export_gltf +from .helpers_collections import (set_active_collection) + +""" +generates a temporary scene, fills it with data, cleans up after itself + * named using temp_scene_name + * filled using the tempScene_filler + * written on disk to gltf_output_path, with the gltf export parameters in export_settings + * 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): + + temp_scene = bpy.data.scenes.new(name=temp_scene_name) + temp_root_collection = temp_scene.collection + + # save active scene + original_scene = bpy.context.window.scene + # and selected collection + original_collection = bpy.context.view_layer.active_layer_collection + # and mode + original_mode = bpy.context.active_object.mode if bpy.context.active_object != None else None + # we change the mode to object mode, otherwise the gltf exporter is not happy + if original_mode != None and original_mode != 'OBJECT': + print("setting to object mode", original_mode) + bpy.ops.object.mode_set(mode='OBJECT') + # we set our active scene to be this one : this is needed otherwise the stand-in empties get generated in the wrong scene + bpy.context.window.scene = temp_scene + + area = [area for area in bpy.context.screen.areas if area.type == "VIEW_3D"][0] + region = [region for region in area.regions if region.type == 'WINDOW'][0] + with bpy.context.temp_override(scene=temp_scene, area=area, region=region): + # detect scene mistmatch + scene_mismatch = bpy.context.scene.name != bpy.context.window.scene.name + if scene_mismatch: + raise Exception("Context scene mismatch, aborting", bpy.context.scene.name, bpy.context.window.scene.name) + + set_active_collection(bpy.context.scene, temp_root_collection.name) + # generate contents of temporary scene + scene_filler_data = tempScene_filler(temp_root_collection) + # export the temporary scene + try: + export_gltf(gltf_output_path, export_settings) + except Exception as error: + print("failed to export gltf !", error) + raise error + # restore everything + tempScene_cleaner(temp_scene, scene_filler_data) + + # reset active scene + bpy.context.window.scene = original_scene + # reset active collection + bpy.context.view_layer.active_layer_collection = original_collection + # reset mode + if original_mode != None: + bpy.ops.object.mode_set( mode = original_mode ) + diff --git a/tools/gltf_auto_export/helpers_collections.py b/tools/gltf_auto_export/helpers/helpers_collections.py similarity index 89% rename from tools/gltf_auto_export/helpers_collections.py rename to tools/gltf_auto_export/helpers/helpers_collections.py index 8280d71..edb3214 100644 --- a/tools/gltf_auto_export/helpers_collections.py +++ b/tools/gltf_auto_export/helpers/helpers_collections.py @@ -1,5 +1,4 @@ import bpy -from .helpers import traverse_tree # returns the list of the collections in use for a given scene def get_used_collections(scene): @@ -22,7 +21,6 @@ def get_used_collections(scene): # gets all collections that should ALWAYS be exported to their respective gltf files, even if they are not used in the main scene/level def get_marked_collections(scene, addon_prefs): export_marked_assets = getattr(addon_prefs,"export_marked_assets") - # print("checking library for marked collections") root_collection = scene.collection marked_collections = [] @@ -42,12 +40,10 @@ def get_sub_collections(collections, parent, children_per_collection): collection_names = set() used_collections = [] - for root_collection in collections: node = Node(name=root_collection.name, parent=parent) parent.children.append(node) - #print("root collection", root_collection.name) for collection in traverse_tree(root_collection): # TODO: filter out COLLECTIONS that have the flatten flag (unlike the flatten flag on colleciton instances themselves) node_name = collection.name @@ -164,6 +160,15 @@ def get_collection_hierarchy(root_col, levels=1): recurse(root_col, root_col.children, 0) return level_lookup + + +# traverse all collections +def traverse_tree(t): + yield t + for child in t.children: + yield from traverse_tree(child) + + # the active collection is a View Layer concept, so you actually have to find the active LayerCollection # which must be done recursively def find_layer_collection_recursive(find, col): @@ -195,3 +200,24 @@ def find_collection_ascendant_target_collection(collection_parents, target_colle return None return find_collection_ascendant_target_collection(collection_parents, target_collections, parent) +def set_active_collection(scene, collection_name): + layer_collection = bpy.data.scenes[scene.name].view_layers['ViewLayer'].layer_collection + layerColl = recurLayerCollection(layer_collection, collection_name) + # set active collection to the collection + bpy.context.view_layer.active_layer_collection = layerColl + +# find which of the library scenes the given collection stems from +# TODO: does not seem efficient at all ? +def get_source_scene(collection_name, library_scenes): + match = None + for scene in library_scenes: + root_collection = scene.collection + found = False + for cur_collection in traverse_tree(root_collection): + if cur_collection.name == collection_name: + found = True + break + if found: + match = scene + break + return match diff --git a/tools/gltf_auto_export/helpers/helpers_scenes.py b/tools/gltf_auto_export/helpers/helpers_scenes.py new file mode 100644 index 0000000..fb0ad70 --- /dev/null +++ b/tools/gltf_auto_export/helpers/helpers_scenes.py @@ -0,0 +1,126 @@ +import bpy +from .helpers_collections import (set_active_collection) +from .object_makers import (make_empty) + +# 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, collection_instances_combine_mode=None, library_collections=[]): + root_objects = [] + special_properties= { # to be able to reset any special property afterwards + "combine": [], + } + for object in source_collection.objects: + if filter is not None and filter(object) is False: + continue + #check if a specific collection instance does not have an ovveride for combine_mode + combine_mode = object['_combine'] if '_combine' in object else collection_instances_combine_mode + + if object.instance_type == 'COLLECTION' and (combine_mode == 'Split' or (combine_mode == 'EmbedExternal' and (object.instance_collection.name in library_collections)) ): + #print("creating empty for", object.name, object.instance_collection.name, library_collections, combine_mode) + collection_name = object.instance_collection.name + original_name = object.name + + object.name = original_name + "____bak" + empty_obj = make_empty(original_name, object.location, object.rotation_euler, object.scale, destination_collection) + """we inject the collection/blueprint name, as a component called 'BlueprintName', but we only do this in the empty, not the original object""" + empty_obj['BlueprintName'] = '"'+collection_name+'"' + empty_obj['SpawnHere'] = '' + + for k, v in object.items(): + if k != 'template' or k != '_combine': # do not copy these properties + empty_obj[k] = v + if parent_empty is not None: + empty_obj.parent = parent_empty + else: + # we backup special properties that we do not want to export, and remove them + if '_combine' in object: + special_properties["combine"].append((object, object['_combine'])) + del object['_combine'] + + if parent_empty is not None: + object.parent = parent_empty + destination_collection.objects.link(object) + else: + root_objects.append(object) + destination_collection.objects.link(object) + + # for every sub-collection of the source, copy its content into a new sub-collection of the destination + for collection in source_collection.children: + original_name = collection.name + collection.name = original_name + "____bak" + collection_placeholder = make_empty(original_name, [0,0,0], [0,0,0], [1,1,1], destination_collection) + + if parent_empty is not None: + collection_placeholder.parent = parent_empty + + nested_results = copy_hollowed_collection_into(collection, destination_collection, collection_placeholder, filter, collection_instances_combine_mode, library_collections) + sub_root_objects = nested_results["root_objects"] + sub_special_properties = nested_results["special_properties"] + + root_objects.extend(sub_root_objects) + for s in sub_special_properties.keys(): + if not s in special_properties.keys(): + special_properties[s] = [] + special_properties[s].extend(sub_special_properties[s]) + + return {"root_objects": root_objects, "special_properties": special_properties} + +# clear & remove "hollow scene" +def clear_hollow_scene(temp_scene, original_root_collection, root_objects, special_properties): + def restore_original_names(collection): + if collection.name.endswith("____bak"): + collection.name = collection.name.replace("____bak", "") + for object in collection.objects: + if object.instance_type == 'COLLECTION': + if object.name.endswith("____bak"): + object.name = object.name.replace("____bak", "") + for child_collection in collection.children: + restore_original_names(child_collection) + + # reset original names + restore_original_names(original_root_collection) + + # remove empties (only needed when we go via ops ????) + temp_root_collection = temp_scene.collection + temp_scene_objects = [o for o in temp_root_collection.objects] + for object in temp_scene_objects: + if object.type == 'EMPTY': + if hasattr(object, "SpawnHere"): + bpy.data.objects.remove(object, do_unlink=True) + else: + try: + temp_root_collection.objects.unlink(object) + except: + print("failed to unlink", object) + if object in root_objects: + pass + else: + bpy.data.objects.remove(object, do_unlink=True) + else: + temp_root_collection.objects.unlink(object) + + # remove temporary collections + """for collection in temporary_collections: + bpy.data.collections.remove(collection)""" + + # put back special properties + for (object, value) in special_properties["combine"]: + object['_combine'] = value + + # remove the temporary scene + bpy.data.scenes.remove(temp_scene) + + +# convenience utility to get lists of scenes +def get_scenes(addon_prefs): + 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"))) + + 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] + + diff --git a/tools/gltf_auto_export/helpers/object_makers.py b/tools/gltf_auto_export/helpers/object_makers.py new file mode 100644 index 0000000..50827b5 --- /dev/null +++ b/tools/gltf_auto_export/helpers/object_makers.py @@ -0,0 +1,47 @@ +import bmesh +import bpy +import mathutils + +# Makes an empty, at the specified location, rotation, scale stores it in existing collection, from https://blender.stackexchange.com/questions/51290/how-to-add-empty-object-not-using-bpy-ops +def make_empty(name, location, rotation, scale, collection): + object_data = None + empty_obj = bpy.data.objects.new( name, object_data ) + + empty_obj.empty_display_size = 2 + empty_obj.empty_display_type = 'PLAIN_AXES' + + empty_obj.name = name + empty_obj.location = location + empty_obj.scale = scale + empty_obj.rotation_euler = rotation + + collection.objects.link( empty_obj ) + #bpy.context.view_layer.update() + return empty_obj + +def make_cube(name, location=[0,0,0], rotation=[0,0,0], scale=[1,1,1], collection=None): + new_mesh = bpy.data.meshes.new(name+"_Mesh") #None + """verts = [( 1.0, 1.0, 0.0), + ( 1.0, -1.0, 0.0), + (-1.0, -1.0, 0.0), + (-1.0, 1.0, 0.0), + ] # 4 verts made with XYZ coords + edges = [] + faces = [[0, 1, 2, 3]] + new_mesh.from_pydata(verts, edges, faces)""" + + + bm = bmesh.new() + bmesh.ops.create_cube(bm, size=0.1, matrix=mathutils.Matrix.Translation(location)) # FIXME: other ways to set position seems to fail ? + bm.to_mesh(new_mesh) + bm.free() + + new_object = bpy.data.objects.new(name, new_mesh) + new_object.name = name + new_object.location = location + new_object.scale = scale + new_object.rotation_euler = rotation + + if collection != None: + collection.objects.link( new_object ) + return new_object \ No newline at end of file diff --git a/tools/gltf_auto_export/helpers/to_remove_later.py b/tools/gltf_auto_export/helpers/to_remove_later.py new file mode 100644 index 0000000..cdeba37 --- /dev/null +++ b/tools/gltf_auto_export/helpers/to_remove_later.py @@ -0,0 +1,222 @@ +bl_info = { + "name": "gltf_auto_export", + "author": "kaosigh", + "version": (0, 10, 0), + "blender": (3, 4, 0), + "location": "File > Import-Export", + "description": "glTF/glb auto-export", + "warning": "", + "wiki_url": "https://github.com/kaosat-dev/Blender_bevy_components_workflow", + "tracker_url": "https://github.com/kaosat-dev/Blender_bevy_components_workflow/issues/new", + "category": "Import-Export" +} + +import bpy +from bpy.props import (BoolProperty, + IntProperty, + StringProperty, + EnumProperty, + CollectionProperty + ) + + +# glTF extensions are named following a convention with known prefixes. +# See: https://github.com/KhronosGroup/glTF/tree/main/extensions#about-gltf-extensions +# also: https://github.com/KhronosGroup/glTF/blob/main/extensions/Prefixes.md +glTF_extension_name = "EXT_auto_export" + +# Support for an extension is "required" if a typical glTF viewer cannot be expected +# to load a given model without understanding the contents of the extension. +# For example, a compression scheme or new image format (with no fallback included) +# would be "required", but physics metadata or app-specific settings could be optional. +extension_is_required = False + +class ExampleExtensionProperties(bpy.types.PropertyGroup): + enabled: bpy.props.BoolProperty( + name=bl_info["name"], + description='Include this extension in the exported glTF file.', + default=True + ) + + auto_export_main_scene_name: StringProperty( + name='Main scene', + description='The name of the main scene/level/world to auto export', + default='Scene' + ) + auto_export_output_folder: StringProperty( + name='Export folder (relative)', + description='The root folder for all exports(relative to current file) Defaults to current folder', + default='' + ) + auto_export_library_scene_name: StringProperty( + name='Library scene', + description='The name of the library scene to auto export', + default='Library' + ) + # scene components + auto_export_scene_settings: BoolProperty( + name='Export scene settings', + description='Export scene settings ie AmbientLighting, Bloom, AO etc', + default=False + ) + + # blueprint settings + auto_export_blueprints: BoolProperty( + name='Export Blueprints', + description='Replaces collection instances with an Empty with a BlueprintName custom property', + default=True + ) + auto_export_blueprints_path: StringProperty( + name='Blueprints path', + description='path to export the blueprints to (relative to the Export folder)', + default='library' + ) + + auto_export_materials_library: BoolProperty( + name='Export materials library', + description='remove materials from blueprints and use the material library instead', + default=False + ) + auto_export_materials_path: StringProperty( + name='Materials path', + description='path to export the materials libraries to (relative to the root folder)', + default='materials' + ) + +def register(): + bpy.utils.register_class(ExampleExtensionProperties) + bpy.types.Scene.ExampleExtensionProperties = bpy.props.PointerProperty(type=ExampleExtensionProperties) + +def register_panel(): + # Register the panel on demand, we need to be sure to only register it once + # This is necessary because the panel is a child of the extensions panel, + # which may not be registered when we try to register this extension + try: + bpy.utils.register_class(GLTF_PT_UserExtensionPanel) + except Exception: + pass + + # If the glTF exporter is disabled, we need to unregister the extension panel + # Just return a function to the exporter so it can unregister the panel + return unregister_panel + + +def unregister_panel(): + # Since panel is registered on demand, it is possible it is not registered + try: + bpy.utils.unregister_class(GLTF_PT_UserExtensionPanel) + except Exception: + pass + + +def unregister(): + unregister_panel() + bpy.utils.unregister_class(ExampleExtensionProperties) + del bpy.types.Scene.ExampleExtensionProperties + +class GLTF_PT_UserExtensionPanel(bpy.types.Panel): + + bl_space_type = 'FILE_BROWSER' + bl_region_type = 'TOOL_PROPS' + bl_label = "Enabled" + bl_parent_id = "GLTF_PT_export_user_extensions" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + sfile = context.space_data + operator = sfile.active_operator + return operator.bl_idname == "EXPORT_SCENE_OT_gltf" + + def draw_header(self, context): + props = bpy.context.scene.ExampleExtensionProperties + self.layout.prop(props, 'enabled') + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + props = bpy.context.scene.ExampleExtensionProperties + layout.active = props.enabled + + props = bpy.context.scene.ExampleExtensionProperties + for bla in props.__annotations__: + layout.prop(props, bla) + + +class glTF2ExportUserExtension: + + def __init__(self): + # We need to wait until we create the gltf2UserExtension to import the gltf2 modules + # Otherwise, it may fail because the gltf2 may not be loaded yet + from io_scene_gltf2.io.com.gltf2_io_extensions import Extension + self.Extension = Extension + self.properties = bpy.context.scene.ExampleExtensionProperties + + def gather_node_hook(self, gltf2_object, blender_object, export_settings): + if self.properties.enabled: + if gltf2_object.extensions is None: + gltf2_object.extensions = {} + print("bla bla") + gltf2_object.extensions[glTF_extension_name] = self.Extension( + name=glTF_extension_name, + extension={"auto_export_blueprints": self.properties.auto_export_blueprints}, + required=extension_is_required + ) + + +def did_export_parameters_change(current_params, previous_params): + set1 = set(previous_params.items()) + set2 = set(current_params.items()) + difference = dict(set1 ^ set2) + + changed_param_names = list(set(difference.keys())- set(AutoExportGltfPreferenceNames)) + changed_parameters = len(changed_param_names) > 0 + return changed_parameters + +# original in export_blueprints => export_collections + # The part below is not necessary NORMALLY , but blender crashes in the "normal" case when using bpy.context.temp_override, + #if relevant we replace sub collections instances with placeholders too + # this is not needed if a collection/blueprint does not have sub blueprints or sub collections + collection_in_blueprint_hierarchy = collection_name in blueprint_hierarchy and len(blueprint_hierarchy[collection_name]) > 0 + collection_has_child_collections = len(bpy.data.collections[collection_name].children) > 0 + #if collection_in_blueprint_hierarchy or collection_has_child_collections: + + + + """else: + print("standard export") + # set active scene to be the library scene + original_scene = bpy.context.window.scene + bpy.context.window.scene = library_scene + with bpy.context.temp_override(scene=library_scene): + print("active scene", bpy.context.scene) + export_gltf(gltf_output_path, export_settings) + bpy.context.window.scene = original_scene""" + +""" + blueprint_template = object['Template'] if 'Template' in object else False + if blueprint_template and parent_empty is None: # ONLY WORKS AT ROOT LEVEL + print("BLUEPRINT TEMPLATE", blueprint_template, destination_collection, parent_empty) + for object in source_collection.objects: + if object.type == 'EMPTY' and object.name.endswith("components"): + original_collection = bpy.data.collections[collection_name] + components_holder = object + print("WE CAN INJECT into", object, "data from", original_collection) + + # now we look for components inside the collection + components = {} + for object in original_collection.objects: + if object.type == 'EMPTY' and object.name.endswith("components"): + for component_name in object.keys(): + if component_name not in '_RNA_UI': + print( component_name , "-" , object[component_name] ) + components[component_name] = object[component_name] + + # copy template components into target object + for key in components: + print("copying ", key,"to", components_holder) + if not key in components_holder: + components_holder[key] = components[key] + """ \ No newline at end of file diff --git a/tools/gltf_auto_export/helpers_export.py b/tools/gltf_auto_export/helpers_export.py deleted file mode 100644 index 9acfb7d..0000000 --- a/tools/gltf_auto_export/helpers_export.py +++ /dev/null @@ -1,196 +0,0 @@ -import os -import bpy - - -from .preferences import (AutoExportGltfPreferenceNames) -from .helpers_scenes import (generate_hollow_scene, clear_hollow_scene) -from .helpers_collections import (recurLayerCollection) -from .blueprints import clear_blueprint_hollow_scene, generate_blueprint_hollow_scene -from .helpers import (traverse_tree) -from .dynamic import (is_object_dynamic, is_object_static) - -###################################################### -#### Export logic ##### - - -def generate_gltf_export_preferences(addon_prefs): - # default values - gltf_export_preferences = dict( - export_format= 'GLB', #'GLB', 'GLTF_SEPARATE', 'GLTF_EMBEDDED' - check_existing=False, - - use_selection=False, - use_visible=True, # Export visible and hidden objects. See Object/Batch Export to skip. - use_renderable=False, - use_active_collection= False, - use_active_collection_with_nested=False, - use_active_scene = False, - - export_texcoords=True, - export_normals=True, - # here add draco settings - export_draco_mesh_compression_enable = False, - - export_tangents=False, - #export_materials - export_colors=True, - export_attributes=True, - #use_mesh_edges - #use_mesh_vertices - export_cameras=True, - export_extras=True, # For custom exported properties. - export_lights=True, - export_yup=True, - export_skins=True, - export_morph=False, - export_apply=False, - export_animations=False - ) - - for key in addon_prefs.__annotations__.keys(): - if str(key) not in AutoExportGltfPreferenceNames: - #print("overriding setting", key, "value", getattr(addon_prefs,key)) - gltf_export_preferences[key] = getattr(addon_prefs,key) - - return gltf_export_preferences - -# find which of the library scenes the given collection stems from -# TODO: does not seem efficient at all ? -def get_source_scene(collection_name, library_scenes): - match = None - for scene in library_scenes: - root_collection = scene.collection - found = False - for cur_collection in traverse_tree(root_collection): - if cur_collection.name == collection_name: - found = True - break - if found: - match = scene - break - return match - -# export collections: all the collections that have an instance in the main scene AND any marked collections, even if they do not have instances -def export_collections(collections, folder_path, library_scene, addon_prefs, gltf_export_preferences, blueprint_hierarchy, library_collections): - # set active scene to be the library scene (hack for now) - bpy.context.window.scene = library_scene - # save current active collection - active_collection = bpy.context.view_layer.active_layer_collection - export_materials_library = getattr(addon_prefs,"export_materials_library") - - for collection_name in collections: - print("exporting collection", collection_name) - layer_collection = bpy.context.view_layer.layer_collection - layerColl = recurLayerCollection(layer_collection, collection_name) - # set active collection to the collection - bpy.context.view_layer.active_layer_collection = layerColl - gltf_output_path = os.path.join(folder_path, collection_name) - - export_settings = { **gltf_export_preferences, 'use_active_scene': True, 'use_active_collection': True, 'use_active_collection_with_nested':True} - - # if we are using the material library option, do not export materials, use placeholder instead - if export_materials_library: - export_settings['export_materials'] = 'PLACEHOLDER' - - - #if relevant we replace sub collections instances with placeholders too - # this is not needed if a collection/blueprint does not have sub blueprints or sub collections - collection_in_blueprint_hierarchy = collection_name in blueprint_hierarchy and len(blueprint_hierarchy[collection_name]) > 0 - collection_has_child_collections = len(bpy.data.collections[collection_name].children) > 0 - if collection_in_blueprint_hierarchy or collection_has_child_collections: - #print("generate hollow scene for nested blueprints", library_collections) - backup = bpy.context.window.scene - collection = bpy.data.collections[collection_name] - (hollow_scene, temporary_collections, root_objects, special_properties) = generate_blueprint_hollow_scene(collection, library_collections, addon_prefs) - - export_gltf(gltf_output_path, export_settings) - - clear_blueprint_hollow_scene(hollow_scene, collection, temporary_collections, root_objects, special_properties) - bpy.context.window.scene = backup - else: - #print("standard export") - export_gltf(gltf_output_path, export_settings) - - - # reset active collection to the one we save before - bpy.context.view_layer.active_layer_collection = active_collection - - -def export_blueprints_from_collections(collections, library_scene, folder_path, addon_prefs, blueprint_hierarchy, library_collections): - export_output_folder = getattr(addon_prefs,"export_output_folder") - gltf_export_preferences = generate_gltf_export_preferences(addon_prefs) - export_blueprints_path = os.path.join(folder_path, export_output_folder, getattr(addon_prefs,"export_blueprints_path")) if getattr(addon_prefs,"export_blueprints_path") != '' else folder_path - - #print("-----EXPORTING BLUEPRINTS----") - #print("LIBRARY EXPORT", export_blueprints_path ) - - try: - export_collections(collections, export_blueprints_path, library_scene, addon_prefs, gltf_export_preferences, blueprint_hierarchy, library_collections) - except Exception as error: - print("failed to export collections to gltf: ", error) - # TODO : rethrow - - -# export all main scenes -def export_main_scenes(scenes, folder_path, addon_prefs): - for scene in scenes: - export_main_scene(scene, folder_path, addon_prefs) - -def export_main_scene(scene, folder_path, addon_prefs, library_collections): - gltf_export_preferences = generate_gltf_export_preferences(addon_prefs) - export_output_folder = getattr(addon_prefs,"export_output_folder") - export_blueprints = getattr(addon_prefs,"export_blueprints") - export_separate_dynamic_and_static_objects = getattr(addon_prefs, "export_separate_dynamic_and_static_objects") - - gltf_output_path = os.path.join(folder_path, export_output_folder, scene.name) - export_settings = { **gltf_export_preferences, - 'use_active_scene': True, - 'use_active_collection':True, - 'use_active_collection_with_nested':True, - 'use_visible': False, - 'use_renderable': False, - 'export_apply':True - } - - if export_blueprints : - if export_separate_dynamic_and_static_objects: - # first export all dynamic objects - (hollow_scene, temporary_collections, root_objects, special_properties) = generate_hollow_scene(scene, library_collections, addon_prefs, is_object_dynamic) - gltf_output_path = os.path.join(folder_path, export_output_folder, scene.name+ "_dynamic") - # set active scene to be the given scene - bpy.context.window.scene = hollow_scene - print(" exporting gltf to", gltf_output_path, ".gltf/glb") - export_gltf(gltf_output_path, export_settings) - clear_hollow_scene(hollow_scene, scene, temporary_collections, root_objects, special_properties) - - # now export static objects - (hollow_scene, temporary_collections, root_objects, special_properties) = generate_hollow_scene(scene, library_collections, addon_prefs, is_object_static) - gltf_output_path = os.path.join(folder_path, export_output_folder, scene.name) - # set active scene to be the given scene - bpy.context.window.scene = hollow_scene - print(" exporting gltf to", gltf_output_path, ".gltf/glb") - export_gltf(gltf_output_path, export_settings) - clear_hollow_scene(hollow_scene, scene, temporary_collections, root_objects, special_properties) - - else: - print("NO SPLIT") - # todo: add exception handling - (hollow_scene, temporary_collections, root_objects, special_properties) = generate_hollow_scene(scene, library_collections, addon_prefs) - # set active scene to be the given scene - bpy.context.window.scene = hollow_scene - print(" exporting gltf to", gltf_output_path, ".gltf/glb") - export_gltf(gltf_output_path, export_settings) - - clear_hollow_scene(hollow_scene, scene, temporary_collections, root_objects, special_properties) - else: - print(" exporting gltf to", gltf_output_path, ".gltf/glb") - export_gltf(gltf_output_path, export_settings) - - -#https://docs.blender.org/api/current/bpy.ops.export_scene.html#bpy.ops.export_scene.gltf -def export_gltf (path, export_settings): - settings = {**export_settings, "filepath": path} - os.makedirs(os.path.dirname(path), exist_ok=True) - bpy.ops.export_scene.gltf(**settings) - - diff --git a/tools/gltf_auto_export/helpers_scenes.py b/tools/gltf_auto_export/helpers_scenes.py deleted file mode 100644 index d0a8bbd..0000000 --- a/tools/gltf_auto_export/helpers_scenes.py +++ /dev/null @@ -1,146 +0,0 @@ -import bpy -from .helpers_collections import (find_layer_collection_recursive) -from .helpers import (make_empty3) - -# generate a copy of a scene that replaces collection instances with empties -# copy original names before creating a new scene, & reset them -def generate_hollow_scene(scene, library_collections, addon_prefs, filter=None): - collection_instances_combine_mode = getattr(addon_prefs, "collection_instances_combine_mode") - - root_collection = scene.collection - temp_scene = bpy.data.scenes.new(name="temp_scene") - copy_root_collection = temp_scene.collection - - # we set our active scene to be this one : this is needed otherwise the stand-in empties get generated in the wrong scene - bpy.context.window.scene = temp_scene - - found = find_layer_collection_recursive(copy_root_collection, bpy.context.view_layer.layer_collection) - if found: - # once it's found, set the active layer collection to the one we found - bpy.context.view_layer.active_layer_collection = found - - original_names = [] - temporary_collections = [] - root_objects = [] - special_properties= { # to be able to reset any special property afterwards - "combine": [], - } - - # 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): - for object in source_collection.objects: - if filter is not None and filter(object) is False: - continue - #check if a specific collection instance does not have an ovveride for combine_mode - combine_mode = object['_combine'] if '_combine' in object else collection_instances_combine_mode - - if object.instance_type == 'COLLECTION' and (combine_mode == 'Split' or (combine_mode == 'EmbedExternal' and (object.instance_collection.name in library_collections)) ): - #print("creating empty for", object.name, object.instance_collection.name, library_collections, combine_mode) - - collection_name = object.instance_collection.name - - original_name = object.name - original_names.append(original_name) - - object.name = original_name + "____bak" - empty_obj = make_empty3(original_name, object.location, object.rotation_euler, object.scale, destination_collection) - """we inject the collection/blueprint name, as a component called 'BlueprintName', but we only do this in the empty, not the original object""" - empty_obj['BlueprintName'] = '"'+collection_name+'"' - empty_obj['SpawnHere'] = '' - - for k, v in object.items(): - if k != 'template' or k != '_combine': # do not copy these properties - empty_obj[k] = v - if parent_empty is not None: - empty_obj.parent = parent_empty - else: - # we backup special properties that we do not want to export, and remove them - if '_combine' in object: - special_properties["combine"].append((object, object['_combine'])) - del object['_combine'] - - if parent_empty is not None: - object.parent = parent_empty - destination_collection.objects.link(object) - else: - root_objects.append(object) - destination_collection.objects.link(object) - - # for every sub-collection of the source, copy its content into a new sub-collection of the destination - for collection in source_collection.children: - original_name = collection.name - collection.name = original_name + "____bak" - collection_placeholder = make_empty3(original_name, [0,0,0], [0,0,0], [1,1,1], destination_collection) - - if parent_empty is not None: - collection_placeholder.parent = parent_empty - - copy_hollowed_collection_into(collection, destination_collection, collection_placeholder) - - copy_hollowed_collection_into(root_collection, copy_root_collection) - - return (temp_scene, temporary_collections, root_objects, special_properties) - -# clear & remove "hollow scene" -def clear_hollow_scene(temp_scene, original_scene, temporary_collections, root_objects, special_properties): - - def restore_original_names(collection): - if collection.name.endswith("____bak"): - collection.name = collection.name.replace("____bak", "") - for object in collection.objects: - if object.instance_type == 'COLLECTION': - if object.name.endswith("____bak"): - object.name = object.name.replace("____bak", "") - for child_collection in collection.children: - restore_original_names(child_collection) - - # reset original names - root_collection = original_scene.collection - restore_original_names(root_collection) - - # remove empties (only needed when we go via ops ????) - temp_root_collection = temp_scene.collection - temp_scene_objects = [o for o in temp_root_collection.objects] - for object in temp_scene_objects: - if object.type == 'EMPTY': - if hasattr(object, "SpawnHere"): - bpy.data.objects.remove(object, do_unlink=True) - else: - bpy.context.scene.collection.objects.unlink(object) - if object in root_objects: - pass - else: - bpy.data.objects.remove(object, do_unlink=True) - else: - bpy.context.scene.collection.objects.unlink(object) - - # remove temporary collections - for collection in temporary_collections: - bpy.data.collections.remove(collection) - - # put back special properties - for (object, value) in special_properties["combine"]: - object['_combine'] = value - - # remove the temporary scene - bpy.data.scenes.remove(temp_scene) - - -# convenience utility to get lists of scenes -def get_scenes(addon_prefs): - 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"))) - - 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 is_scene_ok(self, scene): - prefs = bpy.context.preferences.addons["gltf_auto_export"].preferences - return scene.name not in prefs.main_scenes and scene.name not in prefs.library_scenes - diff --git a/tools/gltf_auto_export/modules/__init__.py b/tools/gltf_auto_export/modules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tools/gltf_auto_export/dynamic.py b/tools/gltf_auto_export/modules/bevy_dynamic.py similarity index 83% rename from tools/gltf_auto_export/dynamic.py rename to tools/gltf_auto_export/modules/bevy_dynamic.py index 62addc1..aaa6622 100644 --- a/tools/gltf_auto_export/dynamic.py +++ b/tools/gltf_auto_export/modules/bevy_dynamic.py @@ -8,13 +8,12 @@ import bpy def is_object_dynamic(object): is_dynamic = object['Dynamic'] if 'Dynamic' in object else False # only look for data in the original collection if it is not alread marked as dynamic at instance level - if not is_dynamic and object.type == 'EMPTY' and hasattr(object, 'instance_collection'): - # get the name of the collection this is an instance of + if not is_dynamic and object.type == 'EMPTY' and hasattr(object, 'instance_collection') and object.instance_collection != None : + #print("collection", object.instance_collection, "object", object.name) + # get the name of the collection this is an instance of collection_name = object.instance_collection.name original_collection = bpy.data.collections[collection_name] - #print("inspecting insides", original_collection) - # scan original collection, look for a 'Dynamic' flag for object in original_collection.objects: #print(" inner", object) @@ -24,8 +23,6 @@ def is_object_dynamic(object): if component_name == 'Dynamic': is_dynamic = True break - print("is object dynamic", is_dynamic, object) - return is_dynamic def is_object_static(object): diff --git a/tools/gltf_auto_export/scene_components.py b/tools/gltf_auto_export/modules/bevy_scene_components.py similarity index 78% rename from tools/gltf_auto_export/scene_components.py rename to tools/gltf_auto_export/modules/bevy_scene_components.py index 6155ce9..0728bc3 100644 --- a/tools/gltf_auto_export/scene_components.py +++ b/tools/gltf_auto_export/modules/bevy_scene_components.py @@ -1,17 +1,20 @@ -import bpy -from .helpers import make_empty3 -# helpers to export scene level data -def upsert_scene_components(scene, world): - +from ..helpers.object_makers import make_empty + +def upsert_scene_components(scene, world, main_scene_names): + #should only be run in one of the main scenes + if scene.name not in main_scene_names: + return + root_collection = scene.collection lighting_components = None + print("upsert scene components", scene.name, scene.objects) for object in scene.objects: - if object.name == "lighting_components": + if object.name == "lighting_components_"+scene.name: lighting_components = object break if lighting_components is None: - lighting_components = make_empty3('lighting_components', [0,0,0], [0,0,0], [0,0,0], None) + lighting_components = make_empty('lighting_components_'+scene.name, [0,0,0], [0,0,0], [0,0,0], root_collection) if world is not None: lighting_components['AmbientLightSettings'] = ambient_color_to_component(world) @@ -41,14 +44,8 @@ def ambient_color_to_component(world): if color is not None and strength is not None: - #print("color", color[0], color[1], color[2], color[3]) - # print("strength", strength) - colorRgba = "Rgba(red: "+ str(color[0]) + ", green: "+ str(color[1]) + ", blue: " + str(color[2]) + ", alpha: "+ str(color[3]) + ")" # TODO: YIKES clean this up - #colorRgba = "Rgba(red: 0.0, green: 0.0, blue:0.0, alpha:0.0)" component = "( color:"+ str(colorRgba) +", brightness:"+str(strength)+")" - - print("component", component) return component return None diff --git a/tools/gltf_auto_export/materials.py b/tools/gltf_auto_export/modules/export_materials.py similarity index 63% rename from tools/gltf_auto_export/materials.py rename to tools/gltf_auto_export/modules/export_materials.py index d2e5c57..cdde179 100644 --- a/tools/gltf_auto_export/materials.py +++ b/tools/gltf_auto_export/modules/export_materials.py @@ -1,10 +1,13 @@ - -from .helpers_export import export_gltf, generate_gltf_export_preferences -from .helpers import traverse_tree -import bpy import os +import bpy from pathlib import Path +from ..helpers.generate_and_export import generate_and_export + +from ..helpers.helpers_collections import (set_active_collection, traverse_tree) +from ..auto_export.export_gltf import (export_gltf, generate_gltf_export_preferences) +from ..helpers.object_makers import make_cube + # get materials per object, and injects the materialInfo component def get_materials(object): material_slots = object.material_slots @@ -38,50 +41,53 @@ def get_all_materials(collection_names, library_scenes): root_collection = scene.collection for cur_collection in traverse_tree(root_collection): if cur_collection.name in collection_names: - #print("collection: ", cur_collection.name) for object in cur_collection.all_objects: - # print(" object:", object.name) used_material_names = used_material_names + get_materials(object) # we only want unique names used_material_names = list(set(used_material_names)) return used_material_names -def make_material_object(name, location, rotation, scale, material): - original_active_object = bpy.context.active_object - # bpy.ops.object.empty_add(type='PLAIN_AXES', location=location, rotation=rotation, scale=scale) - bpy.ops.mesh.primitive_cube_add(size=0.1, location=location) - object = bpy.context.active_object - object.name = name - #obj.scale = scale # scale is not set correctly ????? - if object.data.materials: - # assign to 1st material slot - object.data.materials[0] = material - else: - # no slots - object.data.materials.append(material) +# creates a new object with the applied material, for the material library +def make_material_object(name, location=[0,0,0], rotation=[0,0,0], scale=[1,1,1], material=None, collection=None): + #original_active_object = bpy.context.active_object + #bpy.ops.mesh.primitive_cube_add(size=0.1, location=location) + object = make_cube(name, location=location, rotation=rotation, scale=scale, collection=collection) + if material: + if object.data.materials: + # assign to 1st material slot + object.data.materials[0] = material + else: + # no slots + object.data.materials.append(material) - bpy.context.view_layer.objects.active = original_active_object + #bpy.context.view_layer.objects.active = original_active_object return object # generates a materials scene: -def generate_materials_scenes(used_material_names): - temp_scene = bpy.data.scenes.new(name="__materials_scene") - bpy.context.window.scene = temp_scene - +def generate_materials_scene_content(root_collection, used_material_names): for index, material_name in enumerate(used_material_names): material = bpy.data.materials[material_name] - make_material_object("Material_"+material_name, [index * 0.2,0,0], [], [], material) - - # we set our active scene to be this one : this is needed otherwise the stand-in objects get generated in the wrong scene - return temp_scene + make_material_object("Material_"+material_name, [index * 0.2,0,0], material=material, collection=root_collection) + return {} def clear_materials_scene(temp_scene): root_collection = temp_scene.collection scene_objects = [o for o in root_collection.objects] for object in scene_objects: - bpy.data.objects.remove(object, do_unlink=True) + #print("removing ", object) + try: + mesh = bpy.data.meshes[object.name+"_Mesh"] + bpy.data.meshes.remove(mesh, do_unlink=True) + except Exception as error: + pass + #print("could not remove mesh", error) + + try: + bpy.data.objects.remove(object, do_unlink=True) + except:pass + bpy.data.scenes.remove(temp_scene) # exports the materials used inside the current project: @@ -93,15 +99,6 @@ def export_materials(collections, library_scenes, folder_path, addon_prefs): used_material_names = get_all_materials(collections, library_scenes) current_project_name = Path(bpy.context.blend_data.filepath).stem - print("materials", used_material_names) - - # save the current active scene - current_scene = bpy.context.window.scene - mat_scene = generate_materials_scenes(used_material_names) - - - gltf_output_path = os.path.join(folder_path, export_materials_path, current_project_name + "_materials_library") - print(" exporting Materials to", gltf_output_path, ".gltf/glb") export_settings = { **gltf_export_preferences, 'use_active_scene': True, 'use_active_collection':True, @@ -110,13 +107,19 @@ def export_materials(collections, library_scenes, folder_path, addon_prefs): 'use_renderable': False, 'export_apply':True } - export_gltf(gltf_output_path, export_settings) + gltf_output_path = os.path.join(folder_path, export_materials_path, current_project_name + "_materials_library") - # remove materials scenes - clear_materials_scene(mat_scene) + print(" exporting Materials to", gltf_output_path, ".gltf/glb") + + generate_and_export( + addon_prefs, + temp_scene_name="__materials_scene", + export_settings=export_settings, + gltf_output_path=gltf_output_path, + tempScene_filler= lambda temp_collection: generate_materials_scene_content(temp_collection, used_material_names), + tempScene_cleaner= lambda temp_scene, params: clear_materials_scene(temp_scene=temp_scene) + ) - # reset scene to previously selected scene - bpy.context.window.scene = current_scene def cleanup_materials(collections, library_scenes): # remove temporary components diff --git a/tools/gltf_auto_export/ui/main.py b/tools/gltf_auto_export/ui/main.py index 78be74c..925d004 100644 --- a/tools/gltf_auto_export/ui/main.py +++ b/tools/gltf_auto_export/ui/main.py @@ -8,154 +8,14 @@ from bpy.props import (BoolProperty, CollectionProperty ) -from ..preferences import (AutoExportGltfAddonPreferences, AutoExportGltfPreferenceNames) -from ..helpers_scenes import (get_scenes) -from ..helpers_collections import (get_exportable_collections) +from ..auto_export import auto_export + +from ..auto_export.preferences import (AutoExportGltfAddonPreferences, AutoExportGltfPreferenceNames) +from ..helpers.helpers_scenes import (get_scenes) +from ..helpers.helpers_collections import (get_exportable_collections) ###################################################### ## ui logic & co -class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper): - """test""" - bl_idname = "export_scenes.auto_gltf" - bl_label = "Apply settings" - bl_options = {'PRESET', 'UNDO'} - - # ExportHelper mixin class uses this - filename_ext = '' - - filter_glob: StringProperty( - default='*.glb;*.gltf', - options={'HIDDEN'} - ) - - will_save_settings: BoolProperty( - name='Remember Export Settings', - description='Store glTF export settings in the Blender project', - default=True - ) - - # Custom scene property for saving settings - scene_key = "auto_gltfExportSettings" - - def save_settings(self, context): - # find all props to save - exceptional = [ - # options that don't start with 'export_' - 'main_scenes', - 'library_scenes', - '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 add main & library scene names to our preferences - main_scenes = list(map(lambda scene_data: scene_data, getattr(bpy.context.preferences.addons["gltf_auto_export"].preferences,"main_scenes"))) - library_scenes = list(map(lambda scene_data: scene_data, getattr(bpy.context.preferences.addons["gltf_auto_export"].preferences,"library_scenes"))) - - export_props['main_scene_names'] = list(map(lambda scene_data: scene_data.name, getattr(bpy.context.preferences.addons["gltf_auto_export"].preferences,"main_scenes"))) - export_props['library_scene_names'] = list(map(lambda scene_data: scene_data.name, getattr(bpy.context.preferences.addons["gltf_auto_export"].preferences,"library_scenes"))) - self.properties['main_scene_names'] = export_props['main_scene_names'] - self.properties['library_scene_names'] = export_props['library_scene_names'] - context.scene[self.scene_key] = export_props - - - def apply_settings_to_preferences(self, context): - # find all props to save - exceptional = [ - # options that don't start with 'export_' - 'main_scenes', - 'library_scenes', - '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 - } - addon_prefs = bpy.context.preferences.addons["gltf_auto_export"].preferences - - for (k, v) in export_props.items(): - setattr(addon_prefs, k, v) - - - def execute(self, context): - if self.will_save_settings: - self.save_settings(context) - # apply the operator properties to the addon preferences - self.apply_settings_to_preferences(context) - - return {'FINISHED'} - - def invoke(self, context, event): - settings = context.scene.get(self.scene_key) - print("settings", settings) - self.will_save_settings = False - if settings: - print("loading settings in invoke AutoExportGLTF") - 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 = bpy.context.preferences.addons["gltf_auto_export"].preferences.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 = bpy.context.preferences.addons["gltf_auto_export"].preferences.library_scenes - library_scenes.clear() - for item_name in self.library_scene_names: - item = library_scenes.add() - item.name = item_name - - if hasattr(self, 'collection_instances_combine_mode'): - bpy.context.preferences.addons["gltf_auto_export"].preferences.collection_instances_combine_mode = self.collection_instances_combine_mode - - - except (AttributeError, TypeError): - self.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings") - del context.scene[self.scene_key] - - - for (k, v) in self.properties.items(): - print("PROPERTIES", k, v) - - addon_prefs = bpy.context.preferences.addons["gltf_auto_export"].preferences - - [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: - # we save this list of collections in the context - bpy.context.window_manager.exportedCollections.clear() - #TODO: add error handling for this - for collection_name in collections: - 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") - - - - wm = context.window_manager - wm.fileselect_add(self) - return {'RUNNING_MODAL'} - # return self.execute(context) - - def draw(self, context): - pass - class GLTF_PT_auto_export_main(bpy.types.Panel): bl_space_type = 'FILE_BROWSER' bl_region_type = 'TOOL_PROPS' @@ -214,13 +74,13 @@ class GLTF_PT_auto_export_root(bpy.types.Panel): col = row.column(align=True) col.separator() - source = bpy.context.preferences.addons["gltf_auto_export"].preferences + source = operator rows = 2 # main/level scenes layout.label(text="main scenes") - layout.prop(context.scene, "main_scene", text='') + layout.prop(context.window_manager, "main_scene", text='') row = layout.row() row.template_list("SCENE_UL_GLTF_auto_export", "level scenes", source, "main_scenes", source, "main_scenes_index", rows=rows) @@ -231,7 +91,7 @@ class GLTF_PT_auto_export_root(bpy.types.Panel): add_operator.action = 'ADD' add_operator.scene_type = 'level' #add_operator.source = operator - sub_row.enabled = context.scene.main_scene is not None + sub_row.enabled = context.window_manager.main_scene is not None sub_row = col.row() remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="") @@ -245,7 +105,7 @@ class GLTF_PT_auto_export_root(bpy.types.Panel): # library scenes layout.label(text="library scenes") - layout.prop(context.scene, "library_scene", text='') + layout.prop(context.window_manager, "library_scene", text='') row = layout.row() row.template_list("SCENE_UL_GLTF_auto_export", "library scenes", source, "library_scenes", source, "library_scenes_index", rows=rows) @@ -255,7 +115,7 @@ class GLTF_PT_auto_export_root(bpy.types.Panel): add_operator = sub_row.operator("scene_list.list_action", icon='ADD', text="") add_operator.action = 'ADD' add_operator.scene_type = 'library' - sub_row.enabled = context.scene.library_scene is not None + sub_row.enabled = context.window_manager.library_scene is not None sub_row = col.row() @@ -309,9 +169,6 @@ class GLTF_PT_auto_export_blueprints(bpy.types.Panel): layout.prop(operator, "export_materials_path") - - - class GLTF_PT_auto_export_collections_list(bpy.types.Panel): bl_space_type = 'FILE_BROWSER' bl_region_type = 'TOOL_PROPS' @@ -333,7 +190,6 @@ class GLTF_PT_auto_export_collections_list(bpy.types.Panel): sfile = context.space_data operator = sfile.active_operator - addon_prefs = bpy.context.preferences.addons["gltf_auto_export"].preferences for collection in bpy.context.window_manager.exportedCollections: row = layout.row() @@ -355,30 +211,23 @@ class GLTF_PT_auto_export_gltf(bpy.types.Panel): def draw(self, context): preferences = context.preferences - addon_prefs = preferences.addons["gltf_auto_export"].preferences layout = self.layout sfile = context.space_data operator = sfile.active_operator - #preferences = context.preferences - #print("ADDON PREFERENCES ", list(preferences.addons.keys())) - #print("standard blender gltf prefs", list(preferences.addons["io_scene_gltf2"].preferences.keys())) + addon_prefs = operator + # we get the addon preferences from the standard gltf exporter & use those : addon_prefs_gltf = preferences.addons["io_scene_gltf2"].preferences - #addon_prefs = preferences.addons["gltf_auto_export"].preferences + #self.layout.operator("EXPORT_SCENE_OT_gltf", text='glTF 2.0 (.glb/.gltf)') + #bpy.ops.export_scene.gltf - # print("KEYS", operator.properties.keys()) - #print("BLAS", addon_prefs.__annotations__) - #print(addon_prefs.__dict__) for key in addon_prefs.__annotations__.keys(): if key not in AutoExportGltfPreferenceNames: layout.prop(operator, key) - - - class SCENE_UL_GLTF_auto_export(bpy.types.UIList): # The draw_item function is called for each item of the collection that is visible in the list. # data is the RNA object containing the collection, diff --git a/tools/gltf_auto_export/ui/various.py b/tools/gltf_auto_export/ui/operators.py similarity index 71% rename from tools/gltf_auto_export/ui/various.py rename to tools/gltf_auto_export/ui/operators.py index 3ec5707..31ea51d 100644 --- a/tools/gltf_auto_export/ui/various.py +++ b/tools/gltf_auto_export/ui/operators.py @@ -20,8 +20,7 @@ class SCENES_LIST_OT_actions(Operator): scene_type: bpy.props.StringProperty()#TODO: replace with enum def invoke(self, context, event): - print("INVOKE", self.scene_type, "gltf_auto_export") - source = bpy.context.preferences.addons["gltf_auto_export"].preferences + source = context.space_data.active_operator target_name = "library_scenes" target_index = "library_scenes_index" if self.scene_type == "level": @@ -30,6 +29,7 @@ class SCENES_LIST_OT_actions(Operator): target = getattr(source, target_name) idx = getattr(source, target_index) + current_index = getattr(source, target_index) try: item = target[idx] @@ -37,46 +37,44 @@ class SCENES_LIST_OT_actions(Operator): pass else: if self.action == 'DOWN' and idx < len(target) - 1: - item_next = target[idx + 1].name target.move(idx, idx + 1) - source[target_index] += 1 - info = 'Item "%s" moved to position %d' % (item.name, source[target_index] + 1) + setattr(source, target_index, current_index +1 ) + info = 'Item "%s" moved to position %d' % (item.name, current_index + 1) self.report({'INFO'}, info) elif self.action == 'UP' and idx >= 1: - item_prev = target[idx - 1].name target.move(idx, idx - 1) - source[target_index] -= 1 - info = 'Item "%s" moved to position %d' % (item.name, source[target_index] + 1) + setattr(source, target_index, current_index -1 ) + info = 'Item "%s" moved to position %d' % (item.name, current_index + 1) self.report({'INFO'}, info) elif self.action == 'REMOVE': info = 'Item "%s" removed from list' % (target[idx].name) - source[target_index] -= 1 + setattr(source, target_index, current_index -1 ) target.remove(idx) self.report({'INFO'}, info) if self.action == 'ADD': new_scene_name = None if self.scene_type == "level": - if context.scene.main_scene: - new_scene_name = context.scene.main_scene.name + if context.window_manager.main_scene: + new_scene_name = context.window_manager.main_scene.name else: - if context.scene.library_scene: - new_scene_name = context.scene.library_scene.name + if context.window_manager.library_scene: + new_scene_name = context.window_manager.library_scene.name if new_scene_name: item = target.add() item.name = new_scene_name#f"Rule {idx +1}" if self.scene_type == "level": - context.scene.main_scene = None + context.window_manager.main_scene = None else: - context.scene.library_scene = None + context.window_manager.library_scene = None #name = f"Rule {idx +1}" #target.append({"name": name}) - - source[target_index] = len(target) - 1 + setattr(source, target_index, len(target) - 1) + #source[target_index] = len(target) - 1 info = '"%s" added to list' % (item.name) self.report({'INFO'}, info)