summaryrefslogtreecommitdiff
path: root/src/texture.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/texture.rs')
-rw-r--r--src/texture.rs98
1 files changed, 42 insertions, 56 deletions
diff --git a/src/texture.rs b/src/texture.rs
index 457fea8..a3e2c10 100644
--- a/src/texture.rs
+++ b/src/texture.rs
@@ -3,10 +3,11 @@ use std::num::NonZeroU32;
use std::sync::atomic::{AtomicUsize, Ordering};
use image::error::DecodingError;
-use image::{DynamicImage, EncodableLayout, GenericImage, ImageError, RgbaImage};
+use image::{EncodableLayout, GenericImage, ImageError, RgbaImage};
+use texture_packer::TexturePacker;
use texture_packer::{
exporter::{ExportResult, ImageExporter},
- MultiTexturePacker, TexturePackerConfig,
+ TexturePackerConfig,
};
use thiserror::Error;
@@ -64,8 +65,8 @@ impl From<ImageError> for TextureError {
// TODO make these resizable
// TODO this could probably be moved into WgpuTextures
pub struct TextureAtlases<'a> {
- packer: MultiTexturePacker<'a, image::RgbaImage, TextureId>,
- images: Vec<RgbaImage>,
+ packer: TexturePacker<'a, image::RgbaImage, TextureId>,
+ image: RgbaImage,
width: u32,
height: u32,
}
@@ -90,14 +91,19 @@ impl<'a> TextureAtlases<'a> {
// TODO why is this u32?
pub fn new(width: u32, height: u32) -> Self {
Self {
- packer: MultiTexturePacker::new_skyline(TexturePackerConfig {
+ packer: TexturePacker::new_skyline(TexturePackerConfig {
max_width: width,
max_height: height,
..Default::default()
}),
width,
height,
- images: Vec::with_capacity(1),
+ image: RgbaImage::from_raw(
+ width,
+ height,
+ vec![0; 4 * width as usize * height as usize],
+ )
+ .unwrap(),
}
}
@@ -117,11 +123,7 @@ impl<'a> TextureAtlases<'a> {
}
fn texture_frame(&self, id: TextureId) -> Option<&texture_packer::Frame<TextureId>> {
- self.packer
- .get_pages()
- .iter()
- .map(|a| a.get_frame(&id))
- .next()?
+ self.packer.get_frame(&id)
}
texture_info!(texture_width, w);
@@ -137,59 +139,29 @@ impl<'a> TextureAtlases<'a> {
}
}
- fn atlases(&self) -> ExportResult<Box<[DynamicImage]>> {
- self.packer
- .get_pages()
- .iter()
- .map(ImageExporter::export)
- .collect::<ExportResult<Vec<DynamicImage>>>()
- .map(Vec::into_boxed_slice)
- }
-
- fn push_image(&mut self) -> &mut RgbaImage {
- self.images.push(
- RgbaImage::from_raw(
- self.width,
- self.height,
- vec![0; 4 * self.width as usize * self.height as usize],
- )
- .expect("the image was the wrong size"),
- );
-
- self.images
- .last_mut()
- .expect("we just added an image to the list")
- }
-
- fn fill_images(&mut self) -> ExportResult<()> {
- for (i, atlas) in self.atlases()?.iter().enumerate() {
- #[allow(clippy::option_if_let_else)]
- if let Some(image) = self.images.get_mut(i) {
- image
- .copy_from(atlas, 0, 0)
- .expect("atlases shouldn't be too large");
- } else {
- let image = self.push_image();
- image
- .copy_from(atlas, 0, 0)
- .expect("atlases shouldn't be too large");
- }
- }
-
+ fn fill_image(&mut self) -> ExportResult<()> {
+ let atlas = {
+ profiling::scope!("export atlas");
+ ImageExporter::export(&self.packer)?
+ };
+ profiling::scope!("copy image");
+ self.image
+ .copy_from(&atlas, 0, 0)
+ .expect("image cache is too small");
Ok(())
}
fn clear(&mut self) {
- self.packer = MultiTexturePacker::new_skyline(TexturePackerConfig {
+ self.packer = TexturePacker::new_skyline(TexturePackerConfig {
max_width: self.width,
max_height: self.height,
..Default::default()
});
}
- fn images(&mut self) -> ExportResult<&[RgbaImage]> {
- self.fill_images()?;
- Ok(&self.images)
+ fn image(&mut self) -> ExportResult<&RgbaImage> {
+ self.fill_image()?;
+ Ok(&self.image)
}
}
@@ -197,6 +169,7 @@ pub struct WgpuTextures {
atlases: TextureAtlases<'static>,
diffuse_texture: wgpu::Texture,
diffuse_bind_group: wgpu::BindGroup,
+ changed: bool,
}
macro_rules! get_info {
@@ -276,6 +249,7 @@ impl WgpuTextures {
atlases,
diffuse_texture,
diffuse_bind_group,
+ changed: true,
},
texture_bind_group_layout,
)
@@ -292,6 +266,7 @@ impl WgpuTextures {
texture: &[u8],
format: ImageFormat,
) -> Result<TextureId, TextureError> {
+ self.changed = true;
self.atlases.load_from_memory(texture, format)
}
@@ -304,12 +279,20 @@ impl WgpuTextures {
&self.diffuse_bind_group
}
+ #[profiling::function]
pub fn fill_textures(&mut self, queue: &wgpu::Queue) {
+ // saves time if nothing changed since the last time we did this
+ // FIXME This doesn't do much good once we get procedurally generated animation
+ // We'll have to create our own texture packer, with mutable subtextures,
+ // and more efficient algorithms. This'll also make frame times more consistent
+ if !self.changed {
+ return;
+ }
+
let atlas_size = self.atlases.extent_3d();
// put the packed texture into the base image
- let Ok(atlases) = self.atlases.images() else { return };
- let Some(atlas) = atlases.first() else { return };
+ let Ok(atlas) = self.atlases.image() else { return };
// copy that to the gpu
queue.write_texture(
@@ -327,9 +310,12 @@ impl WgpuTextures {
},
atlas_size,
);
+
+ self.changed = false;
}
pub fn clear_textures(&mut self) {
+ self.changed = true;
self.atlases.clear();
}
}