summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs2
-rw-r--r--src/renderer.rs42
-rw-r--r--src/texture.rs211
3 files changed, 83 insertions, 172 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 311f060..aefcb70 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -18,5 +18,5 @@ pub use instance::Instance;
pub(crate) use instance::InstanceBuffer;
pub use renderer::Renderer;
pub use texture::ImageFormat;
-pub(crate) use texture::WgpuTextures;
+pub(crate) use texture::TextureAtlas;
pub(crate) use vertex::Vertex;
diff --git a/src/renderer.rs b/src/renderer.rs
index 20edf34..a1e2c09 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -1,9 +1,7 @@
use std::{convert::TryInto, num::NonZeroU32};
use crate::{
- texture::{TextureError, TextureId},
- vertex::SQUARE,
- Camera, ImageFormat, Instance, InstanceBuffer, RenderWindowConfig, Vertex, WgpuTextures,
+ vertex::SQUARE, Camera, Instance, InstanceBuffer, RenderWindowConfig, TextureAtlas, Vertex,
};
use pollster::FutureExt;
use thiserror::Error;
@@ -53,7 +51,7 @@ pub struct Renderer {
square_vertices: u32,
instances: InstanceBuffer,
camera: Camera,
- textures: WgpuTextures,
+ textures: TextureAtlas,
window: Window,
}
@@ -200,7 +198,7 @@ impl Renderer {
let instances = InstanceBuffer::new(&device, config.instance_capacity);
// TODO make this configurable
- let (textures, texture_layout) = WgpuTextures::new(
+ let (textures, texture_layout) = TextureAtlas::new(
&device,
window.inner_size().width,
window.inner_size().height,
@@ -289,38 +287,12 @@ impl Renderer {
&mut self.camera
}
- /// Loads a texture from memory, in the given file format
- ///
- /// # Errors
- ///
- /// This returns an error if the texture is not in the given format, or if
- /// the texture is so large that it cannot fit in the texture atlas.
- pub fn texture_from_memory(
- &mut self,
- texture: &[u8],
- format: ImageFormat,
- ) -> Result<TextureId, TextureError> {
- self.textures.texture_from_memory(texture, format)
- }
-
- pub fn texture_width(&self, id: TextureId) -> Option<f32> {
- self.textures.texture_width(id)
- }
-
- pub fn texture_height(&self, id: TextureId) -> Option<f32> {
- self.textures.texture_height(id)
- }
-
- pub fn texture_x(&self, id: TextureId) -> Option<f32> {
- self.textures.texture_x(id)
- }
-
- pub fn texture_y(&self, id: TextureId) -> Option<f32> {
- self.textures.texture_y(id)
+ pub const fn textures(&self) -> &TextureAtlas {
+ &self.textures
}
- pub fn clear_textures(&mut self) {
- self.textures.clear_textures();
+ pub fn textures_mut(&mut self) -> &mut TextureAtlas {
+ &mut self.textures
}
/// Renders a new frame to the window
diff --git a/src/texture.rs b/src/texture.rs
index e0ceb7d..060a029 100644
--- a/src/texture.rs
+++ b/src/texture.rs
@@ -61,135 +61,43 @@ impl From<ImageError> for TextureError {
}
}
+const fn extent_3d(width: u32, height: u32) -> wgpu::Extent3d {
+ wgpu::Extent3d {
+ width,
+ height,
+ depth_or_array_layers: 1,
+ }
+}
+
// TODO make this Debug
// TODO make these resizable
-// TODO this could probably be moved into WgpuTextures
-pub struct TextureAtlas<'a> {
- packer: TexturePacker<'a, image::RgbaImage, TextureId>,
+pub struct TextureAtlas {
+ packer: TexturePacker<'static, image::RgbaImage, TextureId>,
+ diffuse_texture: wgpu::Texture,
+ diffuse_bind_group: wgpu::BindGroup,
image: RgbaImage,
width: u32,
height: u32,
-}
-
-impl<'a> Default for TextureAtlas<'a> {
- fn default() -> Self {
- Self::new(1024, 1024)
- }
+ changed: bool,
}
macro_rules! texture_info {
($name: ident, $prop: ident) => {
- pub fn $name(&self, id: TextureId) -> Option<u32> {
+ pub fn $name(&self, id: TextureId) -> Option<f32> {
let frame = self.texture_frame(id)?;
- Some(frame.frame.$prop)
+ let property = frame.frame.$prop;
+ let value = property as f32;
+ Some(value)
}
};
}
-impl<'a> TextureAtlas<'a> {
+impl TextureAtlas {
/// Creates a new texture atlas, with the given size
// TODO why is this u32?
- pub fn new(width: u32, height: u32) -> Self {
- Self {
- packer: TexturePacker::new_skyline(TexturePackerConfig {
- max_width: width,
- max_height: height,
- ..Default::default()
- }),
- width,
- height,
- image: RgbaImage::from_raw(
- width,
- height,
- vec![0; 4 * width as usize * height as usize],
- )
- .unwrap(),
- }
- }
-
- // TODO support RGBA16
- pub fn load_from_memory(
- &mut self,
- buf: &[u8],
- format: ImageFormat,
- ) -> Result<TextureId, TextureError> {
- let img = image::load_from_memory_with_format(buf, format.format())?.into_rgba8();
- let id = TextureId::new();
- self.packer
- .pack_own(id, img)
- .map_err(TextureError::TextureTooLarge)?;
-
- Ok(id)
- }
-
- fn texture_frame(&self, id: TextureId) -> Option<&texture_packer::Frame<TextureId>> {
- self.packer.get_frame(&id)
- }
-
- texture_info!(texture_width, w);
- texture_info!(texture_height, h);
- texture_info!(texture_x, x);
- texture_info!(texture_y, y);
-
- const fn extent_3d(&self) -> wgpu::Extent3d {
- wgpu::Extent3d {
- width: self.width,
- height: self.height,
- depth_or_array_layers: 1,
- }
- }
-
- 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 = TexturePacker::new_skyline(TexturePackerConfig {
- max_width: self.width,
- max_height: self.height,
- ..Default::default()
- });
- }
-
- fn image(&mut self) -> ExportResult<&RgbaImage> {
- self.fill_image()?;
- Ok(&self.image)
- }
-}
-
-pub struct WgpuTextures {
- atlases: TextureAtlas<'static>,
- diffuse_texture: wgpu::Texture,
- diffuse_bind_group: wgpu::BindGroup,
- changed: bool,
-}
-
-macro_rules! get_info {
- ($name: ident, $divisor: ident) => {
- // TODO try to remove this
- #[allow(clippy::cast_precision_loss)]
- pub fn $name(&self, id: TextureId) -> Option<f32> {
- self.atlases
- .$name(id)
- .map(|u| u as f32 / self.atlases.extent_3d().$divisor as f32)
- }
- };
-}
-
-impl WgpuTextures {
// TODO this is still too large
pub fn new(device: &wgpu::Device, width: u32, height: u32) -> (Self, wgpu::BindGroupLayout) {
- let atlases = TextureAtlas::new(width, height);
- let atlas_size = atlases.extent_3d();
-
+ let atlas_size = extent_3d(width, height);
let diffuse_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Diffuse Texture"),
size: atlas_size,
@@ -246,37 +154,73 @@ impl WgpuTextures {
(
Self {
- atlases,
+ packer: TexturePacker::new_skyline(TexturePackerConfig {
+ max_width: width,
+ max_height: height,
+ ..Default::default()
+ }),
diffuse_texture,
diffuse_bind_group,
+ width,
+ height,
+ image: RgbaImage::from_raw(
+ width,
+ height,
+ vec![0; 4 * width as usize * height as usize],
+ )
+ .unwrap(),
changed: true,
},
texture_bind_group_layout,
)
}
- /// Loads a texture from memory, in the given file format
- ///
- /// # Errors
- ///
- /// This returns an error if the texture is not in the given format, or if
- /// the texture is so large that it cannot fit in the texture atlas.
- pub fn texture_from_memory(
+ pub(crate) const fn bind_group(&self) -> &wgpu::BindGroup {
+ &self.diffuse_bind_group
+ }
+
+ // TODO support RGBA16
+ pub fn load_from_memory(
&mut self,
- texture: &[u8],
+ buf: &[u8],
format: ImageFormat,
) -> Result<TextureId, TextureError> {
- self.changed = true;
- self.atlases.load_from_memory(texture, format)
+ let img = image::load_from_memory_with_format(buf, format.format())?.into_rgba8();
+ let id = TextureId::new();
+ self.packer
+ .pack_own(id, img)
+ .map_err(TextureError::TextureTooLarge)?;
+
+ Ok(id)
}
- get_info!(texture_width, width);
- get_info!(texture_height, height);
- get_info!(texture_x, width);
- get_info!(texture_y, height);
+ fn texture_frame(&self, id: TextureId) -> Option<&texture_packer::Frame<TextureId>> {
+ self.packer.get_frame(&id)
+ }
- pub const fn bind_group(&self) -> &wgpu::BindGroup {
- &self.diffuse_bind_group
+ texture_info!(texture_width, w);
+ texture_info!(texture_height, h);
+ texture_info!(texture_x, x);
+ texture_info!(texture_y, y);
+
+ 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 = TexturePacker::new_skyline(TexturePackerConfig {
+ max_width: self.width,
+ max_height: self.height,
+ ..Default::default()
+ });
}
#[profiling::function]
@@ -289,10 +233,10 @@ impl WgpuTextures {
return;
}
- let atlas_size = self.atlases.extent_3d();
+ let atlas_size = extent_3d(self.width, self.height);
// put the packed texture into the base image
- let Ok(atlas) = self.atlases.image() else { return };
+ drop(self.fill_image());
// copy that to the gpu
queue.write_texture(
@@ -302,7 +246,7 @@ impl WgpuTextures {
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
- atlas.as_bytes(),
+ self.image.as_bytes(),
wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: NonZeroU32::new(atlas_size.width * 4),
@@ -313,9 +257,4 @@ impl WgpuTextures {
self.changed = false;
}
-
- pub fn clear_textures(&mut self) {
- self.changed = true;
- self.atlases.clear();
- }
}