oxygengine_composite_renderer/system/
tilemap.rs

1use crate::{
2    component::{CompositeRenderable, CompositeTilemap},
3    composite_renderer::{Command, Image, Renderable},
4    tileset_asset_protocol::{TilesetAsset, TilesetInfo},
5};
6use core::{
7    assets::{asset::AssetId, database::AssetsDatabase},
8    ecs::{Comp, Universe, WorldRef},
9};
10use std::collections::HashMap;
11
12#[derive(Debug, Default)]
13pub struct CompositeTilemapSystemCache {
14    images_cache: HashMap<String, String>,
15    atlas_table: HashMap<AssetId, String>,
16    infos_cache: HashMap<String, TilesetInfo>,
17}
18pub type CompositeTilemapSystemResources<'a> = (
19    WorldRef,
20    &'a AssetsDatabase,
21    &'a mut CompositeTilemapSystemCache,
22    Comp<&'a mut CompositeRenderable>,
23    Comp<&'a mut CompositeTilemap>,
24);
25
26#[allow(clippy::many_single_char_names)]
27pub fn composite_tilemap_system(universe: &mut Universe) {
28    let (world, assets, mut cache, ..) =
29        universe.query_resources::<CompositeTilemapSystemResources>();
30
31    for id in assets.lately_loaded_protocol("tiles") {
32        let id = *id;
33        let asset = assets
34            .asset_by_id(id)
35            .expect("trying to use not loaded tileset asset");
36        let path = asset.path().to_owned();
37        let asset = asset
38            .get::<TilesetAsset>()
39            .expect("trying to use non-tileset asset");
40        let image = asset.info().image_name();
41        let info = asset.info().clone();
42        cache.images_cache.insert(path.clone(), image);
43        cache.atlas_table.insert(id, path.clone());
44        cache.infos_cache.insert(path, info);
45    }
46    for id in assets.lately_unloaded_protocol("tiles") {
47        if let Some(path) = cache.atlas_table.remove(id) {
48            cache.images_cache.remove(&path);
49            cache.infos_cache.remove(&path);
50        }
51    }
52
53    for (_, (renderable, tilemap)) in world
54        .query::<(&mut CompositeRenderable, &mut CompositeTilemap)>()
55        .iter()
56    {
57        if tilemap.dirty {
58            if let Some(tileset) = tilemap.tileset() {
59                if let Some(name) = cache.images_cache.get(tileset) {
60                    let r = if let Some(info) = cache.infos_cache.get(tileset) {
61                        let grid = tilemap.grid();
62                        let mut commands = Vec::with_capacity(grid.len() * 4);
63                        for row in 0..grid.rows() {
64                            for col in 0..grid.cols() {
65                                if let Some(cell) = grid.get(col, row) {
66                                    if !cell.visible {
67                                        continue;
68                                    }
69                                    if let Some(frame) = info.frame(cell.col, cell.row) {
70                                        let (a, b, c, d, e, f) =
71                                            cell.matrix(col, row, frame.w, frame.h).into();
72                                        commands.push(Command::Store);
73                                        commands.push(Command::Transform(a, b, c, d, e, f));
74                                        commands.push(Command::Draw(
75                                            Image {
76                                                image: name.to_owned().into(),
77                                                source: Some(frame),
78                                                destination: None,
79                                                alignment: 0.0.into(),
80                                            }
81                                            .into(),
82                                        ));
83                                        commands.push(Command::Restore);
84                                    }
85                                }
86                            }
87                        }
88                        Renderable::Commands(commands)
89                    } else {
90                        Renderable::None
91                    };
92                    renderable.0 = r;
93                    tilemap.dirty = false;
94                }
95            }
96        }
97    }
98}