summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs2
-rw-r--r--src/renderer.rs2
-rw-r--r--src/texture.rs89
3 files changed, 93 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index bacb53d..1453ef0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,6 @@
#![feature(let_else)]
#![feature(nonzero_min_max)]
+#![feature(type_alias_impl_trait)]
#![warn(clippy::pedantic)]
#![warn(clippy::nursery)]
#![allow(clippy::module_name_repetitions)]
@@ -8,6 +9,7 @@ pub mod camera;
pub mod config;
pub mod instance;
pub mod renderer;
+mod texture;
mod vertex;
pub(crate) use camera::Camera;
diff --git a/src/renderer.rs b/src/renderer.rs
index 55333f4..d45233b 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -35,11 +35,13 @@ pub enum NewRendererError {
#[error(transparent)]
NoGpu(#[from] NoGpuError),
#[error(transparent)]
+ // TODO better error
WindowInitError(#[from] OsError),
}
#[derive(Debug)]
pub struct Renderer {
+ // TODO move some of this data elsewhere
surface: wgpu::Surface,
surface_config: wgpu::SurfaceConfiguration,
supported_present_modes: Box<[wgpu::PresentMode]>,
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<dyn Error>),
+}
+
+impl From<ImageError> 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<TextureId, TextureError> {
+ 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<Box<[DynamicImage]>> {
+ self.packer
+ .get_pages()
+ .iter()
+ .map(ImageExporter::export)
+ .collect::<ExportResult<Vec<DynamicImage>>>()
+ .map(Vec::into_boxed_slice)
+ }
+}