From d59c0dd1fa4ab3809f4ae572bc68f4c00e2a6686 Mon Sep 17 00:00:00 2001 From: Micha White Date: Sat, 19 Nov 2022 11:15:27 -0500 Subject: Added ImageFile buffers --- alligator_resources/src/texture.rs | 102 +++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 16 deletions(-) (limited to 'alligator_resources/src') diff --git a/alligator_resources/src/texture.rs b/alligator_resources/src/texture.rs index 4b4baa4..f1d34fc 100644 --- a/alligator_resources/src/texture.rs +++ b/alligator_resources/src/texture.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use std::mem::MaybeUninit; +use std::mem::{self, MaybeUninit}; +use std::path::Path; use std::sync::atomic::{AtomicUsize, Ordering}; -use exun::{Expect, Expected, Unexpected}; use image::{GenericImage, ImageBuffer}; use texture_packer::exporter::ImageExporter; use texture_packer::{Frame, TexturePacker, TexturePackerConfig}; @@ -43,19 +43,92 @@ impl From for image::ImageFormat { #[error("{}", .0)] pub struct DecodingError(#[from] image::error::DecodingError); -type LoadError = Expect; - #[allow(clippy::missing_const_for_fn)] -fn convert_image_decoding(e: image::ImageError) -> Expect { +fn convert_image_decoding(e: image::ImageError) -> DecodingError { if let image::ImageError::Decoding(de) = e { - Expected(de.into()) + de.into() } else { - Unexpected(e.into()) + unreachable!("No other error should be possible") + } +} + +#[derive(Debug, Error)] +pub enum LoadError { + #[error("{}", .0)] + Decoding(#[from] DecodingError), + #[error("{}", .0)] + Io(#[from] std::io::Error), +} + +fn convert_image_load_error(e: image::ImageError) -> LoadError { + match e { + image::ImageError::Decoding(de) => LoadError::Decoding(de.into()), + image::ImageError::IoError(ioe) => ioe.into(), + _ => unreachable!("No other error should be possible"), } } type Rgba16Texture = image::ImageBuffer, Box<[u16]>>; +fn vec_image_to_box(vec_image: image::ImageBuffer, Vec>) -> Rgba16Texture { + let width = vec_image.width(); + let height = vec_image.height(); + let buf = vec_image.into_raw().into_boxed_slice(); + ImageBuffer::from_raw(width, height, buf).expect("image buffer is too small") +} + +#[allow(clippy::missing_const_for_fn)] +fn texture_size(image: &Rgba16Texture) -> usize { + image.len() * mem::size_of::>() +} + +struct ImageFile { + path: Box, + texture: Option, +} + +impl ImageFile { + #[allow(clippy::missing_const_for_fn)] + fn new(path: impl AsRef) -> Self { + Self { + path: path.as_ref().into(), + texture: None, + } + } + + fn open(path: impl AsRef) -> Result { + let texture = image::open(&path).map_err(convert_image_load_error)?; + let texture = texture.to_rgba16(); + let texture = vec_image_to_box(texture); + + Ok(Self { + path: path.as_ref().into(), + texture: Some(texture), + }) + } + + fn load(&mut self) -> Result<&Rgba16Texture, LoadError> { + if self.texture.is_none() { + let texture = image::open(&self.path).map_err(convert_image_load_error)?; + let texture = texture.to_rgba16(); + let texture = vec_image_to_box(texture); + self.texture = Some(texture); + } + + Ok(self.texture.as_ref().expect("the texture wasn't loaded")) + } + + fn unload(&mut self) { + self.texture = None; + } + + fn allocated_size(&self) -> usize { + self.texture + .as_ref() + .map_or(0, |texture| texture.len() * mem::size_of::()) + } +} + pub struct TextureManager { textures: HashMap, packer: TexturePacker<'static, Rgba16Texture, TextureId>, @@ -66,7 +139,8 @@ pub struct TextureManager { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TextureConfig { - pub capacity: usize, + pub initial_capacity: usize, + pub max_size: usize, pub atlas_width: u32, pub atlas_height: u32, } @@ -88,7 +162,7 @@ impl TextureManager { pub fn new(config: TextureConfig) -> Self { let width = config.atlas_width; let height = config.atlas_height; - let textures = HashMap::with_capacity(config.capacity); + let textures = HashMap::with_capacity(config.initial_capacity); let packer = packer(width, height); let atlas: Box<[MaybeUninit]> = Box::new_zeroed_slice((4 * width * height) as _); @@ -148,17 +222,13 @@ impl TextureManager { &mut self, buf: &[u8], format: ImageFormat, - ) -> Result { + ) -> Result { let id = TextureId::new(); let texture = image::load_from_memory_with_format(buf, format.into()); let texture = texture.map_err(convert_image_decoding)?; - let texture = texture.into_rgb16(); + let texture = texture.into_rgba16(); + let texture = vec_image_to_box(texture); - let width = texture.width(); - let height = texture.height(); - let buf = texture.into_raw().into_boxed_slice(); - // TODO this expect can be removed by using unexpect - let texture = ImageBuffer::from_raw(width, height, buf).expect("image buffer is too small"); self.textures.insert(id, texture); Ok(id) -- cgit v1.2.3