feat(Blenvy): continued restructuring & upgrade of blueprint spawning logic
* updated simple test to include deep nested blueprint instance within blueprint instance case * restructured materials handling to use the new logic, removed clutter * experimenting with solutions to the deeply nested blueprint instances problem * moved out all obsolete code to "old" folder, keeeping around until all problems are solved * added hack-ish solution to the "aabb system as post process" implementation * various minor boilerprate changes
This commit is contained in:
parent
6dde9823ed
commit
fbcd025dc1
|
@ -0,0 +1,190 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use bevy::{
|
||||||
|
asset::{AssetServer, Assets, Handle},
|
||||||
|
ecs::{
|
||||||
|
component::Component,
|
||||||
|
entity::Entity,
|
||||||
|
query::{Added, With},
|
||||||
|
reflect::ReflectComponent,
|
||||||
|
system::{Commands, Query, Res, ResMut},
|
||||||
|
},
|
||||||
|
gltf::Gltf,
|
||||||
|
hierarchy::{Children, Parent},
|
||||||
|
log::debug,
|
||||||
|
pbr::StandardMaterial,
|
||||||
|
reflect::Reflect,
|
||||||
|
render::mesh::Mesh,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{AssetLoadTracker, BlueprintAssetsLoadState, BlenvyConfig, BlueprintInstanceReady};
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
/// struct containing the name & path of the material to apply
|
||||||
|
pub struct MaterialInfo {
|
||||||
|
pub name: String,
|
||||||
|
pub path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// flag component
|
||||||
|
#[derive(Component)]
|
||||||
|
pub(crate) struct BlueprintMaterialAssetsLoaded;
|
||||||
|
/// flag component
|
||||||
|
#[derive(Component)]
|
||||||
|
pub(crate) struct BlueprintMaterialAssetsNotLoaded;
|
||||||
|
|
||||||
|
/// system that injects / replaces materials from material library
|
||||||
|
pub(crate) fn materials_inject(
|
||||||
|
blenvy_config: ResMut<BlenvyConfig>,
|
||||||
|
material_infos: Query<(Entity, &MaterialInfo), Added<MaterialInfo>>,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
for (entity, material_info) in material_infos.iter() {
|
||||||
|
println!("Entity with material info {:?} {:?}", entity, material_info);
|
||||||
|
let material_full_path = format!("{}#{}", material_info.path, material_info.name);
|
||||||
|
if blenvy_config
|
||||||
|
.materials_cache
|
||||||
|
.contains_key(&material_full_path)
|
||||||
|
{
|
||||||
|
debug!("material is cached, retrieving");
|
||||||
|
blenvy_config
|
||||||
|
.materials_cache
|
||||||
|
.get(&material_full_path)
|
||||||
|
.expect("we should have the material available");
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(BlueprintMaterialAssetsLoaded);
|
||||||
|
} else {
|
||||||
|
let material_file_handle = asset_server.load_untyped(&material_info.path.clone()); // : Handle<Gltf>
|
||||||
|
let material_file_id = material_file_handle.id();
|
||||||
|
|
||||||
|
let asset_infos: Vec<AssetLoadTracker> = vec![AssetLoadTracker {
|
||||||
|
name: material_info.name.clone(),
|
||||||
|
path: material_info.path.clone(),
|
||||||
|
id: material_file_id,
|
||||||
|
loaded: false,
|
||||||
|
handle: material_file_handle.clone(),
|
||||||
|
}];
|
||||||
|
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(BlueprintAssetsLoadState {
|
||||||
|
all_loaded: false,
|
||||||
|
asset_infos,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.insert(BlueprintMaterialAssetsNotLoaded);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO, merge with blueprints_check_assets_loading, make generic ?
|
||||||
|
pub(crate) fn check_for_material_loaded(
|
||||||
|
mut blueprint_assets_to_load: Query<
|
||||||
|
(Entity, &mut BlueprintAssetsLoadState),
|
||||||
|
With<BlueprintMaterialAssetsNotLoaded>,
|
||||||
|
>,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
for (entity, mut assets_to_load) in blueprint_assets_to_load.iter_mut() {
|
||||||
|
let mut all_loaded = true;
|
||||||
|
let mut loaded_amount = 0;
|
||||||
|
let total = assets_to_load.asset_infos.len();
|
||||||
|
for tracker in assets_to_load.asset_infos.iter_mut() {
|
||||||
|
let asset_id = tracker.id;
|
||||||
|
let loaded = asset_server.is_loaded_with_dependencies(asset_id);
|
||||||
|
tracker.loaded = loaded;
|
||||||
|
if loaded {
|
||||||
|
loaded_amount += 1;
|
||||||
|
} else {
|
||||||
|
all_loaded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let progress: f32 = loaded_amount as f32 / total as f32;
|
||||||
|
assets_to_load.progress = progress;
|
||||||
|
|
||||||
|
if all_loaded {
|
||||||
|
assets_to_load.all_loaded = true;
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(BlueprintMaterialAssetsLoaded)
|
||||||
|
.remove::<BlueprintMaterialAssetsNotLoaded>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// system that injects / replaces materials from material library
|
||||||
|
pub(crate) fn materials_inject2(
|
||||||
|
mut blenvy_config: ResMut<BlenvyConfig>,
|
||||||
|
material_infos: Query<
|
||||||
|
(&MaterialInfo, &Children),
|
||||||
|
(
|
||||||
|
Added<BlueprintMaterialAssetsLoaded>,
|
||||||
|
With<BlueprintMaterialAssetsLoaded>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
with_materials_and_meshes: Query<
|
||||||
|
(),
|
||||||
|
(
|
||||||
|
With<Parent>,
|
||||||
|
With<Handle<StandardMaterial>>,
|
||||||
|
With<Handle<Mesh>>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
assets_gltf: Res<Assets<Gltf>>,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
for (material_info, children) in material_infos.iter() {
|
||||||
|
let material_full_path = format!("{}#{}", material_info.path, material_info.name);
|
||||||
|
let mut material_found: Option<&Handle<StandardMaterial>> = None;
|
||||||
|
|
||||||
|
if blenvy_config
|
||||||
|
.materials_cache
|
||||||
|
.contains_key(&material_full_path)
|
||||||
|
{
|
||||||
|
debug!("material is cached, retrieving");
|
||||||
|
let material = blenvy_config
|
||||||
|
.materials_cache
|
||||||
|
.get(&material_full_path)
|
||||||
|
.expect("we should have the material available");
|
||||||
|
material_found = Some(material);
|
||||||
|
} else {
|
||||||
|
let model_handle: Handle<Gltf> = asset_server.load(material_info.path.clone()); // FIXME: kinda weird now
|
||||||
|
let mat_gltf = assets_gltf
|
||||||
|
.get(model_handle.id())
|
||||||
|
.expect("material should have been preloaded");
|
||||||
|
if mat_gltf.named_materials.contains_key(&material_info.name as &str) {
|
||||||
|
let material = mat_gltf
|
||||||
|
.named_materials
|
||||||
|
.get(&material_info.name as &str)
|
||||||
|
.expect("this material should have been loaded");
|
||||||
|
blenvy_config
|
||||||
|
.materials_cache
|
||||||
|
.insert(material_full_path, material.clone());
|
||||||
|
material_found = Some(material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(material) = material_found {
|
||||||
|
for child in children.iter() {
|
||||||
|
if with_materials_and_meshes.contains(*child) {
|
||||||
|
debug!(
|
||||||
|
"injecting material {}, path: {:?}",
|
||||||
|
material_info.name,
|
||||||
|
material_info.path.clone()
|
||||||
|
);
|
||||||
|
|
||||||
|
commands.entity(*child).insert(material.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ use bevy::prelude::*;
|
||||||
use bevy::scene::SceneInstance;
|
use bevy::scene::SceneInstance;
|
||||||
// use bevy::utils::hashbrown::HashSet;
|
// use bevy::utils::hashbrown::HashSet;
|
||||||
|
|
||||||
use crate::{BlueprintAnimationPlayerLink, BlueprintAnimations, BlueprintInfo, BlueprintReadyForPostProcess, BlueprintSpawned, BlueprintSpawning, SpawnTrackRoot, SubBlueprintsSpawnTracker};
|
use crate::{BlueprintAnimationPlayerLink, BlueprintAnimations, BlueprintInfo, BlueprintReadyForPostProcess, BlueprintInstanceReady, BlueprintSpawning, SpawnTrackRoot, SubBlueprintsSpawnTracker};
|
||||||
use crate::{SpawnHere, Spawned};
|
use crate::{SpawnHere, Spawned};
|
||||||
use crate::{
|
use crate::{
|
||||||
BlueprintEvent, CopyComponents, InBlueprint, NoInBlueprint, OriginalChildren
|
BlueprintEvent, CopyComponents, InBlueprint, NoInBlueprint, OriginalChildren
|
||||||
|
@ -113,7 +113,7 @@ pub(crate) fn spawned_blueprint_post_process( // rename to '
|
||||||
);
|
);
|
||||||
|
|
||||||
commands.entity(original)
|
commands.entity(original)
|
||||||
.insert(BlueprintSpawned)
|
.insert(BlueprintInstanceReady)
|
||||||
.remove::<BlueprintSpawning>()
|
.remove::<BlueprintSpawning>()
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::{BlenvyConfig, BlueprintReadyForFinalizing, BlueprintReadyForPostProc
|
||||||
/// helper system that computes the compound aabbs of the scenes/blueprints
|
/// helper system that computes the compound aabbs of the scenes/blueprints
|
||||||
pub fn compute_scene_aabbs(
|
pub fn compute_scene_aabbs(
|
||||||
root_entities: Query<(Entity, &Name), (With<BlueprintReadyForPostProcess>, Without<Aabb>)>,
|
root_entities: Query<(Entity, &Name), (With<BlueprintReadyForPostProcess>, Without<Aabb>)>,
|
||||||
|
other_entities: Query<Entity, (With<BlueprintReadyForPostProcess>, With<Aabb>)>,
|
||||||
children: Query<&Children>,
|
children: Query<&Children>,
|
||||||
existing_aabbs: Query<&Aabb>,
|
existing_aabbs: Query<&Aabb>,
|
||||||
|
|
||||||
|
@ -24,10 +25,16 @@ pub fn compute_scene_aabbs(
|
||||||
commands.entity(root_entity).insert(*aabb).insert(BlueprintReadyForFinalizing);
|
commands.entity(root_entity).insert(*aabb).insert(BlueprintReadyForFinalizing);
|
||||||
} else {
|
} else {
|
||||||
let aabb = compute_descendant_aabb(root_entity, &children, &existing_aabbs);
|
let aabb = compute_descendant_aabb(root_entity, &children, &existing_aabbs);
|
||||||
commands.entity(root_entity).insert(aabb).insert(BlueprintReadyForFinalizing);
|
|
||||||
blenvy_config.aabb_cache.insert(name.to_string(), aabb);
|
blenvy_config.aabb_cache.insert(name.to_string(), aabb);
|
||||||
|
info!("generating aabb for {:?}", name);
|
||||||
|
commands.entity(root_entity).insert(aabb).insert(BlueprintReadyForFinalizing);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for entity in other_entities.iter() {
|
||||||
|
println!("stuff with AABB");
|
||||||
|
commands.entity(entity).insert(BlueprintReadyForFinalizing); // FIXME ! Yikes !!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_descendant_aabb(
|
pub fn compute_descendant_aabb(
|
||||||
|
|
|
@ -1,23 +1,6 @@
|
||||||
use std::path::Path;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
use bevy::{
|
use crate::{BlenvyConfig, BlueprintReadyForPostProcess};
|
||||||
asset::{AssetServer, Assets, Handle},
|
|
||||||
ecs::{
|
|
||||||
component::Component,
|
|
||||||
entity::Entity,
|
|
||||||
query::{Added, With},
|
|
||||||
reflect::ReflectComponent,
|
|
||||||
system::{Commands, Query, Res, ResMut},
|
|
||||||
},
|
|
||||||
gltf::Gltf,
|
|
||||||
hierarchy::{Children, Parent},
|
|
||||||
log::debug,
|
|
||||||
pbr::StandardMaterial,
|
|
||||||
reflect::Reflect,
|
|
||||||
render::mesh::Mesh,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{AssetLoadTracker, BlueprintAssetsLoadState, BlenvyConfig, BlueprintInstanceReady};
|
|
||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
|
@ -27,107 +10,21 @@ pub struct MaterialInfo {
|
||||||
pub path: String,
|
pub path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// flag component
|
#[derive(Component, Default, Debug)]
|
||||||
#[derive(Component)]
|
pub struct MaterialProcessed;
|
||||||
pub(crate) struct BlueprintMaterialAssetsLoaded;
|
|
||||||
/// flag component
|
|
||||||
#[derive(Component)]
|
|
||||||
pub(crate) struct BlueprintMaterialAssetsNotLoaded;
|
|
||||||
|
|
||||||
/// system that injects / replaces materials from material library
|
/// system that injects / replaces materials from material library
|
||||||
pub(crate) fn materials_inject(
|
pub(crate) fn inject_materials(
|
||||||
blenvy_config: ResMut<BlenvyConfig>,
|
|
||||||
material_infos: Query<(Entity, &MaterialInfo), Added<MaterialInfo>>,
|
|
||||||
asset_server: Res<AssetServer>,
|
|
||||||
mut commands: Commands,
|
|
||||||
) {
|
|
||||||
|
|
||||||
|
|
||||||
for (entity, material_info) in material_infos.iter() {
|
|
||||||
println!("Entity with material info {:?} {:?}", entity, material_info);
|
|
||||||
let material_full_path = format!("{}#{}", material_info.path, material_info.name);
|
|
||||||
if blenvy_config
|
|
||||||
.materials_cache
|
|
||||||
.contains_key(&material_full_path)
|
|
||||||
{
|
|
||||||
debug!("material is cached, retrieving");
|
|
||||||
blenvy_config
|
|
||||||
.materials_cache
|
|
||||||
.get(&material_full_path)
|
|
||||||
.expect("we should have the material available");
|
|
||||||
commands
|
|
||||||
.entity(entity)
|
|
||||||
.insert(BlueprintMaterialAssetsLoaded);
|
|
||||||
} else {
|
|
||||||
let material_file_handle = asset_server.load_untyped(&material_info.path.clone()); // : Handle<Gltf>
|
|
||||||
let material_file_id = material_file_handle.id();
|
|
||||||
|
|
||||||
let asset_infos: Vec<AssetLoadTracker> = vec![AssetLoadTracker {
|
|
||||||
name: material_info.name.clone(),
|
|
||||||
path: material_info.path.clone(),
|
|
||||||
id: material_file_id,
|
|
||||||
loaded: false,
|
|
||||||
handle: material_file_handle.clone(),
|
|
||||||
}];
|
|
||||||
|
|
||||||
commands
|
|
||||||
.entity(entity)
|
|
||||||
.insert(BlueprintAssetsLoadState {
|
|
||||||
all_loaded: false,
|
|
||||||
asset_infos,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.insert(BlueprintMaterialAssetsNotLoaded);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO, merge with blueprints_check_assets_loading, make generic ?
|
|
||||||
pub(crate) fn check_for_material_loaded(
|
|
||||||
mut blueprint_assets_to_load: Query<
|
|
||||||
(Entity, &mut BlueprintAssetsLoadState),
|
|
||||||
With<BlueprintMaterialAssetsNotLoaded>,
|
|
||||||
>,
|
|
||||||
asset_server: Res<AssetServer>,
|
|
||||||
mut commands: Commands,
|
|
||||||
) {
|
|
||||||
for (entity, mut assets_to_load) in blueprint_assets_to_load.iter_mut() {
|
|
||||||
let mut all_loaded = true;
|
|
||||||
let mut loaded_amount = 0;
|
|
||||||
let total = assets_to_load.asset_infos.len();
|
|
||||||
for tracker in assets_to_load.asset_infos.iter_mut() {
|
|
||||||
let asset_id = tracker.id;
|
|
||||||
let loaded = asset_server.is_loaded_with_dependencies(asset_id);
|
|
||||||
tracker.loaded = loaded;
|
|
||||||
if loaded {
|
|
||||||
loaded_amount += 1;
|
|
||||||
} else {
|
|
||||||
all_loaded = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let progress: f32 = loaded_amount as f32 / total as f32;
|
|
||||||
assets_to_load.progress = progress;
|
|
||||||
|
|
||||||
if all_loaded {
|
|
||||||
assets_to_load.all_loaded = true;
|
|
||||||
commands
|
|
||||||
.entity(entity)
|
|
||||||
.insert(BlueprintMaterialAssetsLoaded)
|
|
||||||
.remove::<BlueprintMaterialAssetsNotLoaded>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// system that injects / replaces materials from material library
|
|
||||||
pub(crate) fn materials_inject2(
|
|
||||||
mut blenvy_config: ResMut<BlenvyConfig>,
|
mut blenvy_config: ResMut<BlenvyConfig>,
|
||||||
material_infos: Query<
|
material_infos: Query<
|
||||||
(&MaterialInfo, &Children),
|
(Entity, &MaterialInfo, &Children),
|
||||||
(
|
Without<MaterialProcessed>
|
||||||
|
// (With<BlueprintReadyForPostProcess>)
|
||||||
|
/*(
|
||||||
Added<BlueprintMaterialAssetsLoaded>,
|
Added<BlueprintMaterialAssetsLoaded>,
|
||||||
With<BlueprintMaterialAssetsLoaded>,
|
With<BlueprintMaterialAssetsLoaded>,
|
||||||
),
|
),*/
|
||||||
>,
|
>,
|
||||||
with_materials_and_meshes: Query<
|
with_materials_and_meshes: Query<
|
||||||
(),
|
(),
|
||||||
|
@ -142,7 +39,7 @@ pub(crate) fn materials_inject2(
|
||||||
|
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
) {
|
||||||
for (material_info, children) in material_infos.iter() {
|
for (entity, material_info, children) in material_infos.iter() {
|
||||||
let material_full_path = format!("{}#{}", material_info.path, material_info.name);
|
let material_full_path = format!("{}#{}", material_info.path, material_info.name);
|
||||||
let mut material_found: Option<&Handle<StandardMaterial>> = None;
|
let mut material_found: Option<&Handle<StandardMaterial>> = None;
|
||||||
|
|
||||||
|
@ -165,7 +62,7 @@ pub(crate) fn materials_inject2(
|
||||||
let material = mat_gltf
|
let material = mat_gltf
|
||||||
.named_materials
|
.named_materials
|
||||||
.get(&material_info.name as &str)
|
.get(&material_info.name as &str)
|
||||||
.expect("this material should have been loaded");
|
.expect("this material should have been loaded at this stage, please make sure you are correctly preloading them");
|
||||||
blenvy_config
|
blenvy_config
|
||||||
.materials_cache
|
.materials_cache
|
||||||
.insert(material_full_path, material.clone());
|
.insert(material_full_path, material.clone());
|
||||||
|
@ -173,10 +70,12 @@ pub(crate) fn materials_inject2(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commands.entity(entity).insert(MaterialProcessed);
|
||||||
|
|
||||||
if let Some(material) = material_found {
|
if let Some(material) = material_found {
|
||||||
for child in children.iter() {
|
for child in children.iter() {
|
||||||
if with_materials_and_meshes.contains(*child) {
|
if with_materials_and_meshes.contains(*child) {
|
||||||
debug!(
|
info!(
|
||||||
"injecting material {}, path: {:?}",
|
"injecting material {}, path: {:?}",
|
||||||
material_info.name,
|
material_info.name,
|
||||||
material_info.path.clone()
|
material_info.path.clone()
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
pub mod spawn_from_blueprints;
|
pub mod spawn_from_blueprints;
|
||||||
pub use spawn_from_blueprints::*;
|
pub use spawn_from_blueprints::*;
|
||||||
|
|
||||||
pub mod spawn_post_process;
|
|
||||||
pub(crate) use spawn_post_process::*;
|
|
||||||
|
|
||||||
pub mod animation;
|
pub mod animation;
|
||||||
pub use animation::*;
|
pub use animation::*;
|
||||||
|
|
||||||
|
@ -70,10 +67,38 @@ fn aabbs_enabled(blenvy_config: Res<BlenvyConfig>) -> bool {
|
||||||
blenvy_config.aabbs
|
blenvy_config.aabbs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hot_reload(watching_for_changes: Res<WatchingForChanges>) -> bool {
|
||||||
|
watching_for_changes.0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
trait BlenvyApp {
|
||||||
|
fn register_watching_for_changes(&mut self) -> &mut Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlenvyApp for App {
|
||||||
|
fn register_watching_for_changes(&mut self) -> &mut Self {
|
||||||
|
let asset_server = self
|
||||||
|
.world()
|
||||||
|
.get_resource::<AssetServer>()
|
||||||
|
.expect(ASSET_ERROR);
|
||||||
|
|
||||||
|
let watching_for_changes = asset_server.watching_for_changes();
|
||||||
|
self.insert_resource(WatchingForChanges(watching_for_changes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Resource, Default)]
|
||||||
|
pub(crate) struct WatchingForChanges(pub(crate) bool);
|
||||||
|
const ASSET_ERROR: &str = ""; // TODO
|
||||||
|
|
||||||
|
|
||||||
impl Plugin for BlueprintsPlugin {
|
impl Plugin for BlueprintsPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app
|
app
|
||||||
|
.register_watching_for_changes()
|
||||||
|
|
||||||
|
|
||||||
.register_type::<BlueprintInfo>()
|
.register_type::<BlueprintInfo>()
|
||||||
.register_type::<MaterialInfo>()
|
.register_type::<MaterialInfo>()
|
||||||
.register_type::<SpawnHere>()
|
.register_type::<SpawnHere>()
|
||||||
|
@ -94,7 +119,6 @@ impl Plugin for BlueprintsPlugin {
|
||||||
.add_event::<BlueprintEvent>()
|
.add_event::<BlueprintEvent>()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.register_type::<HashMap<String, Vec<String>>>()
|
.register_type::<HashMap<String, Vec<String>>>()
|
||||||
.configure_sets(
|
.configure_sets(
|
||||||
Update,
|
Update,
|
||||||
|
@ -111,32 +135,16 @@ impl Plugin for BlueprintsPlugin {
|
||||||
blueprints_scenes_spawned,
|
blueprints_scenes_spawned,
|
||||||
blueprints_transfer_components,
|
blueprints_transfer_components,
|
||||||
|
|
||||||
|
// post process
|
||||||
(compute_scene_aabbs, apply_deferred)
|
inject_materials,
|
||||||
.chain(),
|
compute_scene_aabbs,// .run_if(aabbs_enabled),
|
||||||
// .run_if(aabbs_enabled),
|
|
||||||
apply_deferred,
|
|
||||||
|
|
||||||
blueprints_finalize_instances,
|
blueprints_finalize_instances,
|
||||||
|
|
||||||
|
|
||||||
/*(
|
|
||||||
materials_inject,
|
|
||||||
check_for_material_loaded,
|
|
||||||
materials_inject2,
|
|
||||||
)
|
|
||||||
.chain()*/
|
|
||||||
)
|
)
|
||||||
.chain()
|
.chain()
|
||||||
.in_set(GltfBlueprintsSet::Spawn),
|
.in_set(GltfBlueprintsSet::Spawn),
|
||||||
)
|
)
|
||||||
/* .add_systems(
|
|
||||||
Update,
|
|
||||||
(spawned_blueprint_post_process, apply_deferred)
|
|
||||||
.chain()
|
|
||||||
.in_set(GltfBlueprintsSet::AfterSpawn),
|
|
||||||
)*/
|
|
||||||
|
|
||||||
/* .add_systems(
|
/* .add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
|
@ -144,9 +152,8 @@ impl Plugin for BlueprintsPlugin {
|
||||||
trigger_blueprint_animation_markers_events,
|
trigger_blueprint_animation_markers_events,
|
||||||
),
|
),
|
||||||
)*/
|
)*/
|
||||||
|
// hot reload
|
||||||
.add_systems(Update, react_to_asset_changes)
|
.add_systems(Update, react_to_asset_changes.run_if(hot_reload))
|
||||||
// .add_systems(Update, track_sub_blueprints)
|
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,8 +80,9 @@ pub enum BlueprintEvent {
|
||||||
},
|
},
|
||||||
|
|
||||||
///
|
///
|
||||||
Ready {
|
InstanceReady {
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
|
blueprint_name: String,
|
||||||
blueprint_path: String,
|
blueprint_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,12 +103,6 @@ pub struct DynamicBlueprintInstance;
|
||||||
pub struct BlueprintSpawning;
|
pub struct BlueprintSpawning;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Component, Reflect, Debug, Default)]
|
|
||||||
#[reflect(Component)]
|
|
||||||
/// component gets added when a blueprint spawning is done
|
|
||||||
pub struct BlueprintSpawned;
|
|
||||||
|
|
||||||
|
|
||||||
use gltf::Gltf as RawGltf;
|
use gltf::Gltf as RawGltf;
|
||||||
|
|
||||||
pub(crate) fn blueprints_prepare_spawn(
|
pub(crate) fn blueprints_prepare_spawn(
|
||||||
|
@ -388,26 +383,44 @@ pub struct BlueprintChildrenReady;
|
||||||
pub struct BlueprintReadyForPostProcess;
|
pub struct BlueprintReadyForPostProcess;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: disregard blueprints that have been spawned WAIT , we already have BlueprintSpawning
|
||||||
pub(crate) fn blueprints_scenes_spawned(
|
pub(crate) fn blueprints_scenes_spawned(
|
||||||
spawned_blueprint_scene_instances: Query<(Entity, Option<&Name>, Option<&Children>, Option<&SpawnTrackRoot>), (With<BlueprintSpawning>, Added<SceneInstance>)>,
|
spawned_blueprint_scene_instances: Query<(Entity, Option<&Name>, Option<&Children>, Option<&SpawnTrackRoot>), (With<BlueprintSpawning>, Added<SceneInstance>)>,
|
||||||
with_blueprint_infos : Query<(Entity, Option<&Name>), With<BlueprintInfo>>,
|
with_blueprint_infos : Query<(Entity, Option<&Name>), With<BlueprintInfo>>,
|
||||||
|
|
||||||
all_children: Query<&Children>,
|
all_children: Query<&Children>,
|
||||||
|
all_parents: Query<&Parent>,
|
||||||
|
|
||||||
mut sub_blueprint_trackers: Query<(Entity, &mut SubBlueprintsSpawnTracker, &BlueprintInfo)>,
|
mut sub_blueprint_trackers: Query<(Entity, &mut SubBlueprintsSpawnTracker, &BlueprintInfo)>,
|
||||||
|
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
|
|
||||||
|
all_names: Query<&Name>
|
||||||
|
|
||||||
) {
|
) {
|
||||||
for (entity, name, children, track_root) in spawned_blueprint_scene_instances.iter(){
|
for (entity, name, children, track_root) in spawned_blueprint_scene_instances.iter(){
|
||||||
info!("Done spawning blueprint scene for entity named {:?} (track root: {:?})", name, track_root);
|
info!("Done spawning blueprint scene for entity named {:?} (track root: {:?})", name, track_root);
|
||||||
let mut sub_blueprint_instances: Vec<Entity> = vec![];
|
let mut sub_blueprint_instances: Vec<Entity> = vec![];
|
||||||
|
let mut sub_blueprint_instance_names: Vec<Name> = vec![];
|
||||||
|
|
||||||
let mut tracker_data: HashMap<Entity, bool> = HashMap::new();
|
let mut tracker_data: HashMap<Entity, bool> = HashMap::new();
|
||||||
|
|
||||||
|
for parent in all_parents.iter_ancestors(entity) {
|
||||||
|
if with_blueprint_infos.get(parent).is_ok() {
|
||||||
|
|
||||||
|
println!("found a parent with blueprint_info {:?} for {:?}", all_names.get(parent), all_names.get(entity));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if children.is_some() {
|
if children.is_some() {
|
||||||
for child in all_children.iter_descendants(entity) {
|
for child in all_children.iter_descendants(entity) {
|
||||||
if with_blueprint_infos.get(child).is_ok() {
|
if with_blueprint_infos.get(child).is_ok() {
|
||||||
sub_blueprint_instances.push(child);
|
sub_blueprint_instances.push(child);
|
||||||
|
if let Ok(nname) = all_names.get(child) {
|
||||||
|
sub_blueprint_instance_names.push(nname.clone());
|
||||||
|
}
|
||||||
|
|
||||||
tracker_data.insert(child, false);
|
tracker_data.insert(child, false);
|
||||||
|
|
||||||
if track_root.is_some() {
|
if track_root.is_some() {
|
||||||
|
@ -424,7 +437,9 @@ pub(crate) fn blueprints_scenes_spawned(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("sub blueprint instances {:?}", sub_blueprint_instances);
|
|
||||||
|
|
||||||
|
println!("sub blueprint instances {:?}", sub_blueprint_instance_names);
|
||||||
|
|
||||||
// TODO: how about when no sub blueprints are present
|
// TODO: how about when no sub blueprints are present
|
||||||
if tracker_data.keys().len() > 0 {
|
if tracker_data.keys().len() > 0 {
|
||||||
|
@ -439,9 +454,7 @@ pub(crate) fn blueprints_scenes_spawned(
|
||||||
// could be done differently, by notifying each parent of a spawning blueprint that this child is done spawning ?
|
// could be done differently, by notifying each parent of a spawning blueprint that this child is done spawning ?
|
||||||
// perhaps using component hooks or observers (ie , if a ComponentSpawning + Parent)
|
// perhaps using component hooks or observers (ie , if a ComponentSpawning + Parent)
|
||||||
|
|
||||||
use crate::{
|
use crate:: CopyComponents;
|
||||||
CopyComponents,
|
|
||||||
};
|
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
|
||||||
|
|
||||||
|
@ -501,7 +514,6 @@ pub(crate) fn blueprints_transfer_components(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
commands.entity(original)
|
commands.entity(original)
|
||||||
.insert(BlueprintReadyForPostProcess); // Tag the entity so any systems dealing with post processing can now it is now their "turn"
|
.insert(BlueprintReadyForPostProcess); // Tag the entity so any systems dealing with post processing can now it is now their "turn"
|
||||||
// commands.entity(original).remove::<Handle<Scene>>(); // FIXME: if we delete the handle to the scene, things get despawned ! not what we want
|
// commands.entity(original).remove::<Handle<Scene>>(); // FIXME: if we delete the handle to the scene, things get despawned ! not what we want
|
||||||
|
@ -513,7 +525,8 @@ pub(crate) fn blueprints_transfer_components(
|
||||||
// now check if the current entity is a child blueprint instance of another entity
|
// now check if the current entity is a child blueprint instance of another entity
|
||||||
// this should always be done last, as children should be finished before the parent can be processed correctly
|
// this should always be done last, as children should be finished before the parent can be processed correctly
|
||||||
if let Some(track_root) = track_root {
|
if let Some(track_root) = track_root {
|
||||||
// println!("got some root {:?}", root_name);
|
let root_name = all_names.get(track_root.0);
|
||||||
|
println!("got some root {:?}", root_name);
|
||||||
if let Ok((s_entity, mut tracker, bp_info)) = sub_blueprint_trackers.get_mut(track_root.0) {
|
if let Ok((s_entity, mut tracker, bp_info)) = sub_blueprint_trackers.get_mut(track_root.0) {
|
||||||
tracker.sub_blueprint_instances.entry(original).or_insert(true);
|
tracker.sub_blueprint_instances.entry(original).or_insert(true);
|
||||||
tracker.sub_blueprint_instances.insert(original, true);
|
tracker.sub_blueprint_instances.insert(original, true);
|
||||||
|
@ -535,44 +548,49 @@ pub(crate) fn blueprints_transfer_components(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Component, Reflect, Debug)]
|
#[derive(Component, Reflect, Debug)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct BlueprintReadyForFinalizing;
|
pub struct BlueprintReadyForFinalizing;
|
||||||
|
|
||||||
pub(crate) fn blueprints_finalize_instances(
|
pub(crate) fn blueprints_finalize_instances(
|
||||||
blueprint_instances: Query<(Entity, Option<&Name>), (With<BlueprintSpawning>, With<BlueprintReadyForFinalizing>)>,
|
blueprint_instances: Query<(Entity, Option<&Name>, &BlueprintInfo), (With<BlueprintSpawning>, With<BlueprintReadyForFinalizing>)>,
|
||||||
|
mut blueprint_events: EventWriter<BlueprintEvent>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
) {
|
||||||
for (entity, name) in blueprint_instances.iter() {
|
for (entity, name, blueprint_info) in blueprint_instances.iter() {
|
||||||
info!("Finalizing blueprint instance {:?}", name);
|
info!("Finalizing blueprint instance {:?}", name);
|
||||||
commands.entity(entity)
|
commands.entity(entity)
|
||||||
.remove::<SpawnHere>()
|
.remove::<SpawnHere>()
|
||||||
.remove::<BlueprintSpawning>()
|
.remove::<BlueprintSpawning>()
|
||||||
.insert(BlueprintSpawned)
|
.remove::<BlueprintReadyForPostProcess>()
|
||||||
|
.insert(BlueprintInstanceReady)
|
||||||
.insert(Visibility::Visible)
|
.insert(Visibility::Visible)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
blueprint_events.send(BlueprintEvent::InstanceReady {entity: entity, blueprint_name: blueprint_info.name.clone(), blueprint_path: blueprint_info.path.clone()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
=> annoying issue with the "nested" useless root node created by blender
|
||||||
|
=> distinguish between blueprint instances inside blueprint instances vs blueprint instances inside blueprints ??
|
||||||
|
|
||||||
BlueprintSpawning
|
BlueprintSpawning
|
||||||
- Blueprint Load Assets
|
- Blueprint Load Assets
|
||||||
- Blueprint Assets Ready: spawn Blueprint's scene
|
- Blueprint Assets Ready: spawn Blueprint's scene
|
||||||
- Blueprint Scene Ready:
|
- Blueprint Scene Ready (SceneInstance component is present):
|
||||||
- get list of sub Blueprints if any, inject blueprints spawn tracker
|
- get list of sub Blueprints if any, inject sub blueprints spawn tracker
|
||||||
=> annoying issue with the "nested" useless root node created by blender
|
- Blueprint copy components to original entity, remove useless nodes
|
||||||
=> distinguish between blueprint instances inside blueprint instances vs blueprint instances inside blueprints ??
|
- Blueprint post process
|
||||||
- Blueprint sub_blueprints Ready
|
|
||||||
if all children are ready
|
|
||||||
|
|
||||||
- Blueprints post process
|
|
||||||
- generate aabb (need full hierarchy in its final form)
|
- generate aabb (need full hierarchy in its final form)
|
||||||
- materials ?
|
- inject materials from library if needed
|
||||||
|
- Blueprint Ready
|
||||||
|
- bubble information up to parent blueprint instance
|
||||||
|
- if all sub_blueprints are ready => Parent blueprint Instance is ready
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// HOT RELOAD
|
// HOT RELOAD
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -215,12 +215,17 @@ Blender side:
|
||||||
Bevy Side:
|
Bevy Side:
|
||||||
- [x] deprecate BlueprintName & BlueprintPath & use BlueprintInfo instead
|
- [x] deprecate BlueprintName & BlueprintPath & use BlueprintInfo instead
|
||||||
- [ ] make blueprint instances invisible until spawning is done to avoid "spawn flash"?
|
- [ ] make blueprint instances invisible until spawning is done to avoid "spawn flash"?
|
||||||
- [ ] should "blueprint spawned" only be triggered after all its sub blueprints have spawned ?
|
- [ ] restructure blueprint spawning
|
||||||
- [ ] "blueprintInstance ready"/finished
|
- [x] "blueprint ready" only be triggered after all its sub blueprints are ready
|
||||||
|
- [x] "blueprintInstance ready"/finished
|
||||||
BlueprintAssetsLoaded
|
BlueprintAssetsLoaded
|
||||||
BlueprintSceneSpawned
|
BlueprintSceneSpawned
|
||||||
BlueprintChildrenReady
|
BlueprintChildrenReady
|
||||||
BlueprintReadyForPostProcess
|
BlueprintReadyForPostProcess
|
||||||
|
- [ ] fix issues with deeply nested blueprints
|
||||||
|
- perhaps reverse logic by using iter_ascendants
|
||||||
|
- [x] fix materials handling
|
||||||
|
- [ ] fix animations handling
|
||||||
|
|
||||||
- [ ] simplify testing example:
|
- [ ] simplify testing example:
|
||||||
- [x] remove use of rapier physics (or even the whole common boilerplate ?)
|
- [x] remove use of rapier physics (or even the whole common boilerplate ?)
|
||||||
|
|
|
@ -122,9 +122,9 @@ def test_export_complex(setup_data):
|
||||||
user_asset.path = "audio/fake.mp3"
|
user_asset.path = "audio/fake.mp3"
|
||||||
|
|
||||||
# we have to cheat, since we cannot rely on the data injected when saving the library file (since we are not saving it as part of the tests)
|
# we have to cheat, since we cannot rely on the data injected when saving the library file (since we are not saving it as part of the tests)
|
||||||
bpy.data.collections["External_blueprint"]["export_path"] = "blueprints/External_blueprint.glb"
|
#bpy.data.collections["External_blueprint"]["export_path"] = "blueprints/External_blueprint.glb"
|
||||||
bpy.data.collections["External_blueprint2"]["export_path"] = "blueprints/External_blueprint2.glb"
|
#bpy.data.collections["External_blueprint2"]["export_path"] = "blueprints/External_blueprint2.glb"
|
||||||
bpy.data.collections["External_blueprint3"]["export_path"] = "blueprints/External_blueprint3.glb"
|
#bpy.data.collections["External_blueprint3"]["export_path"] = "blueprints/External_blueprint3.glb"
|
||||||
|
|
||||||
# do the actual exporting
|
# do the actual exporting
|
||||||
prepare_and_export()
|
prepare_and_export()
|
||||||
|
|
|
@ -106,7 +106,7 @@ def test_export_complex(setup_data):
|
||||||
blenvy.auto_export.auto_export = True
|
blenvy.auto_export.auto_export = True
|
||||||
blenvy.auto_export.export_scene_settings = True
|
blenvy.auto_export.export_scene_settings = True
|
||||||
blenvy.auto_export.export_blueprints = True
|
blenvy.auto_export.export_blueprints = True
|
||||||
#blenvy.auto_export.export_materials_library = True
|
blenvy.auto_export.export_materials_library = True
|
||||||
|
|
||||||
bpy.data.scenes['World'].blenvy_scene_type = 'Level' # set scene as main/level scene
|
bpy.data.scenes['World'].blenvy_scene_type = 'Level' # set scene as main/level scene
|
||||||
bpy.data.scenes['Library'].blenvy_scene_type = 'Library' # set scene as Library scene
|
bpy.data.scenes['Library'].blenvy_scene_type = 'Library' # set scene as Library scene
|
||||||
|
|
Loading…
Reference in New Issue