From 5d299af0e592c76c62c6347152eae2257a95c71f Mon Sep 17 00:00:00 2001 From: Micha White Date: Sat, 1 Oct 2022 17:52:50 -0400 Subject: Quick and dirty texture atlases --- src/texture.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/texture.rs (limited to 'src/texture.rs') diff --git a/src/texture.rs b/src/texture.rs new file mode 100644 index 0000000..aa6f871 --- /dev/null +++ b/src/texture.rs @@ -0,0 +1,89 @@ +use std::error::Error; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use image::error::DecodingError; +use image::{DynamicImage, ImageError}; +use texture_packer::{ + exporter::{ExportResult, ImageExporter}, + MultiTexturePacker, TexturePackerConfig, +}; +use thiserror::Error; + +static NEXT_TEXTURE_ID: AtomicUsize = AtomicUsize::new(0); + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +struct TextureId(usize); + +impl TextureId { + pub fn new() -> Self { + Self(NEXT_TEXTURE_ID.fetch_add(1, Ordering::Relaxed)) + } +} + +type PackError = impl std::fmt::Debug; + +#[derive(Error, Debug)] +pub enum TextureError { + #[error("{:?}", .0)] + TextureTooLarge(PackError), // use an error with a source + #[error("{}", .0)] + BadImage(#[source] DecodingError), // TODO don't export this + #[error("Unexpected Error (this is a bug in alligator_render): {}", .0)] + Unexpected(#[source] Box), +} + +impl From for TextureError { + fn from(ie: ImageError) -> Self { + match ie { + ImageError::Decoding(de) => Self::BadImage(de), + _ => Self::Unexpected(Box::new(ie)), + } + } +} + +struct TextureAtlases<'a> { + packer: MultiTexturePacker<'a, image::RgbaImage, TextureId>, +} + +impl<'a> Default for TextureAtlases<'a> { + fn default() -> Self { + Self { + packer: MultiTexturePacker::new_skyline(TexturePackerConfig::default()), + } + } +} + +impl<'a> TextureAtlases<'a> { + /// Creates a new texture atlas, with the given size + // TODO why is this u32? + pub fn new(width: u32, height: u32) -> Self { + Self { + packer: MultiTexturePacker::new_skyline(TexturePackerConfig { + max_width: width, + max_height: height, + ..Default::default() + }), + } + } + + // TODO specify format + // TODO support RGBA16 + pub fn load_from_memory(&mut self, buf: &[u8]) -> Result { + let img = image::load_from_memory(buf)?.into_rgba8(); + let id = TextureId::new(); + self.packer + .pack_own(id, img) + .map_err(TextureError::TextureTooLarge)?; + + Ok(id) + } + + pub(crate) fn atlases(&self) -> ExportResult> { + self.packer + .get_pages() + .iter() + .map(ImageExporter::export) + .collect::>>() + .map(Vec::into_boxed_slice) + } +} -- cgit v1.2.3