1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use crate::{
    component::{CompositeRenderable, CompositeSurfaceCache},
    composite_renderer::{Command, CompositeRenderer, Image},
};
use core::ecs::{life_cycle::EntityChanges, Comp, Entity, Universe, WorldRef};
use std::collections::HashMap;

#[derive(Debug, Default)]
pub struct CompositeSurfaceCacheSystemCache {
    cached_surfaces: HashMap<Entity, String>,
}

pub type CompositeSurfaceCacheSystemResources<'a, CR> = (
    WorldRef,
    &'a mut CR,
    &'a EntityChanges,
    &'a mut CompositeSurfaceCacheSystemCache,
    Comp<&'a mut CompositeSurfaceCache>,
    Comp<&'a mut CompositeRenderable>,
);

pub fn composite_surface_cache_system<CR>(universe: &mut Universe)
where
    CR: CompositeRenderer + 'static,
{
    let (world, mut renderer, changes, mut cache, ..) =
        universe.query_resources::<CompositeSurfaceCacheSystemResources<CR>>();

    for entity in changes.despawned() {
        if let Some(name) = cache.cached_surfaces.remove(&entity) {
            renderer.destroy_surface(&name);
        }
    }

    for (entity, (surface, renderable)) in world
        .query::<(&mut CompositeSurfaceCache, &mut CompositeRenderable)>()
        .iter()
    {
        if surface.dirty {
            surface.dirty = false;
            if !renderer.has_surface(surface.name()) {
                renderer.create_surface(surface.name(), surface.width(), surface.height());
                cache
                    .cached_surfaces
                    .insert(entity, surface.name().to_owned());
            } else if let Some((width, height)) = renderer.get_surface_size(surface.name()) {
                if width != surface.width() || height != surface.height() {
                    renderer.destroy_surface(surface.name());
                    renderer.create_surface(surface.name(), surface.width(), surface.height());
                    cache
                        .cached_surfaces
                        .insert(entity, surface.name().to_owned());
                }
            }
            let commands = vec![
                Command::Store,
                Command::Draw(renderable.0.clone()),
                Command::Restore,
            ];
            if renderer.update_surface(surface.name(), commands).is_ok() {
                renderable.0 = Image {
                    image: surface.name().to_owned().into(),
                    source: None,
                    destination: None,
                    alignment: 0.0.into(),
                }
                .into();
            }
        }
    }
}