summaryrefslogtreecommitdiff
path: root/alligator_resources/src
diff options
context:
space:
mode:
authorMicha White <botahamec@outlook.com>2022-11-19 12:23:15 -0500
committerMicha White <botahamec@outlook.com>2022-11-19 12:23:15 -0500
commit20b0a802225da2668263c93b492a49d25714598e (patch)
tree19406980382527ff59979a36a83bea3e8447a3f3 /alligator_resources/src
parentd59c0dd1fa4ab3809f4ae572bc68f4c00e2a6686 (diff)
Created TextureRef
Diffstat (limited to 'alligator_resources/src')
-rw-r--r--alligator_resources/src/lib.rs10
-rw-r--r--alligator_resources/src/texture.rs160
2 files changed, 125 insertions, 45 deletions
diff --git a/alligator_resources/src/lib.rs b/alligator_resources/src/lib.rs
index b85eab1..0f7b544 100644
--- a/alligator_resources/src/lib.rs
+++ b/alligator_resources/src/lib.rs
@@ -5,4 +5,12 @@
pub mod texture;
-struct ResourceManager {}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum Priority {
+ Unnecessary,
+ Possible(u8),
+ Eventual(u8),
+ Urgent,
+}
+
+pub struct ResourceManager {}
diff --git a/alligator_resources/src/texture.rs b/alligator_resources/src/texture.rs
index f1d34fc..9aca56d 100644
--- a/alligator_resources/src/texture.rs
+++ b/alligator_resources/src/texture.rs
@@ -2,12 +2,15 @@ use std::collections::HashMap;
use std::mem::{self, MaybeUninit};
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
use image::{GenericImage, ImageBuffer};
use texture_packer::exporter::ImageExporter;
use texture_packer::{Frame, TexturePacker, TexturePackerConfig};
use thiserror::Error;
+use crate::Priority;
+
static NEXT_TEXTURE_ID: AtomicUsize = AtomicUsize::new(0);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -82,12 +85,12 @@ fn texture_size(image: &Rgba16Texture) -> usize {
image.len() * mem::size_of::<image::Rgba<u16>>()
}
-struct ImageFile {
+struct TextureFile {
path: Box<Path>,
- texture: Option<Rgba16Texture>,
+ texture: Option<Arc<Rgba16Texture>>,
}
-impl ImageFile {
+impl TextureFile {
#[allow(clippy::missing_const_for_fn)]
fn new(path: impl AsRef<Path>) -> Self {
Self {
@@ -97,21 +100,21 @@ impl ImageFile {
}
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);
+ let mut this = Self::new(path);
+ this.load()?;
- Ok(Self {
- path: path.as_ref().into(),
- texture: Some(texture),
- })
+ Ok(this)
+ }
+
+ const fn is_loaded(&self) -> bool {
+ self.texture.is_some()
}
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);
+ let texture = Arc::new(vec_image_to_box(texture));
self.texture = Some(texture);
}
@@ -123,14 +126,99 @@ impl ImageFile {
}
fn allocated_size(&self) -> usize {
- self.texture
- .as_ref()
- .map_or(0, |texture| texture.len() * mem::size_of::<u16>())
+ self.texture.as_ref().map_or(0, |t| texture_size(t))
+ }
+}
+
+enum TextureBuffer {
+ Memory(Arc<Rgba16Texture>),
+ Disk(TextureFile),
+}
+
+struct Texture {
+ priority: Priority,
+ buffer: TextureBuffer,
+}
+
+impl Texture {
+ fn from_buffer(texture: Rgba16Texture) -> Self {
+ Self {
+ priority: Priority::Urgent,
+ buffer: TextureBuffer::Memory(Arc::new(texture)),
+ }
+ }
+
+ fn from_path(path: impl AsRef<Path>, priority: Priority) -> Self {
+ Self {
+ priority,
+ buffer: TextureBuffer::Disk(TextureFile::new(path)),
+ }
+ }
+
+ const fn priority(&self) -> Priority {
+ self.priority
+ }
+
+ fn set_priority(&mut self, priority: Priority) {
+ self.priority = priority;
+ }
+
+ fn load_texture(&mut self) -> Result<&Rgba16Texture, LoadError> {
+ match &mut self.buffer {
+ TextureBuffer::Memory(ref texture) => Ok(texture),
+ TextureBuffer::Disk(file) => file.load(),
+ }
+ }
+}
+
+pub struct TextureRef<'a> {
+ id: TextureId,
+ texture: Arc<Rgba16Texture>,
+ manager: &'a TextureManager,
+}
+
+impl<'a> TextureRef<'a> {
+ fn texture_width(&self) -> u32 {
+ self.texture.width()
+ }
+
+ fn texture_height(&self) -> u32 {
+ self.texture.height()
+ }
+
+ #[allow(clippy::missing_const_for_fn)]
+ fn texture(&self) -> &Rgba16Texture {
+ &self.texture
+ }
+
+ // TODO: it's safer to replace this with a position thingy
+ #[must_use]
+ pub fn atlas_x(&self) -> f32 {
+ self.manager
+ .subtexture_x(self.id)
+ .expect("not in texture atlas")
+ }
+
+ #[must_use]
+ pub fn atlas_y(&self) -> f32 {
+ self.manager
+ .subtexture_y(self.id)
+ .expect("not in texture atlas")
+ }
+
+ #[must_use]
+ pub fn width(&self) -> f32 {
+ self.manager.texture_width(self)
+ }
+
+ #[must_use]
+ pub fn height(&self) -> f32 {
+ self.manager.texture_height(self)
}
}
pub struct TextureManager {
- textures: HashMap<TextureId, Rgba16Texture>,
+ textures: HashMap<TextureId, Texture>,
packer: TexturePacker<'static, Rgba16Texture, TextureId>,
atlas: Rgba16Texture, // cached texture atlas
width: u32,
@@ -179,32 +267,22 @@ impl TextureManager {
}
}
- pub fn load_to_atlas(&mut self, id: TextureId) {
- let texture = self.texture(id);
- if self.packer.pack_own(id, texture.clone()).is_err() {
- let texture = self.texture(id);
+ pub fn load_to_atlas(&mut self, id: TextureId, texture: &TextureRef) {
+ let get_texture = || texture.texture().clone();
+
+ if self.packer.pack_own(id, get_texture()).is_err() {
+ let texture = get_texture();
self.resize_atlas(self.width + texture.width(), self.height + texture.height());
- let texture = self.texture(id);
self.packer
- .pack_own(id, texture.clone())
+ .pack_own(id, get_texture())
.expect("packer is still too small after resizing");
}
}
- /// Resize the texture atlas
+ /// Clear and resize the texture atlas
pub fn resize_atlas(&mut self, width: u32, height: u32) {
- let old_packer = &self.packer;
- let mut new_packer = packer(width, height);
-
- for id in old_packer.get_frames().keys() {
- let texture = self.texture(*id).clone();
- new_packer
- .pack_own(*id, texture)
- .expect("resized packer is too small to hold subtextures");
- }
-
- self.packer = new_packer;
+ self.packer = packer(width, height);
}
/// Clear the texture atlas
@@ -228,6 +306,7 @@ impl TextureManager {
let texture = texture.map_err(convert_image_decoding)?;
let texture = texture.into_rgba16();
let texture = vec_image_to_box(texture);
+ let texture = Texture::from_buffer(texture);
self.textures.insert(id, texture);
@@ -237,7 +316,6 @@ impl TextureManager {
pub fn atlas(&mut self) -> &Rgba16Texture {
let atlas = {
profiling::scope!("export atlas");
- // TODO unexpect_msg?
ImageExporter::export(&self.packer).expect("ImageExporter error?")
};
@@ -249,10 +327,6 @@ impl TextureManager {
&self.atlas
}
- fn texture(&self, id: TextureId) -> &Rgba16Texture {
- self.textures.get(&id).expect("invalid TextureId")
- }
-
/// Get the subtexture in the texture atlas
fn subtexture(&self, id: TextureId) -> Option<&Frame<TextureId>> {
self.packer.get_frame(&id)
@@ -277,16 +351,14 @@ impl TextureManager {
/// Get the width of a texture
#[must_use]
#[allow(clippy::cast_precision_loss)]
- pub fn texture_width(&self, id: TextureId) -> f32 {
- let width = self.texture(id).width();
- width as f32 / self.width as f32
+ pub fn texture_width(&self, texture: &TextureRef) -> f32 {
+ texture.texture_width() as f32 / self.width as f32
}
/// Get the height of a texture
#[must_use]
#[allow(clippy::cast_precision_loss)]
- pub fn texture_height(&self, id: TextureId) -> f32 {
- let height = self.texture(id).height();
- height as f32 / self.height as f32
+ pub fn texture_height(&self, texture: &TextureRef) -> f32 {
+ texture.texture_height() as f32 / self.height as f32
}
}