Clean up figure cache models when necessary

Former-commit-id: 7653217b2f4c02f5c179e35907fa47c3526b2a2e
This commit is contained in:
timokoesters 2019-04-23 13:55:48 +02:00
parent df7a145bbc
commit 7baecff1f0
3 changed files with 57 additions and 37 deletions

View File

@ -48,7 +48,7 @@ use crate::{
}; };
pub struct FigureCache { pub struct FigureCache {
models: HashMap<Character, Model<FigurePipeline>>, models: HashMap<Character, (Model<FigurePipeline>, u64)>,
states: HashMap<EcsEntity, FigureState<CharacterSkeleton>>, states: HashMap<EcsEntity, FigureState<CharacterSkeleton>>,
} }
@ -61,41 +61,56 @@ impl FigureCache {
} }
pub fn get_or_create_model<'a>( pub fn get_or_create_model<'a>(
models: &'a mut HashMap<Character, Model<FigurePipeline>>, models: &'a mut HashMap<Character, (Model<FigurePipeline>, u64)>,
renderer: &mut Renderer, renderer: &mut Renderer,
tick: u64,
character: Character) character: Character)
-> &'a Model<FigurePipeline> { -> &'a (Model<FigurePipeline>, u64) {
models.entry(character).or_insert_with(|| { match models.get_mut(&character) {
let bone_meshes = [ Some((model, last_used)) => {
Some(Self::load_head(character.head)), *last_used = tick;
Some(Self::load_chest(character.chest)), }
Some(Self::load_belt(character.belt)), None => {
Some(Self::load_pants(character.pants)), models.insert(character, ({
Some(Self::load_left_hand(character.hand)), let bone_meshes = [
Some(Self::load_right_hand(character.hand)), Some(Self::load_head(character.head)),
Some(Self::load_left_foot(character.foot)), Some(Self::load_chest(character.chest)),
Some(Self::load_right_foot(character.foot)), Some(Self::load_belt(character.belt)),
Some(Self::load_weapon(character.weapon)), Some(Self::load_pants(character.pants)),
None, Some(Self::load_left_hand(character.hand)),
None, Some(Self::load_right_hand(character.hand)),
None, Some(Self::load_left_foot(character.foot)),
None, Some(Self::load_right_foot(character.foot)),
None, Some(Self::load_weapon(character.weapon)),
None, None,
None, None,
]; None,
None,
None,
None,
None,
];
let mut mesh = Mesh::new(); let mut mesh = Mesh::new();
bone_meshes bone_meshes
.iter() .iter()
.enumerate() .enumerate()
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm))) .filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
.for_each(|(i, bone_mesh)| { .for_each(|(i, bone_mesh)| {
mesh.push_mesh_map(bone_mesh, |vert| vert.with_bone_idx(i as u8)) 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<f32>) -> Mesh<FigurePipeline> { fn load_mesh(filename: &'static str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
@ -191,17 +206,19 @@ impl FigureCache {
self.states.retain(|entity, _| ecs.entities().is_alive(*entity)); self.states.retain(|entity, _| ecs.entities().is_alive(*entity));
} }
pub fn render(&mut self, renderer: &mut Renderer, client: &Client, globals: &Consts<Globals>) { pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client, globals: &Consts<Globals>) {
let tick = client.get_tick();
let ecs = client.state().ecs(); let ecs = client.state().ecs();
let models = &mut self.models; let models = &mut self.models;
for (entity, &character) in ( for (entity, &character) in (
&ecs.entities(), &ecs.entities(),
&ecs.read_storage::<comp::Character>(), &ecs.read_storage::<comp::Character>(),
).join() { ).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(); let state = self.states.get(&entity).unwrap();
renderer.render_figure( renderer.render_figure(
model, &model.0,
globals, globals,
&state.locals, &state.locals,
&state.bone_consts, &state.bone_consts,

View File

@ -139,10 +139,13 @@ impl Scene {
// Maintain the figures // Maintain the figures
self.figure_cache.maintain(renderer, client); self.figure_cache.maintain(renderer, client);
// Remove unused figures
self.figure_cache.clean(client.get_tick());
} }
/// Render the scene using the provided `Renderer` /// 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) // Render the skybox first (it appears over everything else so must be rendered first)
renderer.render_skybox( renderer.render_skybox(
&self.skybox.model, &self.skybox.model,

View File

@ -87,7 +87,7 @@ impl SessionState {
renderer.clear(BG_COLOR); renderer.clear(BG_COLOR);
// Render the screen using the global renderer // 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 // Draw the UI to the screen
self.hud.render(renderer); self.hud.render(renderer);