From eeaab0ebed3e9656483c110b0afeeb39fc720846 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Tue, 23 Apr 2019 13:55:48 +0200 Subject: [PATCH] Clean up figure cache models when necessary Former-commit-id: 7653217b2f4c02f5c179e35907fa47c3526b2a2e --- voxygen/src/scene/figure.rs | 87 ++++++++++++++++++++++--------------- voxygen/src/scene/mod.rs | 5 ++- voxygen/src/session.rs | 2 +- 3 files changed, 57 insertions(+), 37 deletions(-) diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index e41acc8d81..985e1746a0 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -48,7 +48,7 @@ use crate::{ }; pub struct FigureCache { - models: HashMap>, + models: HashMap, u64)>, states: HashMap>, } @@ -61,41 +61,56 @@ impl FigureCache { } pub fn get_or_create_model<'a>( - models: &'a mut HashMap>, + models: &'a mut HashMap, u64)>, renderer: &mut Renderer, + tick: u64, character: Character) - -> &'a Model { - models.entry(character).or_insert_with(|| { - let bone_meshes = [ - Some(Self::load_head(character.head)), - Some(Self::load_chest(character.chest)), - Some(Self::load_belt(character.belt)), - Some(Self::load_pants(character.pants)), - Some(Self::load_left_hand(character.hand)), - Some(Self::load_right_hand(character.hand)), - Some(Self::load_left_foot(character.foot)), - Some(Self::load_right_foot(character.foot)), - Some(Self::load_weapon(character.weapon)), - None, - None, - None, - None, - None, - None, - None, - ]; + -> &'a (Model, u64) { + match models.get_mut(&character) { + Some((model, last_used)) => { + *last_used = tick; + } + None => { + models.insert(character, ({ + let bone_meshes = [ + Some(Self::load_head(character.head)), + Some(Self::load_chest(character.chest)), + Some(Self::load_belt(character.belt)), + Some(Self::load_pants(character.pants)), + Some(Self::load_left_hand(character.hand)), + Some(Self::load_right_hand(character.hand)), + Some(Self::load_left_foot(character.foot)), + Some(Self::load_right_foot(character.foot)), + Some(Self::load_weapon(character.weapon)), + None, + None, + None, + None, + None, + None, + None, + ]; - let mut mesh = Mesh::new(); - bone_meshes - .iter() - .enumerate() - .filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm))) - .for_each(|(i, bone_mesh)| { - mesh.push_mesh_map(bone_mesh, |vert| vert.with_bone_idx(i as u8)) - }); + let mut mesh = Mesh::new(); + bone_meshes + .iter() + .enumerate() + .filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm))) + .for_each(|(i, bone_mesh)| { + mesh.push_mesh_map(bone_mesh, |vert| vert.with_bone_idx(i as u8)) + }); - renderer.create_model(&mesh).unwrap() - }) + renderer.create_model(&mesh).unwrap() + }, tick)); + } + } + + &models[&character] + } + + pub fn clean(&mut self, tick: u64) { + // TODO: Don't hard-code this + self.models.retain(|_, (_, last_used)| *last_used + 60 > tick); } fn load_mesh(filename: &'static str, position: Vec3) -> Mesh { @@ -191,17 +206,19 @@ impl FigureCache { self.states.retain(|entity, _| ecs.entities().is_alive(*entity)); } - pub fn render(&mut self, renderer: &mut Renderer, client: &Client, globals: &Consts) { + pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client, globals: &Consts) { + let tick = client.get_tick(); let ecs = client.state().ecs(); let models = &mut self.models; + for (entity, &character) in ( &ecs.entities(), &ecs.read_storage::(), ).join() { - let model = Self::get_or_create_model(models, renderer, character); + let model = Self::get_or_create_model(models, renderer, tick, character); let state = self.states.get(&entity).unwrap(); renderer.render_figure( - model, + &model.0, globals, &state.locals, &state.bone_consts, diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 0fd74edb59..8fa60f65c3 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -139,10 +139,13 @@ impl Scene { // Maintain the figures self.figure_cache.maintain(renderer, client); + + // Remove unused figures + self.figure_cache.clean(client.get_tick()); } /// Render the scene using the provided `Renderer` - pub fn render(&mut self, renderer: &mut Renderer, client: &Client) { + pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client) { // Render the skybox first (it appears over everything else so must be rendered first) renderer.render_skybox( &self.skybox.model, diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index df0e014bf8..64273e57c4 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -87,7 +87,7 @@ impl SessionState { renderer.clear(BG_COLOR); // Render the screen using the global renderer - self.scene.render(renderer, &self.client.borrow()); + self.scene.render(renderer, &mut self.client.borrow_mut()); // Draw the UI to the screen self.hud.render(renderer);