summaryrefslogtreecommitdiff
path: root/textures
diff options
context:
space:
mode:
Diffstat (limited to 'textures')
-rw-r--r--textures/Cargo.toml13
-rw-r--r--textures/src/lib.rs96
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)
+ }
+}