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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use crate::{
component::{CompositeRenderable, CompositeTilemap},
composite_renderer::{Command, Image, Renderable},
tileset_asset_protocol::{TilesetAsset, TilesetInfo},
};
use core::{
assets::{asset::AssetId, database::AssetsDatabase},
ecs::{Comp, Universe, WorldRef},
};
use std::collections::HashMap;
#[derive(Debug, Default)]
pub struct CompositeTilemapSystemCache {
images_cache: HashMap<String, String>,
atlas_table: HashMap<AssetId, String>,
infos_cache: HashMap<String, TilesetInfo>,
}
pub type CompositeTilemapSystemResources<'a> = (
WorldRef,
&'a AssetsDatabase,
&'a mut CompositeTilemapSystemCache,
Comp<&'a mut CompositeRenderable>,
Comp<&'a mut CompositeTilemap>,
);
#[allow(clippy::many_single_char_names)]
pub fn composite_tilemap_system(universe: &mut Universe) {
let (world, assets, mut cache, ..) =
universe.query_resources::<CompositeTilemapSystemResources>();
for id in assets.lately_loaded_protocol("tiles") {
let id = *id;
let asset = assets
.asset_by_id(id)
.expect("trying to use not loaded tileset asset");
let path = asset.path().to_owned();
let asset = asset
.get::<TilesetAsset>()
.expect("trying to use non-tileset asset");
let image = asset.info().image_name();
let info = asset.info().clone();
cache.images_cache.insert(path.clone(), image);
cache.atlas_table.insert(id, path.clone());
cache.infos_cache.insert(path, info);
}
for id in assets.lately_unloaded_protocol("tiles") {
if let Some(path) = cache.atlas_table.remove(id) {
cache.images_cache.remove(&path);
cache.infos_cache.remove(&path);
}
}
for (_, (renderable, tilemap)) in world
.query::<(&mut CompositeRenderable, &mut CompositeTilemap)>()
.iter()
{
if tilemap.dirty {
if let Some(tileset) = tilemap.tileset() {
if let Some(name) = cache.images_cache.get(tileset) {
let r = if let Some(info) = cache.infos_cache.get(tileset) {
let grid = tilemap.grid();
let mut commands = Vec::with_capacity(grid.len() * 4);
for row in 0..grid.rows() {
for col in 0..grid.cols() {
if let Some(cell) = grid.get(col, row) {
if !cell.visible {
continue;
}
if let Some(frame) = info.frame(cell.col, cell.row) {
let (a, b, c, d, e, f) =
cell.matrix(col, row, frame.w, frame.h).into();
commands.push(Command::Store);
commands.push(Command::Transform(a, b, c, d, e, f));
commands.push(Command::Draw(
Image {
image: name.to_owned().into(),
source: Some(frame),
destination: None,
alignment: 0.0.into(),
}
.into(),
));
commands.push(Command::Restore);
}
}
}
}
Renderable::Commands(commands)
} else {
Renderable::None
};
renderable.0 = r;
tilemap.dirty = false;
}
}
}
}
}