diff --git a/src/render/texturearray.rs b/src/render/texturearray.rs index a1a935f..da70c1c 100644 --- a/src/render/texturearray.rs +++ b/src/render/texturearray.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use serde::Deserialize; use std::{collections::HashMap, fs::File, io::Read, num::NonZeroU32}; use wgpu::BindGroupLayout; @@ -7,50 +8,88 @@ use super::rawtexture::RawTexture; pub struct TextureArray { pub bind_group: wgpu::BindGroup, pub bind_group_layout: BindGroupLayout, - texture_dims: Vec<(u32, u32)>, - texture_indices: HashMap, + textures: HashMap, + error_texture: Texture, } -const TEX: &[&str] = &["error", "small", "gypsum", "earth", "a0"]; - +#[derive(Debug, Clone, Copy)] pub struct Texture { pub index: u32, // Index in texture array pub aspect: f32, // width / height pub height: f32, // Height in game units } +#[derive(Deserialize)] +struct Textures { + texture: Vec, + error: Tex, +} + +#[derive(Deserialize)] +struct Tex { + name: String, + path: String, + height: f32, +} + +impl Tex { + pub fn read(&self, device: &wgpu::Device, queue: &wgpu::Queue) -> Result { + let p = format!("{}/{}", TextureArray::INDEX_ROOT, self.path); + let mut f = File::open(&p)?; + let mut bytes = Vec::new(); + f.read_to_end(&mut bytes)?; + RawTexture::from_bytes(&device, &queue, &bytes, &self.name) + } +} + impl TextureArray { + const INDEX_PATH: &'static str = "assets/index.toml"; + const INDEX_ROOT: &'static str = "assets"; + pub fn get_texture(&self, name: &str) -> Texture { - let index = match self.texture_indices.get(name) { + match self.textures.get(name) { Some(x) => *x, - None => 0, // Default texture - }; - - let dimensions = self.texture_dims[index as usize]; - - return Texture { - index, - height: 100.0, - aspect: dimensions.0 as f32 / dimensions.1 as f32, - }; + None => self.error_texture, + } } pub fn new(device: &wgpu::Device, queue: &wgpu::Queue) -> Result { - let mut textures: Vec = Vec::new(); - let mut texture_indices: HashMap = HashMap::new(); + // Load all textures - let mut i = 0; - for t in TEX { - let p = format!("assets/{t}.png"); - let mut f = File::open(&p)?; - let mut bytes = Vec::new(); - f.read_to_end(&mut bytes)?; - textures.push(RawTexture::from_bytes(&device, &queue, &bytes, &p).unwrap()); - texture_indices.insert(t.to_string(), i); - i += 1; - } + let (error_texture, textures, texture_data) = { + let mut texture_data: Vec = Vec::new(); + let mut textures: HashMap = HashMap::new(); + + let mut texture_index_string = String::new(); + let _ = File::open(Self::INDEX_PATH)?.read_to_string(&mut texture_index_string); + let texture_index: Textures = toml::from_str(&texture_index_string)?; + + // First texture is always error + let raw = texture_index.error.read(device, queue)?; + let error_texture = Texture { + index: 0, + height: texture_index.error.height, + aspect: raw.dimensions.0 as f32 / raw.dimensions.1 as f32, + }; + texture_data.push(raw); + + // Load the rest + let mut i = 1; + for t in texture_index.texture { + let raw = t.read(device, queue)?; + let tx = Texture { + index: i, + height: t.height, + aspect: raw.dimensions.0 as f32 / raw.dimensions.1 as f32, + }; + textures.insert(t.name.clone(), tx); + texture_data.push(raw); + i += 1; + } + + (error_texture, textures, texture_data) + }; - // One of these overall let sampler = device.create_sampler(&wgpu::SamplerDescriptor { address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, @@ -73,19 +112,19 @@ impl TextureArray { view_dimension: wgpu::TextureViewDimension::D2, sample_type: wgpu::TextureSampleType::Float { filterable: true }, }, - count: NonZeroU32::new(textures.len() as u32), + count: NonZeroU32::new(texture_data.len() as u32), }, // Texture sampler wgpu::BindGroupLayoutEntry { binding: 1, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), - count: NonZeroU32::new(textures.len() as u32), + count: NonZeroU32::new(texture_data.len() as u32), }, ], }); - let views: Vec<&wgpu::TextureView> = textures.iter().map(|x| &x.view).collect(); + let views: Vec<&wgpu::TextureView> = texture_data.iter().map(|x| &x.view).collect(); let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { label: Some("texture_bind_group"), layout: &bind_group_layout, @@ -105,8 +144,8 @@ impl TextureArray { return Ok(Self { bind_group, bind_group_layout, - texture_dims: textures.iter().map(|x| x.dimensions).collect(), - texture_indices, + textures, + error_texture, }); } }