summaryrefslogtreecommitdiff
path: root/client/src/scene_prepare.rs
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/scene_prepare.rs')
-rw-r--r--client/src/scene_prepare.rs1030
1 files changed, 0 insertions, 1030 deletions
diff --git a/client/src/scene_prepare.rs b/client/src/scene_prepare.rs
index d4535a1..e69de29 100644
--- a/client/src/scene_prepare.rs
+++ b/client/src/scene_prepare.rs
@@ -1,1030 +0,0 @@
-/*
- wearechat - generic multiplayer game with voip
- Copyright (C) 2025 metamuffin
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, version 3 of the License only.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-*/
-use crate::{
- armature::RArmature,
- download::Downloader,
- meshops::{generate_normals, generate_tangents, generate_texcoords},
- shaders::SceneShaders,
-};
-use anyhow::Result;
-use bytemuck::{Pod, Zeroable};
-use egui::{Grid, Widget};
-use glam::{UVec3, UVec4, Vec2, Vec3, Vec3A, uvec3, uvec4};
-use humansize::DECIMAL;
-use image::ImageReader;
-use log::{debug, trace};
-use std::{
- collections::{HashMap, HashSet},
- hash::Hash,
- io::Cursor,
- marker::PhantomData,
- sync::{Arc, RwLock},
- time::Instant,
-};
-use weareshared::{
- Affine3A,
- packets::Resource,
- resources::{Image, MeshPart, Prefab},
-};
-use wgpu::{
- AddressMode, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout,
- BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, BlendState,
- Buffer, BufferBindingType, BufferUsages, Color, ColorTargetState, ColorWrites,
- CommandEncoderDescriptor, CompareFunction, DepthBiasState, DepthStencilState, Device, Extent3d,
- Face, FilterMode, FragmentState, FrontFace, ImageDataLayout, LoadOp, MultisampleState,
- Operations, PipelineCompilationOptions, PipelineLayoutDescriptor, PolygonMode, PrimitiveState,
- PrimitiveTopology, PushConstantRange, Queue, RenderPassColorAttachment, RenderPassDescriptor,
- RenderPipeline, RenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, ShaderStages,
- StencilState, StoreOp, Texture, TextureAspect, TextureDescriptor, TextureDimension,
- TextureFormat, TextureSampleType, TextureUsages, TextureViewDescriptor, TextureViewDimension,
- VertexAttribute, VertexBufferLayout, VertexFormat, VertexState, VertexStepMode, include_wgsl,
- util::{BufferInitDescriptor, DeviceExt},
-};
-
-pub struct DemandMap<K, V> {
- inner: RwLock<DemandMapState<K, V>>,
-}
-struct DemandMapState<K, V> {
- values: HashMap<K, V>,
- needed: HashSet<K>,
- size_metric: usize,
-}
-impl<K: Hash + Eq + Clone, V: Clone> DemandMap<K, V> {
- pub fn new() -> Self {
- Self {
- inner: DemandMapState {
- needed: HashSet::new(),
- values: HashMap::new(),
- size_metric: 0,
- }
- .into(),
- }
- }
- pub fn needed(&self) -> Vec<K> {
- self.inner.read().unwrap().needed.iter().cloned().collect()
- }
- pub fn insert(&self, key: K, value: V, size: usize) {
- let mut s = self.inner.write().unwrap();
- s.needed.remove(&key);
- s.values.insert(key, value);
- s.size_metric += size;
- }
- pub fn try_get(&self, key: K) -> Option<V> {
- let mut s = self.inner.write().unwrap();
- if let Some(k) = s.values.get(&key) {
- Some(k.to_owned())
- } else {
- s.needed.insert(key);
- None
- }
- }
-}
-
-struct GraphicsConfig {
- max_anisotropy: u16,
- max_mip_count: u32,
-}
-
-pub struct ScenePreparer {
- device: Arc<Device>,
- queue: Arc<Queue>,
- layouts: SceneBgLayouts,
- shaders: SceneShaders,
- render_format: TextureFormat,
- config: GraphicsConfig,
-
- textures: DemandMap<TextureSpec, (Arc<Texture>, Arc<BindGroup>)>,
- placeholder_textures: DemandMap<TextureIdentityKind, (Arc<Texture>, Arc<BindGroup>)>,
- index_buffers: DemandMap<Resource<Vec<[u32; 3]>>, (Arc<Buffer>, u32)>,
- vertex_buffers: DemandMap<Resource<Vec<f32>>, Arc<Buffer>>,
- generated_tangent_buffers: DemandMap<TangentBufferSpec, Arc<Buffer>>,
- generated_normal_buffers: DemandMap<NormalBufferSpec, Arc<Buffer>>,
- generated_texcoord_buffers: DemandMap<TexcoordBufferSpec, Arc<Buffer>>,
- mesh_parts: DemandMap<Resource<MeshPart>, Arc<RMeshPart>>,
- materials: DemandMap<Material, Arc<BindGroup>>,
- pipelines: DemandMap<PipelineSpec, Arc<RenderPipeline>>,
- mip_generation_pipelines: DemandMap<TextureFormat, Arc<MipGenerationPipeline>>,
- pub prefabs: DemandMap<Resource<Prefab>, Arc<RPrefab>>,
-}
-
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
-pub struct PipelineSpec {
- format: TextureFormat,
- skin: bool,
- backface_culling: bool,
-}
-
-pub struct RPrefab(pub Vec<(Affine3A, Arc<RMeshPart>)>);
-pub struct RMeshPart {
- pub pipeline: Arc<RenderPipeline>,
- pub index_count: u32,
- pub index: Arc<Buffer>,
- pub va_position: Arc<Buffer>,
- pub va_normal: Arc<Buffer>,
- pub va_tangent: Arc<Buffer>,
- pub va_texcoord: Arc<Buffer>,
- pub tex_albedo: Arc<BindGroup>,
- pub tex_normal: Arc<BindGroup>,
- pub material: Arc<BindGroup>,
- pub double_sided: bool,
-
- pub va_joint_index: Option<Arc<Buffer>>,
- pub va_joint_weight: Option<Arc<Buffer>>,
- pub joint_uniform: Option<Arc<Buffer>>,
-}
-
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
-struct TextureSpec {
- data: Resource<Image<'static>>,
- linear: bool,
-}
-
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
-struct TangentBufferSpec {
- index: Resource<Vec<[u32; 3]>>,
- position: Resource<Vec<Vec3>>,
- texcoord: Option<Resource<Vec<Vec2>>>,
-}
-
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
-struct NormalBufferSpec {
- index: Resource<Vec<[u32; 3]>>,
- position: Resource<Vec<Vec3>>,
-}
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
-struct TexcoordBufferSpec {
- index: Resource<Vec<[u32; 3]>>,
- position: Resource<Vec<Vec3>>,
-}
-
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
-enum TextureIdentityKind {
- Normal,
- Multiply,
-}
-
-#[derive(Debug, Clone, Copy, Pod, Zeroable, Hash, PartialEq, Eq)]
-#[repr(C)]
-struct Material {
- roughness: u32,
- metallic: u32,
- _pad1: [u32; 2],
- albedo_alpha: UVec4,
- emission: UVec3,
- _pad2: u32,
-}
-
-impl ScenePreparer {
- pub fn new(device: Arc<Device>, queue: Arc<Queue>, render_format: TextureFormat) -> Self {
- Self {
- // TODO normal mipmap requires linear texture, also demand map?
- render_format,
- config: GraphicsConfig {
- max_anisotropy: 16,
- max_mip_count: 16,
- },
- layouts: SceneBgLayouts::load(&device),
- shaders: SceneShaders::load(&device),
- device,
- queue,
- index_buffers: DemandMap::new(),
- vertex_buffers: DemandMap::new(),
- mesh_parts: DemandMap::new(),
- prefabs: DemandMap::new(),
- textures: DemandMap::new(),
- placeholder_textures: DemandMap::new(),
- generated_tangent_buffers: DemandMap::new(),
- generated_normal_buffers: DemandMap::new(),
- generated_texcoord_buffers: DemandMap::new(),
- materials: DemandMap::new(),
- pipelines: DemandMap::new(),
- mip_generation_pipelines: DemandMap::new(),
- }
- }
- pub fn update(&self, dls: &Downloader) -> Result<usize> {
- let mut num_done = 0;
- for pres in self.prefabs.needed() {
- if let Some(prefab) = dls.try_get(pres.clone())? {
- let mut rprefab = RPrefab(Vec::new());
- for (aff, partres) in &prefab.mesh {
- if let Some(part) = self.mesh_parts.try_get(partres.clone()) {
- rprefab.0.push((*aff, part.clone()));
- }
- }
- if rprefab.0.len() == prefab.mesh.len() {
- self.prefabs.insert(pres.clone(), Arc::new(rprefab), 0);
- debug!("prefab created ({pres})");
- num_done += 1;
- }
- }
- }
- for pres in self.index_buffers.needed() {
- let start = Instant::now();
- if let Some(buf) = dls.try_get(pres.clone())? {
- let buffer = self.device.create_buffer_init(&BufferInitDescriptor {
- label: Some("index"),
- contents: bytemuck::cast_slice(buf.as_slice()),
- usage: BufferUsages::INDEX | BufferUsages::COPY_DST,
- });
- self.index_buffers.insert(
- pres.clone(),
- (Arc::new(buffer), (buf.len() * 3) as u32),
- buf.len() * size_of::<u32>() * 3,
- );
- debug!(
- "index buffer created (len={}, took {:?}) {pres}",
- buf.len() / size_of::<u32>(),
- start.elapsed(),
- );
- num_done += 1;
- }
- }
- for pres in self.vertex_buffers.needed() {
- let start = Instant::now();
- if let Some(buf) = dls.try_get(pres.clone())? {
- let buffer = self.device.create_buffer_init(&BufferInitDescriptor {
- contents: bytemuck::cast_slice(buf.as_slice()),
- label: Some("vertex attribute"),
- usage: BufferUsages::VERTEX | BufferUsages::COPY_DST,
- });
- self.vertex_buffers.insert(
- pres.clone(),
- Arc::new(buffer),
- buf.len() * size_of::<f32>(),
- );
- debug!(
- "vertex attribute buffer created (len={}, took {:?}) {pres}",
- buf.len() / size_of::<f32>(),
- start.elapsed()
- );
- num_done += 1;
- }
- }
- for format in self.mip_generation_pipelines.needed() {
- self.mip_generation_pipelines.insert(
- format,
- Arc::new(MipGenerationPipeline::load(&self.device, format)),
- 0,
- );
- }
- for spec in self.textures.needed() {
- let start = Instant::now();
- let format = if spec.linear {
- TextureFormat::Rgba8Unorm
- } else {
- TextureFormat::Rgba8UnormSrgb
- };
- if let Some(mipgen) = self.mip_generation_pipelines.try_get(format) {
- if let Some(buf) = dls.try_get(spec.data.clone())? {
- let image = ImageReader::new(Cursor::new(buf.0)).with_guessed_format()?;
- let image = image.decode()?;
- let dims = (image.width(), image.height());
- let image = image.into_rgba8();
- let image = image.into_vec();
- let tex_bg = create_texture(
- &self.device,
- &self.queue,
- &self.layouts.texture,
- &image,
- dims.0,
- dims.1,
- format,
- Some(&mipgen),
- &self.config,
- );
- self.textures.insert(spec, tex_bg, image.len());
- debug!(
- "texture created (res={}x{}, took {:?})",
- dims.0,
- dims.1,
- start.elapsed()
- );
- num_done += 1;
- }
- }
- }
- for kind in self.placeholder_textures.needed() {
- let (linear, color) = match kind {
- TextureIdentityKind::Normal => (true, [128, 128, 255, 255]),
- TextureIdentityKind::Multiply => (false, [255, 255, 255, 255]),
- };
- let tex_bg = create_texture(
- &self.device,
- &self.queue,
- &self.layouts.texture,
- &color,
- 1,
- 1,
- if linear {
- TextureFormat::Rgba8Unorm
- } else {
- TextureFormat::Rgba8UnormSrgb
- },
- None,
- &self.config,
- );
- self.placeholder_textures.insert(kind, tex_bg, 4);
- num_done += 1;
- }
- for spec in self.generated_tangent_buffers.needed() {
- if let (Some(index), Some(position), texcoord) = (
- dls.try_get(spec.index.clone())?,
- dls.try_get(spec.position.clone())?,
- spec.texcoord.clone().map(|r| dls.try_get(r)).transpose()?,
- ) {
- let texcoord = match texcoord {
- Some(Some(x)) => Some(x),
- Some(None) => continue, // tangents provided but still loading
- None => None,
- };
- let texcoord = texcoord.unwrap_or_else(|| generate_texcoords(&index, &position));
- let tangents = generate_tangents(&index, &position, &texcoord);
- let buffer = self.device.create_buffer_init(&BufferInitDescriptor {
- label: Some("generated tangent"),
- usage: BufferUsages::COPY_DST | BufferUsages::VERTEX,
- contents: bytemuck::cast_slice(tangents.as_slice()),
- });
- self.generated_tangent_buffers.insert(
- spec,
- Arc::new(buffer),
- size_of::<f32>() * tangents.len() * 3,
- );
- }
- }
- for spec in self.generated_normal_buffers.needed() {
- if let (Some(index), Some(position)) = (
- dls.try_get(spec.index.clone())?,
- dls.try_get(spec.position.clone())?,
- ) {
- let normals = generate_normals(&index, &position);
- let buffer = self.device.create_buffer_init(&BufferInitDescriptor {
- label: Some("generated normal"),
- usage: BufferUsages::COPY_DST | BufferUsages::VERTEX,
- contents: bytemuck::cast_slice(normals.as_slice()),
- });
- self.generated_normal_buffers.insert(
- spec,
- Arc::new(buffer),
- size_of::<f32>() * normals.len() * 3,
- );
- }
- }
- for spec in self.generated_texcoord_buffers.needed() {
- if let (Some(index), Some(position)) = (
- dls.try_get(spec.index.clone())?,
- dls.try_get(spec.position.clone())?,
- ) {
- let texcoords = generate_texcoords(&index, &position);
- let buffer = self.device.create_buffer_init(&BufferInitDescriptor {
- label: Some("generated texcoord"),
- usage: BufferUsages::COPY_DST | BufferUsages::VERTEX,
- contents: bytemuck::cast_slice(texcoords.as_slice()),
- });
- self.generated_texcoord_buffers.insert(
- spec,
- Arc::new(buffer),
- size_of::<f32>() * texcoords.len() * 3,
- );
- }
- }
- for spec in self.materials.needed() {
- let buffer = self.device.create_buffer_init(&BufferInitDescriptor {
- label: Some("material props"),
- usage: BufferUsages::COPY_DST | BufferUsages::UNIFORM,
- contents: bytemuck::cast_slice(&[spec]),
- });
- let bind_group = self.device.create_bind_group(&BindGroupDescriptor {
- label: Some("material"),
- layout: &self.layouts.material,
- entries: &[BindGroupEntry {
- binding: 0,
- resource: buffer.as_entire_binding(),
- }],
- });
- self.materials.insert(spec, Arc::new(bind_group), 0);
- }
- for spec in self.pipelines.needed() {
- self.pipelines.insert(
- spec.clone(),
- Arc::new(spec.create(&self.device, &self.layouts, &self.shaders)),
- 0,
- );
- }
- for pres in self.mesh_parts.needed() {
- let start = Instant::now();
- if let Some(part) = dls.try_get(pres.clone())? {
- if let (Some(indexres), Some(positionres)) = (part.index, part.va_position) {
- let index = self.index_buffers.try_get(indexres.clone());
- let position = self
- .vertex_buffers
- .try_get(Resource(positionres.0, PhantomData));
-
- let normal = if let Some(res) = part.va_normal.clone() {
- self.vertex_buffers.try_get(Resource(res.0, PhantomData))
- } else {
- self.generated_normal_buffers.try_get(NormalBufferSpec {
- index: indexres.clone(),
- position: Resource(positionres.0, PhantomData),
- })
- };
-
- let texcoord = if let Some(res) = part.va_texcoord.clone() {
- self.vertex_buffers.try_get(Resource(res.0, PhantomData))
- } else {
- self.generated_texcoord_buffers.try_get(TexcoordBufferSpec {
- index: indexres.clone(),
- position: Resource(positionres.0, PhantomData),
- })
- };
- let tangent = if let Some(res) = part.va_tangent.clone() {
- self.vertex_buffers.try_get(Resource(res.0, PhantomData))
- } else {
- self.generated_tangent_buffers.try_get(TangentBufferSpec {
- index: indexres,
- position: Resource(positionres.0, PhantomData),
- texcoord: part.va_texcoord,
- })
- };
-
- let joint_weight = if let Some(res) = part.va_joint_weight.clone() {
- self.vertex_buffers
- .try_get(Resource(res.0, PhantomData))
- .map(Some)
- } else {
- Some(None)
- };
- let joint_index = if let Some(res) = part.va_joint_index.clone() {
- self.vertex_buffers
- .try_get(Resource(res.0, PhantomData))
- .map(Some)
- } else {
- Some(None)
- };
-
- let mut tex_albedo = None;
- if let Some(albedores) = part.tex_albedo {
- if let Some((_tex, bg)) = self.textures.try_get(TextureSpec {
- data: albedores,
- linear: false,
- }) {
- tex_albedo = Some(bg)
- }
- } else {
- if let Some((_tex, bg)) = self
- .placeholder_textures
- .try_get(TextureIdentityKind::Multiply)
- {
- tex_albedo = Some(bg)
- }
- }
- let mut tex_normal = None;
- if let Some(normalres) = part.tex_normal {
- if let Some((_tex, bg)) = self.textures.try_get(TextureSpec {
- data: normalres,
- linear: true,
- }) {
- tex_normal = Some(bg)
- }
- } else {
- if let Some((_tex, bg)) = self
- .placeholder_textures
- .try_get(TextureIdentityKind::Normal)
- {
- tex_normal = Some(bg)
- }
- }
-
- let material = self.materials.try_get({
- let albedo = part.g_albedo.unwrap_or(Vec3A::ONE);
- let emission = part.g_emission.unwrap_or(Vec3A::ONE);
- Material {
- roughness: part.g_roughness.unwrap_or(1.).to_bits(),
- metallic: part.g_metallic.unwrap_or(0.).to_bits(),
- _pad1: [0, 0],
- albedo_alpha: uvec4(
- albedo.x.to_bits(),
- albedo.y.to_bits(),
- albedo.z.to_bits(),
- part.g_alpha.unwrap_or(1.).to_bits(),
- ),
- emission: uvec3(
- emission.x.to_bits(),
- emission.y.to_bits(),
- emission.z.to_bits(),
- ),
- _pad2: 0,
- }
- });
-
- let armature = if let Some(res) = part.armature.clone() {
- Some(dls.try_get(res)?)
- } else {
- Some(None)
- };
-
- let pipeline = self.pipelines.try_get(PipelineSpec {
- format: self.render_format,
- skin: false,
- backface_culling: part.g_double_sided.is_none(),
- });
-
- if let (
- Some(pipeline),
- Some((index, index_count)),
- Some(va_normal),
- Some(va_tangent),
- Some(va_texcoord),
- Some(va_position),
- Some(va_joint_index),
- Some(va_joint_weight),
- Some(armature),
- Some(tex_normal),
- Some(tex_albedo),
- Some(material),
- ) = (
- pipeline,
- index,
- normal,
- tangent,
- texcoord,
- position,
- joint_index,
- joint_weight,
- armature,
- tex_normal,
- tex_albedo,
- material,
- ) {
- let double_sided = part.g_double_sided.is_some();
-
- let joint_uniform = if let Some(a) = armature {
- let ra = RArmature::new(&self.device, a);
- Some(ra.joint_mat_uniform_buffer.clone())
- } else {
- None
- };
-
- debug!("part created (took {:?}) {pres}", start.elapsed());
- self.mesh_parts.insert(
- pres,
- Arc::new(RMeshPart {
- pipeline,
- index_count,
- index,
- va_normal,
- va_tangent,
- va_position,
- va_texcoord,
- va_joint_index,
- va_joint_weight,
- tex_albedo,
- tex_normal,
- material,
- double_sided,
- joint_uniform,
- }),
- 0,
- );
- num_done += 1;
- }
- }
- }
- }
- self.print_missing();
- Ok(num_done)
- }
-}
-
-struct MipGenerationPipeline {
- pipeline: RenderPipeline,
-}
-impl MipGenerationPipeline {
- pub fn load(device: &Device, format: TextureFormat) -> Self {
- let shader = device.create_shader_module(include_wgsl!("shaders/texture_copy.wgsl"));
- let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
- label: Some("mip generator"),
- layout: None,
- vertex: wgpu::VertexState {
- module: &shader,
- entry_point: Some("vs_main"),
- compilation_options: Default::default(),
- buffers: &[],
- },
- fragment: Some(wgpu::FragmentState {
- module: &shader,
- entry_point: Some("fs_main"),
- compilation_options: Default::default(),
- targets: &[Some(ColorTargetState {
- format,
- blend: None,
- write_mask: ColorWrites::ALL,
- })],
- }),
- primitive: wgpu::PrimitiveState {
- topology: wgpu::PrimitiveTopology::TriangleList,
- ..Default::default()
- },
- depth_stencil: None,
- multisample: wgpu::MultisampleState::default(),
- multiview: None,
- cache: None,
- });
- Self { pipeline }
- }
-}
-
-fn create_texture(
- device: &Device,
- queue: &Queue,
- bgl: &BindGroupLayout,
- data: &[u8],
- width: u32,
- height: u32,
- format: TextureFormat,
- mipgen: Option<&MipGenerationPipeline>,
- config: &GraphicsConfig,
-) -> (Arc<Texture>, Arc<BindGroup>) {
- let mip_level_count = (width.ilog2().max(4) - 3).min(config.max_mip_count);
-
- let extent = Extent3d {
- depth_or_array_layers: 1,
- width,
- height,
- };
- let texture = device.create_texture(&TextureDescriptor {
- label: None,
- size: extent,
- mip_level_count,
- sample_count: 1,
- dimension: TextureDimension::D2,
- format,
- usage: TextureUsages::TEXTURE_BINDING
- | TextureUsages::COPY_DST
- | TextureUsages::RENDER_ATTACHMENT,
- view_formats: &[],
- });
- let textureview = texture.create_view(&TextureViewDescriptor::default());
- let sampler = device.create_sampler(&SamplerDescriptor {
- address_mode_u: AddressMode::Repeat,
- address_mode_v: AddressMode::Repeat,
- mag_filter: FilterMode::Linear,
- min_filter: FilterMode::Linear,
- mipmap_filter: FilterMode::Linear,
- anisotropy_clamp: config.max_anisotropy,
- ..Default::default()
- });
- let bind_group = device.create_bind_group(&BindGroupDescriptor {
- label: None,
- layout: &bgl,
- entries: &[
- BindGroupEntry {
- binding: 0,
- resource: BindingResource::TextureView(&textureview),
- },
- BindGroupEntry {
- binding: 1,
- resource: BindingResource::Sampler(&sampler),
- },
- ],
- });
-
- let level_views = (0..mip_level_count)
- .map(|mip| {
- texture.create_view(&TextureViewDescriptor {
- label: Some("mip generation level view"),
- format: None,
- dimension: None,
- aspect: TextureAspect::All,
- base_mip_level: mip,
- mip_level_count: Some(1),
- base_array_layer: 0,
- array_layer_count: None,
- })
- })
- .collect::<Vec<_>>();
-
- let mut encoder = device.create_command_encoder(&CommandEncoderDescriptor { label: None });
-
- // TODO why does copy_buffer_to_texture have more restrictive alignment requirements?!
- // let upload_buffer = device.create_buffer_init(&BufferInitDescriptor {
- // label: Some("texture upload"),
- // contents: data,
- // usage: BufferUsages::COPY_DST | BufferUsages::COPY_SRC,
- // });
- // encoder.copy_buffer_to_texture(
- // ImageCopyBuffer {
- // buffer: &upload_buffer,
- // layout: ImageDataLayout {
- // offset: 0,
- // bytes_per_row: Some(width * 4),
- // rows_per_image: None,
- // },
- // },
- // texture.as_image_copy(),
- // extent,
- // );
- queue.write_texture(
- texture.as_image_copy(),
- data,
- ImageDataLayout {
- bytes_per_row: Some(width * 4),
- rows_per_image: None,
- offset: 0,
- },
- extent,
- );
-
- for level in 1..mip_level_count {
- let mip_pipeline = &mipgen.unwrap().pipeline;
- let source_view = &level_views[level as usize - 1];
- let target_view = &level_views[level as usize];
- let mip_bind_group = device.create_bind_group(&BindGroupDescriptor {
- layout: &mip_pipeline.get_bind_group_layout(0),
- entries: &[
- BindGroupEntry {
- binding: 0,
- resource: BindingResource::TextureView(source_view),
- },
- BindGroupEntry {
- binding: 1,
- resource: BindingResource::Sampler(&sampler),
- },
- ],
- label: None,
- });
- let mut rpass = encoder.begin_render_pass(&RenderPassDescriptor {
- label: None,
- color_attachments: &[Some(RenderPassColorAttachment {
- view: target_view,
- resolve_target: None,
- ops: Operations {
- load: LoadOp::Clear(Color::WHITE),
- store: StoreOp::Store,
- },
- })],
- depth_stencil_attachment: None,
- timestamp_writes: None,
- occlusion_query_set: None,
- });
-
- rpass.set_pipeline(&mip_pipeline);
- rpass.set_bind_group(0, &mip_bind_group, &[]);
- rpass.draw(0..3, 0..1);
- }
-
- queue.submit(Some(encoder.finish()));
-
- (Arc::new(texture), Arc::new(bind_group))
-}
-
-pub struct SceneBgLayouts {
- pub texture: BindGroupLayout,
- pub material: BindGroupLayout,
- pub joints: BindGroupLayout,
-}
-impl SceneBgLayouts {
- pub fn load(device: &Device) -> Self {
- Self {
- texture: device.create_bind_group_layout(&BindGroupLayoutDescriptor {
- entries: &[
- BindGroupLayoutEntry {
- binding: 0,
- count: None,
- visibility: ShaderStages::FRAGMENT,
- ty: BindingType::Texture {
- sample_type: TextureSampleType::Float { filterable: true },
- view_dimension: TextureViewDimension::D2,
- multisampled: false,
- },
- },
- BindGroupLayoutEntry {
- binding: 1,
- count: None,
- visibility: ShaderStages::FRAGMENT,
- ty: BindingType::Sampler(SamplerBindingType::Filtering),
- },
- ],
- label: None,
- }),
- material: device.create_bind_group_layout(&BindGroupLayoutDescriptor {
- entries: &[BindGroupLayoutEntry {
- binding: 0,
- count: None,
- visibility: ShaderStages::FRAGMENT,
- ty: BindingType::Buffer {
- ty: BufferBindingType::Uniform,
- has_dynamic_offset: false,
- min_binding_size: None,
- },
- }],
- label: None,
- }),
- joints: device.create_bind_group_layout(&BindGroupLayoutDescriptor {
- entries: &[BindGroupLayoutEntry {
- binding: 0,
- count: None,
- visibility: ShaderStages::VERTEX,
- ty: BindingType::Buffer {
- ty: BufferBindingType::Uniform,
- has_dynamic_offset: false,
- min_binding_size: None,
- },
- }],
- label: None,
- }),
- }
- }
-}
-
-impl PipelineSpec {
- pub fn create(
- &self,
- device: &Device,
- layouts: &SceneBgLayouts,
- shaders: &SceneShaders,
- ) -> RenderPipeline {
- let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
- label: None,
- bind_group_layouts: &[&layouts.texture, &layouts.texture, &layouts.material],
- push_constant_ranges: &[PushConstantRange {
- // 4x4 view projections
- // 3x3(+1 pad) model basis
- range: 0..((4 * 4 + 3 * 4) * size_of::<f32>() as u32),
- stages: ShaderStages::VERTEX,
- }],
- });
- device.create_render_pipeline(&RenderPipelineDescriptor {
- label: None,
- layout: Some(&pipeline_layout),
- fragment: Some(FragmentState {
- module: &shaders.fragment_pbr,
- entry_point: Some("main"),
- targets: &[Some(ColorTargetState {
- blend: Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING),
- format: self.format,
- write_mask: ColorWrites::all(),
- })],
- compilation_options: PipelineCompilationOptions::default(),
- }),
- vertex: VertexState {
- module: if self.skin {
- &shaders.vertex_world_skin
- } else {
- &shaders.vertex_world
- },
- entry_point: Some("main"),
- buffers: &[
- // position
- VertexBufferLayout {
- step_mode: VertexStepMode::Vertex,
- array_stride: 3 * size_of::<f32>() as u64,
- attributes: &[VertexAttribute {
- format: VertexFormat::Float32x3,
- offset: 0,
- shader_location: 0,
- }],
- },
- // normal
- VertexBufferLayout {
- step_mode: VertexStepMode::Vertex,
- array_stride: 3 * size_of::<f32>() as u64,
- attributes: &[VertexAttribute {
- format: VertexFormat::Float32x3,
- offset: 0,
- shader_location: 1,
- }],
- },
- // tangent
- VertexBufferLayout {
- step_mode: VertexStepMode::Vertex,
- array_stride: 3 * size_of::<f32>() as u64,
- attributes: &[VertexAttribute {
- format: VertexFormat::Float32x3,
- offset: 0,
- shader_location: 2,
- }],
- },
- // texcoord
- VertexBufferLayout {
- step_mode: VertexStepMode::Vertex,
- array_stride: 2 * size_of::<f32>() as u64,
- attributes: &[VertexAttribute {
- format: VertexFormat::Float32x2,
- offset: 0,
- shader_location: 3,
- }],
- },
- ],
- compilation_options: PipelineCompilationOptions::default(),
- },
- primitive: PrimitiveState {
- topology: PrimitiveTopology::TriangleList,
- front_face: FrontFace::Ccw,
- cull_mode: if self.backface_culling {
- Some(Face::Back)
- } else {
- None
- },
- polygon_mode: PolygonMode::Fill,
- ..Default::default()
- },
- depth_stencil: Some(DepthStencilState {
- depth_write_enabled: true,
- depth_compare: CompareFunction::Less,
- format: TextureFormat::Depth32Float,
- bias: DepthBiasState::default(),
- stencil: StencilState::default(),
- }),
- multisample: MultisampleState::default(),
- multiview: None,
- cache: None,
- })
- }
-}
-
-impl<K, V> Widget for &DemandMap<K, V> {
- fn ui(self, ui: &mut egui::Ui) -> egui::Response {
- let state = self.inner.read().unwrap();
- ui.label(state.needed.len().to_string());
- ui.label(state.values.len().to_string());
- ui.label(humansize::format_size(state.size_metric, DECIMAL));
- ui.end_row();
- ui.response()
- }
-}
-impl ScenePreparer {
- pub fn print_missing(&self) {
- fn visit<K, V>(name: &str, m: &DemandMap<K, V>)
- where
- K: Clone,
- K: Hash,
- K: std::cmp::Eq,
- V: Clone,
- {
- let nl = m.needed().len();
- if nl > 0 {
- trace!("{name}: need {nl}")
- }
- }
- visit("prefabs", &self.prefabs);
- visit("mesh_parts", &self.mesh_parts);
- visit("vertex_buffers", &self.vertex_buffers);
- visit("index_buffers", &self.index_buffers);
- visit("placeholder_textures", &self.placeholder_textures);
- visit("generated_tangent_buffers", &self.generated_tangent_buffers);
- visit("generated_normal_buffers", &self.generated_normal_buffers);
- visit(
- "generated_texcoord_buffers",
- &self.generated_texcoord_buffers,
- );
- visit("textures", &self.textures);
- visit("materials", &self.materials);
- visit("pipelines", &self.pipelines);
- }
-}
-
-impl Widget for &ScenePreparer {
- fn ui(self, ui: &mut egui::Ui) -> egui::Response {
- Grid::new("sp")
- .num_columns(4)
- .show(ui, |ui| {
- ui.label("prefabs");
- self.prefabs.ui(ui);
- ui.label("mesh_parts");
- self.mesh_parts.ui(ui);
- ui.label("vertex_buffers");
- self.vertex_buffers.ui(ui);
- ui.label("index_buffers");
- self.index_buffers.ui(ui);
- ui.label("placeholder_textures");
- self.placeholder_textures.ui(ui);
- ui.label("generated_tangent_buffers");
- self.generated_tangent_buffers.ui(ui);
- ui.label("generated_normal_buffers");
- self.generated_normal_buffers.ui(ui);
- ui.label("generated_texcoord_buffers");
- self.generated_texcoord_buffers.ui(ui);
- ui.label("textures");
- self.textures.ui(ui);
- ui.label("materials");
- self.materials.ui(ui);
- ui.label("pipelines");
- self.pipelines.ui(ui);
- })
- .response
- }
-}