summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMicha White <botahamec@outlook.com>2022-11-19 11:15:27 -0500
committerMicha White <botahamec@outlook.com>2022-11-19 11:15:27 -0500
commitd59c0dd1fa4ab3809f4ae572bc68f4c00e2a6686 (patch)
tree99b6c8b453c329b24aa6f72ae8b829b2dda5c85a
parent64096d822a1d0437db558263845d6908c96f634b (diff)
Added ImageFile buffers
-rw-r--r--alligator_resources/src/texture.rs102
1 files changed, 86 insertions, 16 deletions
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<ImageFormat> for image::ImageFormat {
#[error("{}", .0)]
pub struct DecodingError(#[from] image::error::DecodingError);
-type LoadError = Expect<DecodingError>;
-
#[allow(clippy::missing_const_for_fn)]
-fn convert_image_decoding(e: image::ImageError) -> Expect<DecodingError> {
+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<image::Rgba<u16>, Box<[u16]>>;
+fn vec_image_to_box(vec_image: image::ImageBuffer<image::Rgba<u16>, Vec<u16>>) -> 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::<image::Rgba<u16>>()
+}
+
+struct ImageFile {
+ path: Box<Path>,
+ texture: Option<Rgba16Texture>,
+}
+
+impl ImageFile {
+ #[allow(clippy::missing_const_for_fn)]
+ fn new(path: impl AsRef<Path>) -> Self {
+ Self {
+ path: path.as_ref().into(),
+ texture: None,
+ }
+ }
+
+ fn open(path: impl AsRef<Path>) -> Result<Self, LoadError> {
+ 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::<u16>())
+ }
+}
+
pub struct TextureManager {
textures: HashMap<TextureId, Rgba16Texture>,
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<u16>]> = Box::new_zeroed_slice((4 * width * height) as _);
@@ -148,17 +222,13 @@ impl TextureManager {
&mut self,
buf: &[u8],
format: ImageFormat,
- ) -> Result<TextureId, LoadError> {
+ ) -> Result<TextureId, DecodingError> {
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)