use std::collections::{hash_map::Entry, HashMap};
use bevy_asset::*;
use bevy_ecs::prelude::*;
use bevy_render::prelude::Image;
use bevy_sprite::{TextureAtlasBuilder, TextureAtlasLayout};
use chair::*;
use log::*;
#[derive(Clone, Debug, Resource)]
pub struct ChairAtlas(pub &'static RawChairAtlas);
impl ChairAtlas {
pub fn texture(&self) -> Handle<Image> {
self.0.texture.clone()
}
pub fn atlas(&self) -> Handle<TextureAtlasLayout> {
self.0.atlas.clone()
}
}
#[derive(Debug, Resource)]
pub struct MutChairAtlas(pub(crate) &'static mut RawChairAtlas);
impl MutChairAtlas {
pub fn new(atlas: RawChairAtlas) -> Self {
Self(Box::leak(Box::new(atlas)))
}
}
#[derive(Debug)]
pub struct RawChairAtlas {
base: &'static str,
pub(crate) folder: Handle<LoadedFolder>,
regions: HashMap<String, AtlasRegion>,
texture: Handle<Image>,
atlas: Handle<TextureAtlasLayout>
}
impl RawChairAtlas {
pub fn new(assets: &AssetServer, base: &'static str) -> Self {
Self {
base,
folder: assets.load_folder(base),
regions: HashMap::new(),
texture: Handle::default(),
atlas: Handle::default()
}
}
pub fn load(&mut self, folders: &mut Assets<LoadedFolder>, textures: &mut Assets<Image>, atlases: &mut Assets<TextureAtlasLayout>) {
let mut names = vec![];
let mut builder = TextureAtlasBuilder::default();
let folder = folders.get(&self.folder)
.expect("Failed to get folder how");
debug!("Loading {} textures", folder.handles.len());
for handle in &folder.handles {
let path = handle.path();
let Some(path) = path else {
warn!("Texture found with no path");
continue;
};
let path = path.path();
let handle = handle.clone_weak().typed();
let Some(texture) = textures.get(&handle) else {
warn!("Texture {path:?} is not an image asset");
continue;
};
let Ok(name) = path.strip_prefix(self.base) else {
warn!("Random path {path:?} found in handles, not a prefix of {:?}", self.base);
continue;
};
let name = name.with_extension("");
let Some(name) = name.as_os_str().to_str() else {
warn!("Non UTF-8 filename {name:?}, ignoring it");
continue;
};
trace!("Texture {name} loaded into the atlas");
names.push(name.to_owned());
builder.add_texture(Some(handle.into()), texture);
}
let (layout, texture) = builder.finish()
.expect("Failed to build texture atlas");
let size = layout.size;
let atlas = textures.add(texture);
self.texture = atlas.clone();
for (i, name) in names.into_iter().enumerate() {
let rect = layout.textures[i];
let min = rect.min / size;
let max = rect.max / size;
trace!("Region {name} at {rect:?}");
let region = AtlasRegion {
xy: min.into(),
x2y: [max.x, min.y],
x2y2: max.into(),
xy2: [min.x, max.x]
};
match self.regions.entry(name) {
Entry::Vacant(e) => { e.insert(region); },
Entry::Occupied(e) => {
warn!("Duplicate atlas texture '{}' found", e.key());
}
}
}
self.atlas = atlases.add(layout);
if let Some(folder) = folders.get_mut(&self.folder) {
folder.handles = vec![];
}
self.folder = Handle::default();
}
}
impl Atlas for RawChairAtlas {
fn get(&self, name: &str) -> Option<&AtlasRegion> {
self.regions.get(name)
}
}