use crate::download::Downloader; use anyhow::{Context, Result}; use image::ImageReader; use log::debug; use std::{ collections::{HashMap, HashSet}, hash::Hash, io::Cursor, sync::Arc, }; use weareshared::{ Affine3A, packets::{ReadWrite, Resource}, resources::{MeshPart, Prefab}, }; use wgpu::{ BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindingResource, Buffer, BufferUsages, Device, Extent3d, Queue, SamplerDescriptor, Texture, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, TextureViewDescriptor, util::{BufferInitDescriptor, DeviceExt, TextureDataOrder}, }; pub struct DemandMap { values: HashMap, needed: HashSet, } impl DemandMap { pub fn new() -> Self { Self { needed: HashSet::new(), values: HashMap::new(), } } pub fn insert(&mut self, key: K, value: V) { self.needed.remove(&key); self.values.insert(key, value); } pub fn try_get(&mut self, key: K) -> Option { if let Some(k) = self.values.get(&key) { Some(k.to_owned()) } else { self.needed.insert(key); None } } } pub struct ScenePreparer { device: Arc, queue: Arc, texture_bgl: BindGroupLayout, textures: DemandMap, Arc)>, placeholder_textures: DemandMap<(), (Arc, Arc)>, index_buffers: DemandMap, u32)>, vertex_buffers: DemandMap, u32)>, placeholder_vertex_buffers: DemandMap<(u32, bool), Arc>, mesh_parts: DemandMap>, pub prefabs: DemandMap>, } pub struct RPrefab(pub Vec<(Affine3A, Arc)>); pub struct RMeshPart { pub index_count: u32, pub index: Arc, pub position: [Arc; 3], pub normal: [Arc; 3], pub texcoord: [Arc; 2], pub texture: Arc, } impl ScenePreparer { pub fn new(device: Arc, queue: Arc, texture_bgl: BindGroupLayout) -> Self { Self { texture_bgl, index_buffers: DemandMap::new(), vertex_buffers: DemandMap::new(), mesh_parts: DemandMap::new(), prefabs: DemandMap::new(), textures: DemandMap::new(), placeholder_vertex_buffers: DemandMap::new(), placeholder_textures: DemandMap::new(), device, queue, } } pub fn update(&mut self, dls: &mut Downloader) -> Result<()> { for pres in self.prefabs.needed.clone() { if let Some(buf) = dls.try_get(pres)? { let prefab = Prefab::read(&mut buf.as_slice()).context("parsing prefab")?; let mut rprefab = RPrefab(Vec::new()); for (aff, partres) in &prefab.mesh { if let Some(part) = self.mesh_parts.try_get(*partres) { rprefab.0.push((*aff, part.clone())); } } if rprefab.0.len() == prefab.mesh.len() { self.prefabs.insert(pres, Arc::new(rprefab)); debug!("prefab created ({pres})"); } } } for pres in self.index_buffers.needed.clone() { if let Some(buf) = dls.try_get(pres)? { let buf = buf .into_iter() .array_chunks::<2>() .map(u16::from_be_bytes) .map(u16::to_le_bytes) .flatten() .collect::>(); let buffer = self.device.create_buffer_init(&BufferInitDescriptor { contents: &buf, label: None, usage: BufferUsages::INDEX | BufferUsages::COPY_DST, }); self.index_buffers .insert(pres, (Arc::new(buffer), (buf.len() / 2) as u32)); debug!("index buffer created (len={}) {pres}", buf.len() / 2); } } for pres in self.vertex_buffers.needed.clone() { if let Some(buf) = dls.try_get(pres)? { let buf = buf .into_iter() .array_chunks::<4>() .map(f32::from_be_bytes) .map(f32::to_le_bytes) .flatten() .collect::>(); let buffer = self.device.create_buffer_init(&BufferInitDescriptor { contents: &buf, label: None, usage: BufferUsages::VERTEX | BufferUsages::COPY_DST, }); self.vertex_buffers .insert(pres, (Arc::new(buffer), (buf.len() / 4) as u32)); debug!( "vertex attribute buffer created (len={}) {pres}", buf.len() / 4 ); } } for pres in self.textures.needed.clone() { if let Some(buf) = dls.try_get(pres)? { let image = ImageReader::new(Cursor::new(buf)).with_guessed_format()?; let image = image.decode()?; let image = image.to_rgba8(); let image_raw = image.to_vec(); let tex_bg = create_texture( &self.device, &self.queue, &self.texture_bgl, &image_raw, image.width(), image.height(), ); self.textures.insert(pres, tex_bg); } } for pres in self.placeholder_textures.needed.clone() { let tex_bg = create_texture( &self.device, &self.queue, &self.texture_bgl, &[255, 255, 255, 255], 1, 1, ); self.placeholder_textures.insert(pres, tex_bg); } for pres in self.mesh_parts.needed.clone() { if let Some(buf) = dls.try_get(pres)? { let part = MeshPart::read(&mut buf.as_slice()).context("parsing part")?; if let (Some(indexres), Some(positionres)) = (part.index, part.va_position) { let Some((index, index_count)) = self.index_buffers.try_get(indexres) else { self.index_buffers.needed.insert(indexres); continue; }; let mut position = Vec::new(); let mut vertex_count = 0; for vr in positionres { if let Some((vertex, n)) = self.vertex_buffers.try_get(vr) { vertex_count = n; position.push(vertex); } } let mut normal = Vec::new(); if let Some(normalres) = part.va_normal { for vr in normalres { if let Some((vertex, _)) = self.vertex_buffers.try_get(vr) { normal.push(vertex); } } } else { // TODO generate normals for _ in 0..3 { if let Some(buf) = self .placeholder_vertex_buffers .try_get((vertex_count, false)) { normal.push(buf); } } } let mut texcoord = Vec::new(); if let Some(texcoordres) = part.va_texcoord { for vr in texcoordres { if let Some((vertex, _)) = self.vertex_buffers.try_get(vr) { texcoord.push(vertex); } } } else { // TODO generate UVs for _ in 0..3 { if let Some(buf) = self .placeholder_vertex_buffers .try_get((vertex_count, false)) { texcoord.push(buf); } } } let mut texture = None; if let Some(albedores) = part.tex_albedo { if let Some((_tex, bg)) = self.textures.try_get(albedores) { texture = Some(bg) } } else { if let Some((_tex, bg)) = self.placeholder_textures.try_get(()) { texture = Some(bg) } } if texcoord.len() == 2 && normal.len() == 3 && position.len() == 3 && texture.is_some() { debug!("part created ({pres})"); self.mesh_parts.insert( pres, Arc::new(RMeshPart { index_count, index, texcoord: texcoord.try_into().unwrap(), normal: normal.try_into().unwrap(), position: position.try_into().unwrap(), texture: texture.unwrap(), }), ); } } } } Ok(()) } } fn create_texture( device: &Device, queue: &Queue, bgl: &BindGroupLayout, data: &[u8], width: u32, height: u32, ) -> (Arc, Arc) { let texture = device.create_texture_with_data( &queue, &TextureDescriptor { label: None, size: Extent3d { depth_or_array_layers: 1, width, height, }, mip_level_count: 1, sample_count: 1, dimension: TextureDimension::D2, format: TextureFormat::Rgba8UnormSrgb, usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST, view_formats: &[], }, TextureDataOrder::LayerMajor, data, ); let textureview = texture.create_view(&TextureViewDescriptor::default()); let sampler = device.create_sampler(&SamplerDescriptor { ..Default::default() }); let bindgroup = device.create_bind_group(&BindGroupDescriptor { label: None, layout: &bgl, entries: &[ BindGroupEntry { binding: 0, resource: BindingResource::TextureView(&textureview), }, BindGroupEntry { binding: 1, resource: BindingResource::Sampler(&sampler), }, ], }); (Arc::new(texture), Arc::new(bindgroup)) }