use std::collections::HashMap;
use bevy_asset::*;
use bevy_ecs::prelude::*;
use bevy_render::prelude::Image;
use bevy_sprite::{TextureAtlas, TextureAtlasBuilder};
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<TextureAtlas> {
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) handles: Vec<HandleUntyped>,
regions: HashMap<String, AtlasRegion>,
texture: Handle<Image>,
atlas: Handle<TextureAtlas>
}
impl RawChairAtlas {
pub fn new(assets: &AssetServer, base: &'static str) -> std::result::Result<Self, AssetServerError> {
Ok(Self {
base,
handles: assets.load_folder(base)?,
regions: HashMap::new(),
texture: Handle::default(),
atlas: Handle::default()
})
}
pub fn load(&mut self, assets: &AssetServer, textures: &mut Assets<Image>, atlases: &mut Assets<TextureAtlas>) {
let mut names = vec![];
let mut builder = TextureAtlasBuilder::default();
for handle in &self.handles {
let path = assets.get_handle_path(handle);
let Some(path) = path else {
warn!("Texture found with no path");
continue;
};
let path = path.path();
let handle = handle.typed_weak();
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:?}");
continue;
};
names.push(name.to_owned());
builder.add_texture(handle, texture);
}
let atlas = builder.finish(textures)
.expect("Failed to build texture atlas");
self.texture = atlas.texture.clone();
let size = atlas.size;
for (i, name) in names.into_iter().enumerate() {
let rect = atlas.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]
};
if self.regions.contains_key(&name) {
warn!("Duplicate atlas texture '{name}' found");
} else {
self.regions.insert(name, region);
}
}
self.atlas = atlases.add(atlas);
self.handles = vec![];
}
}
impl Atlas for RawChairAtlas {
fn get(&self, name: &str) -> Option<&AtlasRegion> {
self.regions.get(name)
}
}