diff --git a/src/core/entity_handle.rs b/src/core/entity_handle.rs index c6dd4be..e14511f 100644 --- a/src/core/entity_handle.rs +++ b/src/core/entity_handle.rs @@ -1,3 +1,6 @@ +use std::ops::Deref; +use std::sync::Arc; + use bevy::prelude::*; use super::bevy_channel::{BevyChannel, BevyChannelReader}; @@ -16,16 +19,28 @@ fn despawn(mut cmds: Commands, mut reader: ResMut>) { } } +#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone)] +pub struct EntityHandle(Arc); +impl EntityHandle { + pub fn get(&self) -> Entity { + self.0.0 + } + pub fn new(entity: Entity) -> Self { + Self(EntityHandleInner(entity).into()) + } +} +impl Deref for EntityHandle { + type Target = Entity; + + fn deref(&self) -> &Self::Target { + &self.0.0 + } +} static DESTROY: BevyChannel = BevyChannel::new(); -#[derive(Deref, DerefMut, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct EntityHandle(pub Entity); -impl Drop for EntityHandle { +#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct EntityHandleInner(Entity); +impl Drop for EntityHandleInner { fn drop(&mut self) { DESTROY.send(self.0); } } -impl From for EntityHandle { - fn from(value: Entity) -> Self { - Self(value) - } -} diff --git a/src/nodes/audio.rs b/src/nodes/audio.rs index 7373093..50bdf37 100644 --- a/src/nodes/audio.rs +++ b/src/nodes/audio.rs @@ -73,10 +73,11 @@ fn update_sound_event( }, )) .id(); - sound.spatial.set_entity(entity); - sound.entity.set(entity.into()).unwrap(); + let entity = EntityHandle::new(entity); + sound.spatial.set_entity(entity.clone()); + sound.entity.set(entity).unwrap(); } - if let Some(sink) = sound.entity.get().and_then(|e| sinks.get(e.0).ok()) { + if let Some(sink) = sound.entity.get().and_then(|e| sinks.get(e.get()).ok()) { if sound.play.lock().take().is_some() { sink.play(); } diff --git a/src/nodes/drawable/lines.rs b/src/nodes/drawable/lines.rs index 1b4b700..ff21205 100644 --- a/src/nodes/drawable/lines.rs +++ b/src/nodes/drawable/lines.rs @@ -257,7 +257,7 @@ fn build_line_mesh( extension: LineExtension {}, })), )); - _ = lines.entity.set(e.id().into()); + _ = lines.entity.set(EntityHandle::new(e.id())); e } }; diff --git a/src/nodes/drawable/model.rs b/src/nodes/drawable/model.rs index b517c5d..54a615b 100644 --- a/src/nodes/drawable/model.rs +++ b/src/nodes/drawable/model.rs @@ -107,7 +107,10 @@ fn load_models( Visibility::Hidden, )) .id(); - model.bevy_scene_entity.set(entity.into()).unwrap(); + model + .bevy_scene_entity + .set(EntityHandle::new(entity)) + .unwrap(); } } @@ -144,7 +147,7 @@ fn apply_materials( for (param_name, param) in model_part.pending_material_parameters.lock().drain() { let mut new_mat = materials.get(&mesh_mat.0).unwrap().clone(); param.apply_to_material( - &model_part.space.node().unwrap().get_client().unwrap(), + &model_part.spatial.node().unwrap().get_client().unwrap(), &mut new_mat, ¶m_name, &asset_server, @@ -193,7 +196,7 @@ fn gen_model_parts( .unwrap_or_else(|| name.to_string()); let parent_spatial = parent .as_ref() - .map(|p| p.space.clone()) + .map(|p| p.spatial.clone()) .unwrap_or_else(|| model.spatial.clone()); let client = model.spatial.node()?.get_client()?; let (spatial, model_part) = @@ -211,8 +214,7 @@ fn gen_model_parts( entity: OnceLock::new(), mesh_entity: OnceLock::new(), path, - space: spatial.clone(), - _model: Arc::downgrade(&model), + spatial: spatial.clone(), pending_material_parameters: Mutex::default(), pending_material_replacement: Mutex::default(), holdout: AtomicBool::new(false), @@ -222,8 +224,8 @@ fn gen_model_parts( (spatial, model_part) } Some(part) => { - part.space.set_spatial_parent(&parent_spatial).unwrap(); - (part.space.clone(), part.clone()) + part.spatial.set_spatial_parent(&parent_spatial).unwrap(); + (part.spatial.clone(), part.clone()) } }; let aabb = Aabb::enclosing( @@ -247,8 +249,8 @@ fn gen_model_parts( }); let _ = spatial.set_spatial_parent(&parent_spatial); spatial.set_local_transform(transform.compute_matrix()); - - spatial.set_entity(entity); + let entity_handle = EntityHandle::new(entity); + spatial.set_entity(entity_handle.clone()); cmds.entity(entity) .insert(SpatialNode(Arc::downgrade(&spatial))); let mesh_entity = children_query @@ -257,17 +259,18 @@ fn gen_model_parts( .flat_map(|v| v.iter()) .find(|e| has_mesh.get(*e).unwrap_or(false))?; _ = model_part.bounds.set(aabb); - _ = model_part.entity.set(entity.into()); - _ = model_part.mesh_entity.set(mesh_entity.into()); + _ = model_part.entity.set(entity_handle); + _ = model_part.mesh_entity.set(EntityHandle::new(mesh_entity)); parts.push(model_part.clone()); Some(model_part) }, ); } _ = model.parts.set(parts); + model.pre_bound_parts.lock().clear(); model .spatial - .set_entity(model.bevy_scene_entity.get().unwrap().0); + .set_entity(model.bevy_scene_entity.get().unwrap().clone()); } } @@ -324,8 +327,6 @@ impl HashedPbrMaterial { mat.emissive_texture.hash(state); mat.metallic_roughness_texture.hash(state); mat.occlusion_texture.hash(state); - // should always be the same, TODO: make the spherical harmonics buffer a per mesh instance thing - // mat.spherical_harmonics.hash(state); } } fn hash_color(color: Color, state: &mut H) { @@ -463,8 +464,7 @@ pub struct ModelPart { entity: OnceLock, mesh_entity: OnceLock, path: String, - space: Arc, - _model: Weak, + spatial: Arc, pending_material_parameters: Mutex>, pending_material_replacement: Mutex>>, holdout: AtomicBool, @@ -591,8 +591,7 @@ impl Model { entity: OnceLock::new(), mesh_entity: OnceLock::new(), path: part_path, - space: spatial, - _model: Arc::downgrade(self), + spatial, pending_material_parameters: Mutex::default(), pending_material_replacement: Mutex::default(), holdout: AtomicBool::new(false), @@ -617,7 +616,7 @@ impl ModelAspect for Model { let model = node.get_aspect::()?; let part = model.get_model_part(part_path)?; Alias::create_with_id( - &part.space.node().unwrap(), + &part.spatial.node().unwrap(), &calling_client, id, MODEL_PART_ASPECT_ALIAS_INFO.clone(), @@ -628,6 +627,11 @@ impl ModelAspect for Model { } impl Drop for Model { fn drop(&mut self) { + for p in self.parts.get().unwrap().iter() { + if let Some(node) = p.spatial.node() { + node.destroy(); + } + } MODEL_REGISTRY.remove(self); } } diff --git a/src/nodes/drawable/text.rs b/src/nodes/drawable/text.rs index 6fc0852..f5af010 100644 --- a/src/nodes/drawable/text.rs +++ b/src/nodes/drawable/text.rs @@ -152,7 +152,8 @@ fn spawn_text( )) .add_children(&letters) .id(); - text.entity.lock().replace(EntityHandle(entity)); + let entity = EntityHandle::new(entity); + text.entity.lock().replace(entity.clone()); text.spatial.set_entity(entity); } } diff --git a/src/nodes/spatial/mod.rs b/src/nodes/spatial/mod.rs index 5f29227..f691d7d 100644 --- a/src/nodes/spatial/mod.rs +++ b/src/nodes/spatial/mod.rs @@ -49,7 +49,7 @@ fn spawn_spatial_nodes(mut cmds: Commands) { let entity = cmds .spawn((SpatialNode(Arc::downgrade(&spatial)), Name::new("Spatial"))) .id(); - spatial.set_entity(entity); + spatial.set_entity(EntityHandle::new(entity)); } } @@ -160,15 +160,15 @@ impl Spatial { spatial.mark_dirty(); spatial } - pub fn set_entity(&self, entity: Entity) { - self.entity.write().replace(entity.into()); + pub fn set_entity(&self, entity: EntityHandle) { + self.entity.write().replace(entity); self.mark_dirty(); for child in self.children.get_valid_contents() { child.mark_dirty(); } } pub fn get_entity(&self) -> Option { - self.entity.read().as_ref().map(|v| v.0) + self.entity.read().as_ref().map(|v| v.get()) } pub fn add_to( node: &Arc, @@ -222,7 +222,7 @@ impl Spatial { bounds } pub(super) fn mark_dirty(&self) { - let Some(entity) = self.entity.read().as_ref().map(|v| v.0) else { + let Some(entity) = self.entity.read().as_ref().map(|v| v.get()) else { return; }; let enabled = self @@ -232,7 +232,7 @@ impl Spatial { let transform = enabled.then(|| BevyTransform::from_matrix(self.local_transform())); let parent = self .get_parent() - .and_then(|v| v.entity.read().as_ref().map(|v| v.0)); + .and_then(|v| v.entity.read().as_ref().map(|v| v.get())); UPDATED_SPATIALS_NODES .lock() .insert(entity, (transform, parent));