Compare commits

..

No commits in common. "fa4386a1850159f744c6e5a1c98b52629f578072" and "f5b063cd344d9ab8dc6141abab7c8958b5509512" have entirely different histories.

8 changed files with 128 additions and 133 deletions

View File

@ -122,7 +122,8 @@ impl Plugin for BlueprintsPlugin {
.register_type::<Animations>() .register_type::<Animations>()
.register_type::<BlueprintsList>() .register_type::<BlueprintsList>()
.register_type::<Vec<String>>() .register_type::<Vec<String>>()
.register_type::<HashMap<String, Vec<String>>>() .register_type::<HashMap<String,Vec<String>>>()
.insert_resource(BluePrintsConfig { .insert_resource(BluePrintsConfig {
format: self.format, format: self.format,
library_folder: self.library_folder.clone(), library_folder: self.library_folder.clone(),
@ -143,21 +144,26 @@ impl Plugin for BlueprintsPlugin {
.add_systems( .add_systems(
Update, Update,
( (
( (
prepare_blueprints, prepare_blueprints,
check_for_loaded, check_for_loaded,
spawn_from_blueprints, spawn_from_blueprints,
apply_deferred, apply_deferred
) )
.chain(), .chain(),
(compute_scene_aabbs, apply_deferred) (
compute_scene_aabbs,
apply_deferred
)
.chain() .chain()
.run_if(aabbs_enabled), .run_if(aabbs_enabled),
apply_deferred, apply_deferred,
( (
materials_inject, materials_inject,
check_for_material_loaded, check_for_material_loaded,
materials_inject2, materials_inject2
) )
.chain() .chain()
.run_if(materials_library_enabled), .run_if(materials_library_enabled),

View File

@ -1,17 +1,13 @@
use std::path::Path; use std::path::Path;
use bevy::{ use bevy::{
asset::{AssetServer, Assets, Handle}, asset::{AssetId, AssetServer, Assets, Handle},
ecs::{ ecs::{
component::Component, component::Component, entity::Entity, query::{Added, With}, reflect::ReflectComponent, system::{Commands, Query, Res, ResMut}
entity::Entity,
query::{Added, With},
reflect::ReflectComponent,
system::{Commands, Query, Res, ResMut},
}, },
gltf::Gltf, gltf::Gltf,
hierarchy::{Children, Parent}, hierarchy::{Children, Parent},
log::debug, log::{debug, info},
pbr::StandardMaterial, pbr::StandardMaterial,
reflect::Reflect, reflect::Reflect,
render::mesh::Mesh, render::mesh::Mesh,
@ -63,24 +59,25 @@ pub(crate) fn materials_inject(
commands commands
.entity(entity) .entity(entity)
.insert(BlueprintMaterialAssetsLoaded); .insert(BlueprintMaterialAssetsLoaded);
} else { } else {
let material_file_handle: Handle<Gltf> = asset_server.load(materials_path.clone()); let material_file_handle: Handle<Gltf> = asset_server.load(materials_path.clone());
let material_file_id = material_file_handle.id(); let material_file_id = material_file_handle.id();
let asset_infos: Vec<AssetLoadTracker<Gltf>> = vec![ let mut asset_infos:Vec<AssetLoadTracker<Gltf>> = vec![];
AssetLoadTracker {
name: material_full_path,
id: material_file_id,
loaded: false,
handle: material_file_handle.clone(),
}
];
asset_infos.push(AssetLoadTracker {
name: material_full_path,
id: material_file_id,
loaded: false,
handle: material_file_handle.clone()
});
commands commands
.entity(entity) .entity(entity)
.insert(AssetsToLoad { .insert(AssetsToLoad{
all_loaded: false, all_loaded: false,
asset_infos, asset_infos: asset_infos,
..Default::default() progress: 0.0
//..Default::default()
}) })
.insert(BlueprintMaterialAssetsNotLoaded); .insert(BlueprintMaterialAssetsNotLoaded);
/**/ /**/
@ -90,50 +87,41 @@ pub(crate) fn materials_inject(
// TODO, merge with check_for_loaded, make generic ? // TODO, merge with check_for_loaded, make generic ?
pub(crate) fn check_for_material_loaded( pub(crate) fn check_for_material_loaded(
mut blueprint_assets_to_load: Query< mut blueprint_assets_to_load: Query<(Entity, &mut AssetsToLoad<Gltf>),With<BlueprintMaterialAssetsNotLoaded>>,
(Entity, &mut AssetsToLoad<Gltf>),
With<BlueprintMaterialAssetsNotLoaded>,
>,
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
mut commands: Commands, mut commands: Commands,
) { ){
for (entity, mut assets_to_load) in blueprint_assets_to_load.iter_mut() { for (entity, mut assets_to_load) in blueprint_assets_to_load.iter_mut(){
let mut all_loaded = true; let mut all_loaded = true;
let mut loaded_amount = 0; let mut loaded_amount = 0;
let total = assets_to_load.asset_infos.len(); let total = assets_to_load.asset_infos.len();
for tracker in assets_to_load.asset_infos.iter_mut() { for tracker in assets_to_load.asset_infos.iter_mut(){
let asset_id = tracker.id; let asset_id = tracker.id;
let loaded = asset_server.is_loaded_with_dependencies(asset_id); let loaded = asset_server.is_loaded_with_dependencies(asset_id);
tracker.loaded = loaded; tracker.loaded = loaded;
if loaded { if loaded {
loaded_amount += 1; loaded_amount += 1;
} else { }else{
all_loaded = false; all_loaded = false;
} }
} }
let progress: f32 = loaded_amount as f32 / total as f32; let progress:f32 = loaded_amount as f32 / total as f32;
assets_to_load.progress = progress; assets_to_load.progress = progress;
if all_loaded { if all_loaded {
assets_to_load.all_loaded = true; assets_to_load.all_loaded = true;
commands commands.entity(entity)
.entity(entity)
.insert(BlueprintMaterialAssetsLoaded) .insert(BlueprintMaterialAssetsLoaded)
.remove::<BlueprintMaterialAssetsNotLoaded>(); .remove::<BlueprintMaterialAssetsNotLoaded>();
} }
} }
} }
/// system that injects / replaces materials from material library /// system that injects / replaces materials from material library
pub(crate) fn materials_inject2( pub(crate) fn materials_inject2(
mut blueprints_config: ResMut<BluePrintsConfig>, mut blueprints_config: ResMut<BluePrintsConfig>,
material_infos: Query< material_infos: Query<(&MaterialInfo, &Children, ), (Added<BlueprintMaterialAssetsLoaded>, With<BlueprintMaterialAssetsLoaded>)>,
(&MaterialInfo, &Children),
(
Added<BlueprintMaterialAssetsLoaded>,
With<BlueprintMaterialAssetsLoaded>,
),
>,
with_materials_and_meshes: Query< with_materials_and_meshes: Query<
(), (),
( (
@ -169,8 +157,8 @@ pub(crate) fn materials_inject2(
.get(&material_full_path) .get(&material_full_path)
.expect("we should have the material available"); .expect("we should have the material available");
material_found = Some(material); material_found = Some(material);
} else { }else {
let model_handle: Handle<Gltf> = asset_server.load(materials_path.clone()); // FIXME: kinda weird now let model_handle: Handle<Gltf> = asset_server.load(materials_path.clone());// FIXME: kinda weird now
let mat_gltf = assets_gltf let mat_gltf = assets_gltf
.get(model_handle.id()) .get(model_handle.id())
.expect("material should have been preloaded"); .expect("material should have been preloaded");

View File

@ -48,29 +48,23 @@ pub(crate) struct OriginalChildren(pub Vec<Entity>);
#[derive(Component, Reflect, Default, Debug)] #[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)] #[reflect(Component)]
pub struct BlueprintsList(pub HashMap<String, Vec<String>>); pub struct BlueprintsList(pub HashMap<String,Vec<String>>);
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub(crate) struct AssetLoadTracker<T: bevy::prelude::Asset> { pub(crate) struct AssetLoadTracker<T:bevy::prelude::Asset>{
#[allow(dead_code)]
pub name: String, pub name: String,
pub id: AssetId<T>, pub id: AssetId<T>,
pub loaded: bool, pub loaded: bool,
#[allow(dead_code)] pub handle: Handle<T>
pub handle: Handle<T>,
} }
#[derive(Component, Debug)] #[derive(Component, Default, Debug)]
pub(crate) struct AssetsToLoad<T: bevy::prelude::Asset> { pub(crate) struct AssetsToLoad<T:bevy::prelude::Asset>{
pub all_loaded: bool, pub all_loaded: bool,
pub asset_infos: Vec<AssetLoadTracker<T>>, pub asset_infos: Vec<AssetLoadTracker<T>>,
pub progress: f32, pub progress: f32
}
impl <T: bevy::prelude::Asset>Default for AssetsToLoad<T> {
fn default() -> Self {
Self { all_loaded: Default::default(), asset_infos: Default::default(), progress: Default::default() }
}
} }
/// flag component /// flag component
#[derive(Component)] #[derive(Component)]
pub(crate) struct BlueprintAssetsLoaded; pub(crate) struct BlueprintAssetsLoaded;
@ -97,8 +91,15 @@ pub(crate) fn prepare_blueprints(
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
blueprints_config: Res<BluePrintsConfig>, blueprints_config: Res<BluePrintsConfig>,
) { ) {
for (entity, blupeprint_name, original_parent, library_override, name, blueprints_list) in for (
spawn_placeholders.iter() entity,
blupeprint_name,
original_parent,
library_override,
name,
blueprints_list,
) in spawn_placeholders.iter()
{ {
debug!( debug!(
"requesting to spawn {:?} for entity {:?}, id: {:?}, parent:{:?}", "requesting to spawn {:?} for entity {:?}, id: {:?}, parent:{:?}",
@ -109,10 +110,19 @@ pub(crate) fn prepare_blueprints(
if blueprints_list.is_some() { if blueprints_list.is_some() {
let blueprints_list = blueprints_list.unwrap(); let blueprints_list = blueprints_list.unwrap();
// println!("blueprints list {:?}", blueprints_list.0.keys()); // println!("blueprints list {:?}", blueprints_list.0.keys());
let mut asset_infos: Vec<AssetLoadTracker<Gltf>> = vec![]; let mut asset_infos:Vec<AssetLoadTracker<Gltf>> = vec![];
let library_path =
library_override.map_or_else(|| &blueprints_config.library_folder, |l| &l.0);
for (blueprint_name, _) in blueprints_list.0.iter() { for (blueprint_name, _) in blueprints_list.0.iter() {
/*if blueprint_name == what {
println!("WHOLY MOLLY !")
}*/
// println!("library path {:?}", library_path);
let mut library_path = &blueprints_config.library_folder; // TODO: we cannot use the overriden library path
// FIXME: hack
if blueprint_name == "World" {
library_path= &library_override.unwrap().0;
}
let model_file_name = format!("{}.{}", &blueprint_name, &blueprints_config.format); let model_file_name = format!("{}.{}", &blueprint_name, &blueprints_config.format);
let model_path = Path::new(&library_path).join(Path::new(model_file_name.as_str())); let model_path = Path::new(&library_path).join(Path::new(model_file_name.as_str()));
@ -124,60 +134,61 @@ pub(crate) fn prepare_blueprints(
name: model_path.to_string_lossy().into(), name: model_path.to_string_lossy().into(),
id: model_id, id: model_id,
loaded: false, loaded: false,
handle: model_handle.clone(), handle: model_handle.clone()
}); })
} }
} }
// if not all assets are already loaded, inject a component to signal that we need them to be loaded // if not all assets are already loaded, inject a component to signal that we need them to be loaded
if !asset_infos.is_empty() { if asset_infos.len() > 0 {
commands commands
.entity(entity) .entity(entity)
.insert(AssetsToLoad { .insert(AssetsToLoad{
all_loaded: false, all_loaded: false,
asset_infos, asset_infos: asset_infos,
..Default::default() progress: 0.0
}) //..Default::default()
.insert(BlueprintAssetsNotLoaded); })
} else { .insert(BlueprintAssetsNotLoaded);
commands.entity(entity).insert(BlueprintAssetsLoaded); }else {
commands
.entity(entity)
.insert(BlueprintAssetsLoaded);
} }
} else { }
// in case there are no blueprintsList else { // in case there are no blueprintsList
commands.entity(entity).insert(BlueprintAssetsLoaded); commands
.entity(entity)
.insert(BlueprintAssetsLoaded);
} }
} }
} }
pub(crate) fn check_for_loaded( pub(crate) fn check_for_loaded(
mut blueprint_assets_to_load: Query< mut blueprint_assets_to_load: Query<(Entity, &mut AssetsToLoad<Gltf>), With<BlueprintAssetsNotLoaded>>,
(Entity, &mut AssetsToLoad<Gltf>),
With<BlueprintAssetsNotLoaded>,
>,
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
mut commands: Commands, mut commands: Commands,
) { ){
for (entity, mut assets_to_load) in blueprint_assets_to_load.iter_mut() { for (entity, mut assets_to_load) in blueprint_assets_to_load.iter_mut(){
let mut all_loaded = true; let mut all_loaded = true;
let mut loaded_amount = 0; let mut loaded_amount = 0;
let total = assets_to_load.asset_infos.len(); let total = assets_to_load.asset_infos.len();
for tracker in assets_to_load.asset_infos.iter_mut() { for tracker in assets_to_load.asset_infos.iter_mut(){
let asset_id = tracker.id; let asset_id = tracker.id;
let loaded = asset_server.is_loaded_with_dependencies(asset_id); let loaded = asset_server.is_loaded_with_dependencies(asset_id);
tracker.loaded = loaded; tracker.loaded = loaded;
if loaded { if loaded {
loaded_amount += 1; loaded_amount += 1;
} else { }else{
all_loaded = false; all_loaded = false;
} }
} }
let progress: f32 = loaded_amount as f32 / total as f32; let progress:f32 = loaded_amount as f32 / total as f32;
// println!("progress: {}",progress); // println!("progress: {}",progress);
assets_to_load.progress = progress; assets_to_load.progress = progress;
if all_loaded { if all_loaded {
assets_to_load.all_loaded = true; assets_to_load.all_loaded = true;
commands commands.entity(entity)
.entity(entity)
.insert(BlueprintAssetsLoaded) .insert(BlueprintAssetsLoaded)
.remove::<BlueprintAssetsNotLoaded>(); .remove::<BlueprintAssetsNotLoaded>();
} }
@ -186,20 +197,16 @@ pub(crate) fn check_for_loaded(
pub(crate) fn spawn_from_blueprints( pub(crate) fn spawn_from_blueprints(
spawn_placeholders: Query< spawn_placeholders: Query<
( (
Entity, Entity,
&BlueprintName, &BlueprintName,
Option<&Transform>, Option<&Transform>,
Option<&Parent>, Option<&Parent>,
Option<&Library>, Option<&Library>,
Option<&AddToGameWorld>, Option<&AddToGameWorld>,
Option<&Name>, Option<&Name>,
), ),
( (With<BlueprintAssetsLoaded>, Added<BlueprintAssetsLoaded>, Without<BlueprintAssetsNotLoaded>),
With<BlueprintAssetsLoaded>,
Added<BlueprintAssetsLoaded>,
Without<BlueprintAssetsNotLoaded>,
),
>, >,
mut commands: Commands, mut commands: Commands,
@ -210,7 +217,8 @@ pub(crate) fn spawn_from_blueprints(
blueprints_config: Res<BluePrintsConfig>, blueprints_config: Res<BluePrintsConfig>,
children: Query<&Children>, children: Query<&Children>,
) { ){
for ( for (
entity, entity,
blupeprint_name, blupeprint_name,
@ -219,6 +227,7 @@ pub(crate) fn spawn_from_blueprints(
library_override, library_override,
add_to_world, add_to_world,
name, name,
) in spawn_placeholders.iter() ) in spawn_placeholders.iter()
{ {
info!( info!(
@ -235,7 +244,7 @@ pub(crate) fn spawn_from_blueprints(
let model_path = Path::new(&library_path).join(Path::new(model_file_name.as_str())); let model_path = Path::new(&library_path).join(Path::new(model_file_name.as_str()));
// info!("attempting to spawn {:?}", model_path); // info!("attempting to spawn {:?}", model_path);
let model_handle: Handle<Gltf> = asset_server.load(model_path); // FIXME: kinda weird now let model_handle: Handle<Gltf> = asset_server.load(model_path);// FIXME: kinda weird now
let gltf = assets_gltf let gltf = assets_gltf
.get(&model_handle) .get(&model_handle)
@ -282,4 +291,4 @@ pub(crate) fn spawn_from_blueprints(
commands.entity(world).add_child(entity); commands.entity(world).add_child(entity);
} }
} }
} }

View File

@ -7,10 +7,7 @@ use bevy::scene::SceneInstance;
use super::{AnimationPlayerLink, Animations}; use super::{AnimationPlayerLink, Animations};
use super::{SpawnHere, Spawned}; use super::{SpawnHere, Spawned};
use crate::{ use crate::{AssetsToLoad, BlueprintAssetsLoaded, CopyComponents, InBlueprint, NoInBlueprint, OriginalChildren};
AssetsToLoad, BlueprintAssetsLoaded, CopyComponents, InBlueprint, NoInBlueprint,
OriginalChildren,
};
/// this system is in charge of doing any necessary post processing after a blueprint scene has been spawned /// this system is in charge of doing any necessary post processing after a blueprint scene has been spawned
/// - it removes one level of useless nesting /// - it removes one level of useless nesting
@ -93,7 +90,7 @@ pub(crate) fn spawned_blueprint_post_process(
commands.entity(original).remove::<SpawnHere>(); commands.entity(original).remove::<SpawnHere>();
commands.entity(original).remove::<Spawned>(); commands.entity(original).remove::<Spawned>();
commands.entity(original).remove::<Handle<Scene>>(); commands.entity(original).remove::<Handle<Scene>>();
commands.entity(original).remove::<AssetsToLoad<Gltf>>(); // also clear the sub assets tracker to free up handles, perhaps just freeing up the handles and leave the rest would be better ? commands.entity(original).remove::<AssetsToLoad<Gltf>>();// also clear the sub assets tracker to free up handles, perhaps just freeing up the handles and leave the rest would be better ?
commands.entity(original).remove::<BlueprintAssetsLoaded>(); commands.entity(original).remove::<BlueprintAssetsLoaded>();
commands.entity(root_entity).despawn_recursive(); commands.entity(root_entity).despawn_recursive();
} }

View File

@ -11,7 +11,7 @@ impl Plugin for CorePlugin {
legacy_mode: false, legacy_mode: false,
library_folder: "models/library".into(), library_folder: "models/library".into(),
format: GltfFormat::GLB, format: GltfFormat::GLB,
material_library: true, material_library:true,
aabbs: true, aabbs: true,
..Default::default() ..Default::default()
}, },

View File

@ -1,8 +1,6 @@
use bevy::prelude::*; use bevy::{prelude::*, utils::hashbrown::HashMap};
use bevy_gltf_blueprints::{ use bevy_gltf_blueprints::{BluePrintBundle, BlueprintName, BlueprintsList, GameWorldTag, Library, SpawnHere};
BluePrintBundle, BlueprintName, GameWorldTag, use bevy_gltf_worlflow_examples_common_rapier::{assets::GameAssets, GameState, InAppRunning};
};
use bevy_gltf_worlflow_examples_common_rapier::{GameState, InAppRunning};
use bevy_rapier3d::prelude::Velocity; use bevy_rapier3d::prelude::Velocity;
use rand::Rng; use rand::Rng;
@ -14,7 +12,7 @@ pub fn setup_game(
) { ) {
// here we actually spawn our game world/level // here we actually spawn our game world/level
commands.spawn(( commands.spawn((
SceneBundle { SceneBundle{
scene: asset_server.load("models/World.glb#Scene0"), scene: asset_server.load("models/World.glb#Scene0"),
..default() ..default()
}, },

View File

@ -73,13 +73,6 @@ def copy_hollowed_collection_into(source_collection, destination_collection, par
"""we inject the collection/blueprint name, as a component called 'BlueprintName', but we only do this in the empty, not the original object""" """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+'"' if legacy_mode else '("'+collection_name+'")' empty_obj['BlueprintName'] = '"'+collection_name+'"' if legacy_mode else '("'+collection_name+'")'
empty_obj['SpawnHere'] = '()' empty_obj['SpawnHere'] = '()'
# we also inject a list of all sub blueprints, so that the bevy side can preload them
root_node = CollectionNode()
root_node.name = "root"
children_per_collection = {}
get_sub_collections([object.instance_collection], root_node, children_per_collection)
empty_obj["BlueprintsList"] = f"({json.dumps(dict(children_per_collection))})"
#empty_obj["Assets"] = {"Animations": [], "Materials": [], "Models":[], "Textures":[], "Audio":[], "Other":[]}
# we copy custom properties over from our original object to our empty # we copy custom properties over from our original object to our empty
for component_name, component_value in object.items(): for component_name, component_value in object.items():
@ -169,7 +162,8 @@ def inject_blueprints_list_into_main_scene(scene):
break break
if assets_list is None: if assets_list is None:
assets_list = make_empty('assets_list_'+scene.name+"_components", [0,0,0], [0,0,0], [0,0,0], root_collection) assets_list = make_empty('assets_list_'+scene.name, [0,0,0], [0,0,0], [0,0,0], root_collection)
# find all blueprints used in a scene # find all blueprints used in a scene
# TODO: export a tree rather than a flat list ? because you could have potential clashing items in flat lists (amongst other issues) # TODO: export a tree rather than a flat list ? because you could have potential clashing items in flat lists (amongst other issues)
@ -180,12 +174,16 @@ def inject_blueprints_list_into_main_scene(scene):
#print("collection_names", collection_names, "collections", collections) #print("collection_names", collection_names, "collections", collections)
(bla, bli ) = get_sub_collections(collections, root_node, children_per_collection) (bla, bli ) = get_sub_collections(collections, root_node, children_per_collection)
#print("sfdsfsdf", bla, bli, "root", root_node, "children_per_collection", children_per_collection)
# with sub collections
# (collection_names, collections) = get_sub_collections(all_collections, root_node, children_per_collection)
#
# what about marked assets ? # what about marked assets ?
# what about audio assets ?
# what about materials ?
# object['MaterialInfo'] = '(name: "'+material.name+'", source: "'+current_project_name + '")'
#assets_list["blueprints_direct"] = list(collection_names) #assets_list["blueprints_direct"] = list(collection_names)
assets_list["BlueprintsList"] = f"({json.dumps(dict(children_per_collection))})" assets_list["BlueprintsList"] = f"({json.dumps(dict(children_per_collection))})"
assets_list["Materials"]= '()' #'({"a":[]})'
#'([])'
#
#
print("assets list", assets_list["BlueprintsList"], children_per_collection) print("assets list", assets_list["BlueprintsList"], children_per_collection)

View File

@ -16,7 +16,7 @@ def setup_data(request):
root_path = "../../testing/bevy_example" root_path = "../../testing/bevy_example"
assets_root_path = os.path.join(root_path, "assets") assets_root_path = os.path.join(root_path, "assets")
models_path = os.path.join(assets_root_path, "models") models_path = os.path.join(assets_root_path, "models")
materials_path = os.path.join(assets_root_path, "materials") #materials_path = os.path.join("../../testing", "materials")
#other_materials_path = os.path.join("../../testing", "other_materials") #other_materials_path = os.path.join("../../testing", "other_materials")
print("\nPerforming teardown...") print("\nPerforming teardown...")
@ -75,8 +75,7 @@ def test_export_complex(setup_data):
export_scene_settings=True, export_scene_settings=True,
export_blueprints=True, export_blueprints=True,
export_legacy_mode=False, export_legacy_mode=False,
export_animations=True, export_animations=True
export_materials_library=True
) )
# blueprint1 => has an instance, got changed, should export # blueprint1 => has an instance, got changed, should export
# blueprint2 => has NO instance, but marked as asset, should export # blueprint2 => has NO instance, but marked as asset, should export