oxygengine_composite_renderer/system/
tilemap.rs1use 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}