diff options
Diffstat (limited to 'textures')
| -rw-r--r-- | textures/Cargo.toml | 13 | ||||
| -rw-r--r-- | textures/src/lib.rs | 96 |
2 files changed, 109 insertions, 0 deletions
diff --git a/textures/Cargo.toml b/textures/Cargo.toml new file mode 100644 index 0000000..e550a92 --- /dev/null +++ b/textures/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "alligator_textures" +version = "0.1.0" +edition = "2021" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +packer = { path = "../packer" } + +image = "0.24" +exun = "0.2" diff --git a/textures/src/lib.rs b/textures/src/lib.rs new file mode 100644 index 0000000..c1b56a8 --- /dev/null +++ b/textures/src/lib.rs @@ -0,0 +1,96 @@ +use std::collections::HashMap; +use std::path::Path; +use std::sync::Arc; + +use exun::{RawUnexpected, ResultErrorExt}; +use image::RgbaImage; +use packer::{RectanglePacker, TextureAtlas}; + +type ExunResult<T> = Result<T, RawUnexpected>; + +pub struct TextureManager { + textures: HashMap<Arc<str>, TextureMetadata>, + loaded_textures: HashMap<Arc<str>, Arc<RgbaImage>>, + packer: RectanglePacker, + target_size: usize, + current_size: usize, +} + +struct TextureMetadata { + path: Arc<Path>, + size: usize, +} + +impl TextureManager { + pub fn new(target_size: usize) -> Self { + Self { + textures: HashMap::new(), + loaded_textures: HashMap::new(), + packer: RectanglePacker::new(), + target_size, + current_size: 0, + } + } + + pub fn add_texture(&mut self, name: Arc<str>, path: Arc<Path>, size: usize) { + self.textures.insert(name, TextureMetadata { path, size }); + } + + pub fn try_preload(&mut self, name: Arc<str>) -> ExunResult<Option<bool>> { + let Some(metadata) = self.textures.get(&name) else { + return Ok(None); + }; + + if self.current_size + metadata.size < self.target_size { + self.load(name)?; + Ok(Some(true)) + } else { + Ok(Some(false)) + } + } + + pub fn load(&mut self, name: Arc<str>) -> ExunResult<Option<()>> { + let Some(metadata) = self.textures.get(&name) else { + return Ok(None); + }; + + self.current_size += metadata.size; + let texture = image::open(&metadata.path).unexpect()?.to_rgba8(); + self.loaded_textures.insert(name, Arc::new(texture)); + + Ok(Some(())) + } + + pub fn unload(&mut self, name: Arc<str>) -> Option<()> { + self.loaded_textures.remove(&name)?; + Some(()) + } + + pub fn pack_texture(&mut self, name: Arc<str>) -> ExunResult<()> { + if !self.loaded_textures.contains_key(&name) { + self.load(name.clone())?; + } + + self.packer.add_texture( + name.clone(), + self.loaded_textures + .get(&name) + .expect("we checked to make sure it was loaded") + .clone(), + ); + + Ok(()) + } + + pub fn reset_packer(&mut self) { + self.packer = RectanglePacker::new(); + } + + pub fn reload_texture_atlas( + &mut self, + min_width: u32, + min_height: u32, + ) -> ExunResult<TextureAtlas> { + self.packer.output(min_width, min_height) + } +} |
