use anyhow::Result; use std::{collections::HashMap, num::NonZeroU32, path::PathBuf}; use wgpu::BindGroupLayout; use super::{loader::TextureLoader, Texture, TextureArrayConfig}; pub struct TextureArray { pub bind_group: wgpu::BindGroup, pub bind_group_layout: BindGroupLayout, textures: HashMap, config: TextureArrayConfig, } impl TextureArray { const INDEX_PATH: &'static str = "assets.ignore"; pub fn get_starfield(&self) -> Texture { return self.get_texture(&self.config.starfield); } pub fn get_texture(&self, name: &str) -> Texture { match self.textures.get(name) { Some(x) => *x, None => self.get_texture(&self.config.error), } } pub fn new(device: &wgpu::Device, queue: &wgpu::Queue) -> Result { // Load all textures let loader = TextureLoader::load(device, queue, &PathBuf::from(Self::INDEX_PATH))?; let sampler = device.create_sampler(&wgpu::SamplerDescriptor { address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_w: wgpu::AddressMode::ClampToEdge, mag_filter: wgpu::FilterMode::Linear, min_filter: wgpu::FilterMode::Nearest, mipmap_filter: wgpu::FilterMode::Nearest, ..Default::default() }); let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: Some("texture_bind_group_layout"), entries: &[ // Texture data wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Texture { multisampled: false, view_dimension: wgpu::TextureViewDimension::D2, sample_type: wgpu::TextureSampleType::Float { filterable: true }, }, count: NonZeroU32::new(loader.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(loader.texture_data.len() as u32), }, ], }); let views: Vec<&wgpu::TextureView> = loader.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, entries: &[ wgpu::BindGroupEntry { binding: 0, // Array of all views resource: wgpu::BindingResource::TextureViewArray(&views), }, wgpu::BindGroupEntry { binding: 1, resource: wgpu::BindingResource::SamplerArray(&[&sampler].repeat(views.len())), }, ], }); return Ok(Self { bind_group, bind_group_layout, textures: loader.textures, config: loader.config, }); } }