Add asset removal. Clean up old/removed meshes

This commit is contained in:
Carter Anderson 2020-05-17 18:48:14 -07:00
parent 86c18edbfd
commit 33d4d5f562
6 changed files with 104 additions and 29 deletions

View file

@ -1,19 +1,23 @@
use crate::{
update_asset_storage_system, AssetChannel, AssetLoader, AssetServer, ChannelAssetHandler,
Handle, HandleId, DEFAULT_HANDLE_ID,
Handle, HandleId,
};
use bevy_app::{stage, AppBuilder, Events};
use bevy_core::bytes::GetBytes;
use legion::prelude::*;
use std::{path::{Path, PathBuf}, collections::HashMap};
use std::{
collections::HashMap,
path::{Path, PathBuf},
};
pub enum AssetEvent<T> {
Created { handle: Handle<T> },
Modified { handle: Handle<T> },
Removed { handle: Handle<T> },
}
pub struct Assets<T> {
assets: HashMap<HandleId, T>,
assets: HashMap<Handle<T>, T>,
paths: HashMap<PathBuf, Handle<T>>,
events: Events<AssetEvent<T>>,
}
@ -34,16 +38,15 @@ impl<T> Assets<T> {
}
pub fn add(&mut self, asset: T) -> Handle<T> {
let id = HandleId::new();
self.assets.insert(id, asset);
let handle = Handle::from_id(id);
let handle = Handle::new();
self.assets.insert(handle, asset);
self.events.send(AssetEvent::Created { handle });
handle
}
pub fn set(&mut self, handle: Handle<T>, asset: T) {
let exists = self.assets.contains_key(&handle.id);
self.assets.insert(handle.id, asset);
let exists = self.assets.contains_key(&handle);
self.assets.insert(handle, asset);
if exists {
self.events.send(AssetEvent::Modified { handle });
@ -53,9 +56,9 @@ impl<T> Assets<T> {
}
pub fn add_default(&mut self, asset: T) -> Handle<T> {
let exists = self.assets.contains_key(&DEFAULT_HANDLE_ID);
self.assets.insert(DEFAULT_HANDLE_ID, asset);
let handle = Handle::default();
let exists = self.assets.contains_key(&handle);
self.assets.insert(handle, asset);
if exists {
self.events.send(AssetEvent::Modified { handle });
} else {
@ -69,27 +72,44 @@ impl<T> Assets<T> {
}
pub fn get_id(&self, id: HandleId) -> Option<&T> {
self.assets.get(&id)
self.assets.get(&Handle::from_id(id))
}
pub fn get_id_mut(&mut self, id: HandleId) -> Option<&mut T> {
self.assets.get_mut(&id)
self.assets.get_mut(&Handle::from_id(id))
}
pub fn get(&self, handle: &Handle<T>) -> Option<&T> {
self.assets.get(&handle.id)
self.assets.get(&handle)
}
pub fn get_mut(&mut self, handle: &Handle<T>) -> Option<&mut T> {
self.assets.get_mut(&handle.id)
self.assets.get_mut(&handle)
}
pub fn get_or_insert_with(&mut self, handle: Handle<T>, insert_fn: impl FnOnce() -> T) -> &mut T {
self.assets.entry(handle.id).or_insert_with(insert_fn)
pub fn get_or_insert_with(
&mut self,
handle: Handle<T>,
insert_fn: impl FnOnce() -> T,
) -> &mut T {
let mut event = None;
let borrowed = self.assets.entry(handle).or_insert_with(|| {
event = Some(AssetEvent::Created { handle });
insert_fn()
});
if let Some(event) = event {
self.events.send(event);
}
borrowed
}
pub fn iter(&self) -> impl Iterator<Item = (Handle<T>, &T)> {
self.assets.iter().map(|(k, v)| (Handle::from_id(*k), v))
self.assets.iter().map(|(k, v)| (*k, v))
}
pub fn remove(&mut self, handle: &Handle<T>) -> Option<T> {
self.assets.remove(&handle)
}
pub fn asset_event_system(

View file

@ -4,7 +4,7 @@ use crate::{
VertexBufferDescriptor, VertexBufferDescriptors, VertexFormat,
},
render_resource::{BufferInfo, BufferUsage},
renderer::RenderResources,
renderer::{RenderResourceContext, RenderResources},
shader::AsUniforms,
Renderable, Vertex,
};
@ -320,6 +320,20 @@ pub mod shape {
}
}
fn remove_current_mesh_resources(
render_resources: &dyn RenderResourceContext,
handle: Handle<Mesh>,
) {
if let Some(resource) = render_resources.get_asset_resource(handle, VERTEX_BUFFER_ASSET_INDEX) {
render_resources.remove_buffer(resource);
render_resources.remove_asset_resource(handle, VERTEX_BUFFER_ASSET_INDEX);
}
if let Some(resource) = render_resources.get_asset_resource(handle, INDEX_BUFFER_ASSET_INDEX) {
render_resources.remove_buffer(resource);
render_resources.remove_asset_resource(handle, INDEX_BUFFER_ASSET_INDEX);
}
}
pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Schedulable> {
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
let mesh_events = resources.get::<Events<AssetEvent<Mesh>>>().unwrap();
@ -333,18 +347,26 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Sched
.read_resource::<Events<AssetEvent<Mesh>>>()
.with_query(<(Read<Handle<Mesh>>, Write<Renderable>)>::query())
.build(
move |_, world, (render_resource_context, meshes, mesh_events), query| {
let render_resources = &*render_resource_context.context;
let changed_meshes = mesh_event_reader
.iter(&mesh_events)
.map(|e| match e {
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
Some(handle)
move |_, world, (render_resources, meshes, mesh_events), query| {
let render_resources = &*render_resources.context;
let mut changed_meshes = HashSet::new();
for event in mesh_event_reader.iter(&mesh_events) {
match event {
AssetEvent::Created { handle } => {
changed_meshes.insert(*handle);
}
})
.filter(|h| h.is_some())
.map(|h| *h.unwrap())
.collect::<HashSet<Handle<Mesh>>>();
AssetEvent::Modified { handle } => {
changed_meshes.insert(*handle);
remove_current_mesh_resources(render_resources, *handle);
}
AssetEvent::Removed { handle } => {
remove_current_mesh_resources(render_resources, *handle);
// if mesh was modified and removed in the same update, ignore the modification
// events are ordered so future modification events are ok
changed_meshes.remove(handle);
}
}
}
for changed_mesh_handle in changed_meshes.iter() {
if let Some(mesh) = meshes.get(changed_mesh_handle) {

View file

@ -125,4 +125,13 @@ impl RenderResourceContext for HeadlessRenderResourceContext {
}
}
fn create_shader_module_from_source(&self, _shader_handle: Handle<Shader>, _shader: &Shader) {}
fn remove_asset_resource_untyped(
&self,
handle: HandleUntyped,
index: usize) {
self.asset_resources
.write()
.unwrap()
.remove(&(handle, index));
}
}

View file

@ -61,6 +61,10 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
handle: HandleUntyped,
index: usize,
) -> Option<RenderResource>;
fn remove_asset_resource_untyped(
&self,
handle: HandleUntyped,
index: usize);
fn create_render_pipeline(
&self,
pipeline_handle: Handle<PipelineDescriptor>,
@ -101,6 +105,12 @@ impl dyn RenderResourceContext {
{
self.get_asset_resource_untyped(handle.into(), index)
}
pub fn remove_asset_resource<T>(&self, handle: Handle<T>, index: usize)
where
T: 'static,
{
self.remove_asset_resource_untyped(handle.into(), index);
}
}
impl_downcast!(RenderResourceContext);

View file

@ -366,6 +366,15 @@ impl RenderResourceContext for WgpuRenderResourceContext {
asset_resources.get(&(handle, index)).cloned()
}
fn remove_asset_resource_untyped(
&self,
handle: HandleUntyped,
index: usize,
) {
let mut asset_resources = self.resources.asset_resources.write().unwrap();
asset_resources.remove(&(handle, index));
}
fn create_render_pipeline(
&self,
pipeline_handle: Handle<PipelineDescriptor>,

View file

@ -6,7 +6,12 @@ use bevy::{
fn main() {
App::build()
.add_default_plugins()
// Adds frame time diagnostics
.add_plugin(FrameTimeDiagnosticsPlugin::default())
// Adds a system that prints diagnostics to the console
.add_plugin(PrintDiagnosticsPlugin::default())
// Any plugin can register diagnostics
// Uncomment this to add some render resource diagnostics:
// .add_plugin(bevy::wgpu::diagnostic::WgpuResourceDiagnosticsPlugin::default())
.run();
}