oxygengine_composite_renderer/system/
sprite_sheet.rs

1use crate::{
2    component::{CompositeRenderable, CompositeSprite},
3    composite_renderer::Image,
4    math::Rect,
5    sprite_sheet_asset_protocol::SpriteSheetAsset,
6};
7use core::{
8    assets::{asset::AssetId, database::AssetsDatabase},
9    ecs::{Comp, Universe, WorldRef},
10};
11use std::collections::HashMap;
12
13#[derive(Debug, Default)]
14pub struct CompositeSpriteSheetSystemCache {
15    images_cache: HashMap<String, String>,
16    atlas_table: HashMap<AssetId, String>,
17    frames_cache: HashMap<String, HashMap<String, Rect>>,
18}
19
20pub type CompositeSpriteSheetSystemResources<'a> = (
21    WorldRef,
22    &'a AssetsDatabase,
23    &'a mut CompositeSpriteSheetSystemCache,
24    Comp<&'a mut CompositeRenderable>,
25    Comp<&'a mut CompositeSprite>,
26);
27
28pub fn composite_sprite_sheet_system(universe: &mut Universe) {
29    let (world, assets, mut cache, ..) =
30        universe.query_resources::<CompositeSpriteSheetSystemResources>();
31
32    for id in assets.lately_loaded_protocol("atlas") {
33        let id = *id;
34        let asset = assets
35            .asset_by_id(id)
36            .expect("trying to use not loaded atlas asset");
37        let path = asset.path().to_owned();
38        let asset = asset
39            .get::<SpriteSheetAsset>()
40            .expect("trying to use non-atlas asset");
41        let image = asset.info().meta.image_name();
42        let frames = asset
43            .info()
44            .frames
45            .iter()
46            .map(|(k, v)| (k.to_owned(), v.frame))
47            .collect();
48        cache.images_cache.insert(path.clone(), image);
49        cache.atlas_table.insert(id, path.clone());
50        cache.frames_cache.insert(path, frames);
51    }
52    for id in assets.lately_unloaded_protocol("atlas") {
53        if let Some(path) = cache.atlas_table.remove(id) {
54            cache.images_cache.remove(&path);
55            cache.frames_cache.remove(&path);
56        }
57    }
58
59    for (_, (renderable, sprite)) in world
60        .query::<(&mut CompositeRenderable, &mut CompositeSprite)>()
61        .iter()
62    {
63        if sprite.dirty {
64            if let Some((sheet, frame)) = sprite.sheet_frame() {
65                if let (Some(name), Some(frames)) =
66                    (cache.images_cache.get(sheet), cache.frames_cache.get(sheet))
67                {
68                    renderable.0 = Image {
69                        image: name.clone().into(),
70                        source: frames.get(frame).copied(),
71                        destination: None,
72                        alignment: sprite.alignment,
73                    }
74                    .into();
75                    sprite.dirty = false;
76                }
77            }
78        }
79    }
80}