summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/src/main.rs1
-rw-r--r--client/src/renderer.rs28
-rw-r--r--client/src/scene_prepare.rs111
-rw-r--r--client/src/scene_render.rs30
-rw-r--r--client/src/shader.wgsl33
5 files changed, 141 insertions, 62 deletions
diff --git a/client/src/main.rs b/client/src/main.rs
index cfbd052..1b615d1 100644
--- a/client/src/main.rs
+++ b/client/src/main.rs
@@ -1,3 +1,4 @@
+#![feature(iter_array_chunks)]
pub mod download;
pub mod network;
pub mod renderer;
diff --git a/client/src/renderer.rs b/client/src/renderer.rs
index 7116a20..34450b2 100644
--- a/client/src/renderer.rs
+++ b/client/src/renderer.rs
@@ -1,7 +1,8 @@
-use crate::{download::Downloader, scene_prepare::ScenePreparer, scene_render::ScenePipeline};
-use anyhow::{Context, Result, anyhow};
+use crate::{scene_prepare::ScenePreparer, scene_render::ScenePipeline};
+use anyhow::{Result, anyhow};
use log::{info, warn};
use pollster::FutureExt;
+use std::sync::Arc;
use weareshared::tree::SceneTree;
use wgpu::{
Backends, CommandEncoderDescriptor, Device, DeviceDescriptor, Features, Instance,
@@ -13,10 +14,11 @@ use winit::window::Window;
pub struct Renderer<'a> {
surface: Surface<'a>,
queue: Queue,
- device: Device,
+ device: Arc<Device>,
surface_configuration: SurfaceConfiguration,
scene_pipeline: ScenePipeline,
pub scene_prepare: ScenePreparer,
+ surface_needs_reconfigure: bool,
}
impl<'a> Renderer<'a> {
pub fn new(window: &'a Window) -> Result<Self> {
@@ -39,8 +41,11 @@ impl<'a> Renderer<'a> {
let (device, queue) = adapter
.request_device(
&DeviceDescriptor {
- required_features: Features::default(),
- required_limits: Limits::downlevel_defaults(),
+ required_features: Features::PUSH_CONSTANTS,
+ required_limits: Limits {
+ max_push_constant_size: 48,
+ ..Limits::default()
+ },
..Default::default()
},
None,
@@ -53,13 +58,16 @@ impl<'a> Renderer<'a> {
surface.configure(&device, &surface_configuration);
+ let device = Arc::new(device);
+
Ok(Self {
scene_pipeline: ScenePipeline::new(&device, surface_configuration.format),
- scene_prepare: ScenePreparer::new(),
+ scene_prepare: ScenePreparer::new(device.clone()),
surface,
device,
queue,
surface_configuration,
+ surface_needs_reconfigure: false,
})
}
@@ -71,9 +79,15 @@ impl<'a> Renderer<'a> {
}
pub fn draw(&mut self, scene: &SceneTree) -> Result<()> {
+ if self.surface_needs_reconfigure {
+ self.surface
+ .configure(&self.device, &self.surface_configuration);
+ self.surface_needs_reconfigure = false
+ }
let target = self.surface.get_current_texture()?;
if target.suboptimal {
- warn!("suboptimal swapchain texture")
+ warn!("suboptimal swapchain texture");
+ self.surface_needs_reconfigure = true;
}
let target_view = target
.texture
diff --git a/client/src/scene_prepare.rs b/client/src/scene_prepare.rs
index 8d50fc3..47f168d 100644
--- a/client/src/scene_prepare.rs
+++ b/client/src/scene_prepare.rs
@@ -1,5 +1,6 @@
use crate::download::Downloader;
use anyhow::{Context, Result};
+use log::{debug, info};
use std::{
collections::{HashMap, HashSet},
sync::Arc,
@@ -8,8 +9,12 @@ use weareshared::{
Affine3A,
packets::{ReadWrite, Resource},
resources::{Attribute, Part, Prefab},
+ store::sha256,
+};
+use wgpu::{
+ Buffer, BufferUsages, Device,
+ util::{BufferInitDescriptor, DeviceExt},
};
-use wgpu::Buffer;
pub struct ScenePreparer {
index_buffers: HashMap<Resource, (Arc<Buffer>, u32)>,
@@ -20,6 +25,8 @@ pub struct ScenePreparer {
parts_needed: HashSet<Resource>,
pub prefabs: HashMap<Resource, RPrefab>,
pub prefabs_needed: HashSet<Resource>,
+
+ device: Arc<Device>,
}
pub struct RPrefab(pub Vec<(Affine3A, Arc<RPart>)>);
@@ -32,7 +39,7 @@ pub struct RPart {
}
impl ScenePreparer {
- pub fn new() -> Self {
+ pub fn new(device: Arc<Device>) -> Self {
Self {
index_buffers: HashMap::new(),
vertex_buffers: HashMap::new(),
@@ -42,6 +49,7 @@ impl ScenePreparer {
prefabs: HashMap::new(),
prefabs_needed: HashSet::new(),
index_buffers_needed: HashSet::new(),
+ device,
}
}
pub fn update(&mut self, dls: &mut Downloader) -> Result<()> {
@@ -59,12 +67,45 @@ impl ScenePreparer {
}
if rprefab.0.len() == prefab.0.len() {
self.prefabs.insert(*pres, rprefab);
+ debug!("prefab created ({pres})");
done.push(*pres);
}
}
}
for pres in &self.index_buffers_needed {
- if let Some(buf) = dls.try_get(*pres)? {}
+ if let Some(buf) = dls.try_get(*pres)? {
+ 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() as u32 / 2));
+ debug!("index buffer created (len={}) {pres}", buf.len() / 6);
+ done.push(*pres);
+ }
+ }
+ for pres in &self.vertex_buffers_needed {
+ 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::<Vec<_>>();
+ 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));
+ debug!(
+ "vertex attribute buffer created (len={}) {pres}",
+ buf.len() / 4
+ );
+ done.push(*pres);
+ }
}
for pres in &self.parts_needed {
if let Some(buf) = dls.try_get(*pres)? {
@@ -80,64 +121,72 @@ impl ScenePreparer {
self.index_buffers_needed.insert(indexres);
continue;
};
- let mut positions = Vec::new();
+ let mut position = Vec::new();
for vr in positionres {
match vr {
Attribute::Constant(_) => todo!(),
Attribute::Vertex(resource) => {
- let Some(vertex) = self.vertex_buffers.get(&resource).cloned()
- else {
- self.vertex_buffers_needed.insert(indexres);
- continue;
+ if let Some(vertex) = self.vertex_buffers.get(&resource).cloned() {
+ position.push(vertex);
+ } else {
+ self.vertex_buffers_needed.insert(resource);
};
- positions.push(vertex);
}
Attribute::Texture(_resource) => todo!(),
}
}
- let mut normals = Vec::new();
+ let mut normal = Vec::new();
for vr in normalres {
match vr {
Attribute::Constant(_) => todo!(),
Attribute::Vertex(resource) => {
- let Some(vertex) = self.vertex_buffers.get(&resource).cloned()
- else {
- self.vertex_buffers_needed.insert(indexres);
- continue;
+ if let Some(vertex) = self.vertex_buffers.get(&resource).cloned() {
+ normal.push(vertex);
+ } else {
+ self.vertex_buffers_needed.insert(resource);
};
- normals.push(vertex);
}
Attribute::Texture(_resource) => todo!(),
}
}
- let mut texcoords = Vec::new();
+ let mut texcoord = Vec::new();
for vr in texcoordres {
match vr {
Attribute::Constant(_) => todo!(),
Attribute::Vertex(resource) => {
- let Some(vertex) = self.vertex_buffers.get(&resource).cloned()
- else {
- self.vertex_buffers_needed.insert(indexres);
- continue;
+ if let Some(vertex) = self.vertex_buffers.get(&resource).cloned() {
+ texcoord.push(vertex);
+ } else {
+ self.vertex_buffers_needed.insert(resource);
};
- texcoords.push(vertex);
}
Attribute::Texture(_resource) => todo!(),
}
}
- self.parts.insert(
- *pres,
- Arc::new(RPart {
- index_count,
- index,
- texcoord: texcoords.try_into().unwrap(),
- normal: normals.try_into().unwrap(),
- position: positions.try_into().unwrap(),
- }),
- );
+ if texcoord.len() == 2 && normal.len() == 3 && position.len() == 3 {
+ debug!("part created ({pres})");
+ self.parts.insert(
+ *pres,
+ Arc::new(RPart {
+ index_count,
+ index,
+ texcoord: texcoord.try_into().unwrap(),
+ normal: normal.try_into().unwrap(),
+ position: position.try_into().unwrap(),
+ }),
+ );
+ done.push(*pres);
+ }
}
}
}
+
+ for d in done {
+ self.parts_needed.remove(&d);
+ self.prefabs_needed.remove(&d);
+ self.index_buffers_needed.remove(&d);
+ self.vertex_buffers_needed.remove(&d);
+ }
Ok(())
}
}
diff --git a/client/src/scene_render.rs b/client/src/scene_render.rs
index 366b956..b2cd915 100644
--- a/client/src/scene_render.rs
+++ b/client/src/scene_render.rs
@@ -4,7 +4,7 @@ use wgpu::{
BindGroup, BindGroupDescriptor, BindGroupLayoutDescriptor, BlendState, Color, ColorTargetState,
ColorWrites, CommandEncoder, Device, FragmentState, FrontFace, IndexFormat, LoadOp,
MultisampleState, Operations, PipelineCompilationOptions, PipelineLayoutDescriptor,
- PolygonMode, PrimitiveState, PrimitiveTopology, RenderPassColorAttachment,
+ PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange, RenderPassColorAttachment,
RenderPassDescriptor, RenderPipeline, RenderPipelineDescriptor, ShaderStages, StoreOp,
TextureFormat, TextureView, VertexAttribute, VertexBufferLayout, VertexFormat, VertexState,
VertexStepMode, include_wgsl,
@@ -33,7 +33,10 @@ impl ScenePipeline {
let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
label: None,
bind_group_layouts: &[&bind_group_layout],
- push_constant_ranges: &[],
+ push_constant_ranges: &[PushConstantRange {
+ range: 0..(12 * 4),
+ stages: ShaderStages::VERTEX,
+ }],
});
let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
label: None,
@@ -53,19 +56,12 @@ impl ScenePipeline {
entry_point: Some("vs_main"),
buffers: &[VertexBufferLayout {
step_mode: VertexStepMode::Vertex,
- array_stride: 2 * 4 * 3,
- attributes: &[
- VertexAttribute {
- format: VertexFormat::Float32x3,
- offset: 0,
- shader_location: 0,
- },
- VertexAttribute {
- format: VertexFormat::Float32x3,
- offset: 3 * 4,
- shader_location: 1,
- },
- ],
+ array_stride: 4,
+ attributes: &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(|i| VertexAttribute {
+ format: VertexFormat::Float32,
+ offset: 0,
+ shader_location: i,
+ }),
}],
compilation_options: PipelineCompilationOptions::default(),
},
@@ -111,13 +107,13 @@ impl ScenePipeline {
})],
..Default::default()
});
- rpass.set_bind_group(0, &self.bind_group, &[]);
- rpass.set_pipeline(&self.pipeline);
for ob in scene.objects.values() {
if let Some(prefab) = prefabs.get(&ob.res) {
for (affine, part) in &prefab.0 {
let affine = affine.to_cols_array().map(|v| v.to_le_bytes());
+ rpass.set_bind_group(0, &self.bind_group, &[]);
+ rpass.set_pipeline(&self.pipeline);
rpass.set_push_constants(ShaderStages::VERTEX, 0, affine.as_flattened());
rpass.set_index_buffer(part.index.slice(..), IndexFormat::Uint16);
rpass.set_vertex_buffer(0, part.position[0].slice(..));
diff --git a/client/src/shader.wgsl b/client/src/shader.wgsl
index 41c21d9..68bd93d 100644
--- a/client/src/shader.wgsl
+++ b/client/src/shader.wgsl
@@ -1,11 +1,30 @@
-@vertex
-fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {
- let x = f32(i32(in_vertex_index) % 2);
- let y = f32(i32(in_vertex_index & 1u) * 2 - 1);
- return vec4<f32>(x, y, 0.0, 1.0);
+
+struct VertexIn {
+ @location(0) x: f32,
+ @location(1) y: f32,
+ @location(2) z: f32,
+ @location(3) nx: f32,
+ @location(4) ny: f32,
+ @location(5) nz: f32,
+ @location(6) u: f32,
+ @location(7) v: f32,
+}
+struct VertexOut {
+ @builtin(position) clip: vec4<f32>,
+ @location(0) normal: vec3<f32>,
+ @location(1) uv: vec2<f32>,
}
+@vertex
+fn vs_main(vi: VertexIn) -> VertexOut {
+ let vo = VertexOut(
+ vec4(vi.x * 0.1, vi.y * 0.1, 0., 1.),
+ vec3(vi.nx, vi.ny, vi.nz),
+ vec2(vi.u, vi.v),
+ );
+ return vo;
+}
@fragment
-fn fs_main() -> @location(0) vec4<f32> {
- return vec4<f32>(1.0, 0.0, 0.0, 1.0);
+fn fs_main(vo: VertexOut) -> @location(0) vec4<f32> {
+ return vec4<f32>(vo.normal, 1.0);
}