summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/Cargo.toml1
-rw-r--r--client/src/renderer.rs15
-rw-r--r--client/src/scene_prepare.rs286
-rw-r--r--client/src/scene_render.rs109
-rw-r--r--client/src/shader.wgsl4
-rw-r--r--client/src/state.rs3
-rw-r--r--client/src/window.rs2
7 files changed, 299 insertions, 121 deletions
diff --git a/client/Cargo.toml b/client/Cargo.toml
index 4bcfb4c..da0f5c6 100644
--- a/client/Cargo.toml
+++ b/client/Cargo.toml
@@ -16,3 +16,4 @@ winit = "0.30.8"
weareshared = { path = "../shared" }
rand = "0.9.0-beta.1"
glam = "0.29.2"
+image = "0.25.5"
diff --git a/client/src/renderer.rs b/client/src/renderer.rs
index 3561d87..3591503 100644
--- a/client/src/renderer.rs
+++ b/client/src/renderer.rs
@@ -13,7 +13,7 @@ use winit::window::Window;
pub struct Renderer<'a> {
surface: Surface<'a>,
- queue: Queue,
+ queue: Arc<Queue>,
device: Arc<Device>,
surface_configuration: SurfaceConfiguration,
scene_pipeline: ScenePipeline,
@@ -60,10 +60,15 @@ impl<'a> Renderer<'a> {
surface.configure(&device, &surface_configuration);
let device = Arc::new(device);
+ let queue = Arc::new(queue);
+
+ let (scene_pipeline, texture_bgl) =
+ ScenePipeline::new(&device, surface_configuration.format);
+ let scene_prepare = ScenePreparer::new(device.clone(), queue.clone(), texture_bgl);
Ok(Self {
- scene_pipeline: ScenePipeline::new(&device, surface_configuration.format),
- scene_prepare: ScenePreparer::new(device.clone()),
+ scene_pipeline,
+ scene_prepare,
surface,
device,
queue,
@@ -77,6 +82,7 @@ impl<'a> Renderer<'a> {
self.surface_configuration.height = height;
self.surface
.configure(&self.device, &self.surface_configuration);
+ self.scene_pipeline.resize(&self.device, width, height);
}
pub fn draw(&mut self, scene: &SceneTree) -> Result<()> {
@@ -102,8 +108,7 @@ impl<'a> Renderer<'a> {
&mut commands,
&target_view,
scene,
- &self.scene_prepare.prefabs,
- &mut self.scene_prepare.prefabs_needed,
+ &mut self.scene_prepare.prefabs,
);
let i = self.queue.submit(Some(commands.finish()));
diff --git a/client/src/scene_prepare.rs b/client/src/scene_prepare.rs
index 85db160..f7a5bc8 100644
--- a/client/src/scene_prepare.rs
+++ b/client/src/scene_prepare.rs
@@ -1,31 +1,62 @@
use crate::download::Downloader;
use anyhow::{Context, Result};
+use image::{ImageFormat, ImageReader};
use log::debug;
use std::{
collections::{HashMap, HashSet},
+ hash::Hash,
+ io::Cursor,
sync::Arc,
};
use weareshared::{
Affine3A,
packets::{ReadWrite, Resource},
- resources::{Attribute, Part, Prefab},
+ resources::{Part, Prefab},
};
use wgpu::{
- Buffer, BufferUsages, Device,
- util::{BufferInitDescriptor, DeviceExt},
+ BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindingResource, Buffer,
+ BufferUsages, Device, Extent3d, Queue, SamplerDescriptor, Texture, TextureDescriptor,
+ TextureDimension, TextureFormat, TextureUsages, TextureViewDescriptor,
+ util::{BufferInitDescriptor, DeviceExt, TextureDataOrder},
};
-pub struct ScenePreparer {
- index_buffers: HashMap<Resource, (Arc<Buffer>, u32)>,
- index_buffers_needed: HashSet<Resource>,
- vertex_buffers: HashMap<Resource, Arc<Buffer>>,
- vertex_buffers_needed: HashSet<Resource>,
- parts: HashMap<Resource, Arc<RPart>>,
- parts_needed: HashSet<Resource>,
- pub prefabs: HashMap<Resource, RPrefab>,
- pub prefabs_needed: HashSet<Resource>,
+pub struct DemandMap<K, V> {
+ values: HashMap<K, V>,
+ needed: HashSet<K>,
+}
+impl<K: Hash + Eq, V: Clone> DemandMap<K, V> {
+ 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<V> {
+ if let Some(k) = self.values.get(&key) {
+ Some(k.to_owned())
+ } else {
+ self.needed.insert(key);
+ None
+ }
+ }
+}
+pub struct ScenePreparer {
device: Arc<Device>,
+ queue: Arc<Queue>,
+ texture_bgl: BindGroupLayout,
+
+ textures: DemandMap<Resource, (Arc<Texture>, Arc<BindGroup>)>,
+ placeholder_textures: DemandMap<(), (Arc<Texture>, Arc<BindGroup>)>,
+ index_buffers: DemandMap<Resource, (Arc<Buffer>, u32)>,
+ vertex_buffers: DemandMap<Resource, (Arc<Buffer>, u32)>,
+ placeholder_vertex_buffers: DemandMap<(u32, bool), Arc<Buffer>>,
+ parts: DemandMap<Resource, Arc<RPart>>,
+ pub prefabs: DemandMap<Resource, Arc<RPrefab>>,
}
pub struct RPrefab(pub Vec<(Affine3A, Arc<RPart>)>);
@@ -35,44 +66,42 @@ pub struct RPart {
pub position: [Arc<Buffer>; 3],
pub normal: [Arc<Buffer>; 3],
pub texcoord: [Arc<Buffer>; 2],
+ pub texture: Arc<BindGroup>,
}
impl ScenePreparer {
- pub fn new(device: Arc<Device>) -> Self {
+ pub fn new(device: Arc<Device>, queue: Arc<Queue>, texture_bgl: BindGroupLayout) -> Self {
Self {
- index_buffers: HashMap::new(),
- vertex_buffers: HashMap::new(),
- vertex_buffers_needed: HashSet::new(),
- parts: HashMap::new(),
- parts_needed: HashSet::new(),
- prefabs: HashMap::new(),
- prefabs_needed: HashSet::new(),
- index_buffers_needed: HashSet::new(),
+ texture_bgl,
+ index_buffers: DemandMap::new(),
+ vertex_buffers: DemandMap::new(),
+ 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<()> {
- let mut done = Vec::new();
- for pres in &self.prefabs_needed {
- if let Some(buf) = dls.try_get(*pres)? {
+ 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.0 {
- if let Some(part) = self.parts.get(partres) {
+ if let Some(part) = self.parts.try_get(*partres) {
rprefab.0.push((*aff, part.clone()));
- } else {
- self.parts_needed.insert(*partres);
}
}
if rprefab.0.len() == prefab.0.len() {
- self.prefabs.insert(*pres, rprefab);
+ self.prefabs.insert(pres, Arc::new(rprefab));
debug!("prefab created ({pres})");
- done.push(*pres);
}
}
}
- for pres in &self.index_buffers_needed {
- if let Some(buf) = dls.try_get(*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>()
@@ -86,13 +115,12 @@ impl ScenePreparer {
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);
+ .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 {
- if let Some(buf) = dls.try_get(*pres)? {
+ for pres in self.vertex_buffers.needed.clone() {
+ if let Some(buf) = dls.try_get(pres)? {
let buf = buf
.into_iter()
.array_chunks::<4>()
@@ -105,94 +133,174 @@ impl ScenePreparer {
label: None,
usage: BufferUsages::VERTEX | BufferUsages::COPY_DST,
});
- self.vertex_buffers.insert(*pres, Arc::new(buffer));
+ self.vertex_buffers
+ .insert(pres, (Arc::new(buffer), (buf.len() / 4) as u32));
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)? {
+ 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.parts.needed.clone() {
+ if let Some(buf) = dls.try_get(pres)? {
let part = Part::read(&mut buf.as_slice()).context("parsing part")?;
- if let (Some(indexres), Some(positionres), Some(normalres), Some(texcoordres)) = (
- part.index,
- part.va_position,
- part.va_normal,
- part.va_texcoord,
- ) {
- let Some((index, index_count)) = self.index_buffers.get(&indexres).cloned()
- else {
- self.index_buffers_needed.insert(indexres);
+ 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 {
- match vr {
- Attribute::Constant(_) => todo!(),
- Attribute::Vertex(resource) => {
- if let Some(vertex) = self.vertex_buffers.get(&resource).cloned() {
- position.push(vertex);
- } else {
- self.vertex_buffers_needed.insert(resource);
- };
- }
- Attribute::Texture(_resource, _ch) => todo!(),
+ if let Some((vertex, n)) = self.vertex_buffers.try_get(vr) {
+ vertex_count = n;
+ position.push(vertex);
}
}
let mut normal = Vec::new();
- for vr in normalres {
- match vr {
- Attribute::Constant(_) => todo!(),
- Attribute::Vertex(resource) => {
- if let Some(vertex) = self.vertex_buffers.get(&resource).cloned() {
- normal.push(vertex);
- } else {
- self.vertex_buffers_needed.insert(resource);
- };
+ 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);
}
- Attribute::Texture(_resource, _ch) => todo!(),
}
}
let mut texcoord = Vec::new();
- for vr in texcoordres {
- match vr {
- Attribute::Constant(_) => todo!(),
- Attribute::Vertex(resource) => {
- if let Some(vertex) = self.vertex_buffers.get(&resource).cloned() {
- texcoord.push(vertex);
- } else {
- self.vertex_buffers_needed.insert(resource);
- };
+ if let Some(texcoordres) = part.va_texcoord {
+ for vr in texcoordres {
+ if let Some((vertex, _)) = self.vertex_buffers.try_get(vr) {
+ texcoord.push(vertex);
}
- Attribute::Texture(_resource, _ch) => todo!(),
+ }
+ } 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_pbr_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 {
+
+ if texcoord.len() == 2
+ && normal.len() == 3
+ && position.len() == 3
+ && texture.is_some()
+ {
debug!("part created ({pres})");
self.parts.insert(
- *pres,
+ pres,
Arc::new(RPart {
index_count,
index,
texcoord: texcoord.try_into().unwrap(),
normal: normal.try_into().unwrap(),
position: position.try_into().unwrap(),
+ texture: texture.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(())
}
}
+
+fn create_texture(
+ device: &Device,
+ queue: &Queue,
+ bgl: &BindGroupLayout,
+ data: &[u8],
+ width: u32,
+ height: u32,
+) -> (Arc<Texture>, Arc<BindGroup>) {
+ 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))
+}
diff --git a/client/src/scene_render.rs b/client/src/scene_render.rs
index b4965e1..8703c9f 100644
--- a/client/src/scene_render.rs
+++ b/client/src/scene_render.rs
@@ -1,21 +1,24 @@
use glam::{EulerRot, Mat3, Mat4, Vec3, vec3};
-use std::collections::{HashMap, HashSet};
+use std::sync::Arc;
use weareshared::{packets::Resource, tree::SceneTree};
use wgpu::{
- BindGroup, BindGroupDescriptor, BindGroupLayoutDescriptor, BlendState, Color, ColorTargetState,
- ColorWrites, CommandEncoder, Device, FragmentState, FrontFace, IndexFormat, LoadOp,
+ BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState,
+ Color, ColorTargetState, ColorWrites, CommandEncoder, CompareFunction, DepthBiasState,
+ DepthStencilState, Device, Extent3d, FragmentState, FrontFace, IndexFormat, LoadOp,
MultisampleState, Operations, PipelineCompilationOptions, PipelineLayoutDescriptor,
PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange, RenderPassColorAttachment,
- RenderPassDescriptor, RenderPipeline, RenderPipelineDescriptor, ShaderStages, StoreOp,
- TextureFormat, TextureView, VertexAttribute, VertexBufferLayout, VertexFormat, VertexState,
- VertexStepMode, include_wgsl,
+ RenderPassDepthStencilAttachment, RenderPassDescriptor, RenderPipeline,
+ RenderPipelineDescriptor, SamplerBindingType, ShaderStages, StencilState, StoreOp,
+ TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType, TextureUsages,
+ TextureView, TextureViewDescriptor, TextureViewDimension, VertexAttribute, VertexBufferLayout,
+ VertexFormat, VertexState, VertexStepMode, include_wgsl,
};
-use crate::scene_prepare::RPrefab;
+use crate::scene_prepare::{DemandMap, RPrefab};
pub struct ScenePipeline {
pipeline: RenderPipeline,
- bind_group: BindGroup,
+ depth: TextureView,
}
macro_rules! v_attr {
@@ -33,17 +36,45 @@ macro_rules! v_attr {
}
impl ScenePipeline {
- pub fn new(device: &Device, format: TextureFormat) -> Self {
+ pub fn new(device: &Device, format: TextureFormat) -> (Self, BindGroupLayout) {
let module = device.create_shader_module(include_wgsl!("shader.wgsl"));
- let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
- entries: &[],
+ let depth = device.create_texture(&TextureDescriptor {
label: None,
+ size: Extent3d {
+ height: 256,
+ width: 256,
+ depth_or_array_layers: 1,
+ },
+ mip_level_count: 1,
+ sample_count: 1,
+ dimension: TextureDimension::D2,
+ format: TextureFormat::Depth32Float,
+ usage: TextureUsages::RENDER_ATTACHMENT,
+ view_formats: &[],
});
- let bind_group = device.create_bind_group(&BindGroupDescriptor {
+ let depth = depth.create_view(&TextureViewDescriptor::default());
+
+ let bind_group_layout = 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,
- layout: &bind_group_layout,
- entries: &[],
});
let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
label: None,
@@ -79,23 +110,45 @@ impl ScenePipeline {
polygon_mode: PolygonMode::Fill,
..Default::default()
},
- depth_stencil: Default::default(),
+ depth_stencil: Some(DepthStencilState {
+ depth_compare: CompareFunction::Greater,
+ depth_write_enabled: true,
+ format: TextureFormat::Depth32Float,
+ bias: DepthBiasState::default(),
+ stencil: StencilState::default(),
+ }),
multisample: MultisampleState::default(),
multiview: None,
cache: None,
});
- Self {
- bind_group,
- pipeline,
- }
+ (Self { pipeline, depth }, bind_group_layout)
+ }
+
+ pub fn resize(&mut self, device: &Device, width: u32, height: u32) {
+ self.depth = device
+ .create_texture(&TextureDescriptor {
+ label: None,
+ size: Extent3d {
+ height,
+ width,
+ depth_or_array_layers: 1,
+ },
+ mip_level_count: 1,
+ sample_count: 1,
+ dimension: TextureDimension::D2,
+ format: TextureFormat::Depth32Float,
+ usage: TextureUsages::RENDER_ATTACHMENT,
+ view_formats: &[],
+ })
+ .create_view(&TextureViewDescriptor::default());
}
+
pub fn draw(
&mut self,
commands: &mut CommandEncoder,
target: &TextureView,
scene: &SceneTree,
- prefabs: &HashMap<Resource, RPrefab>,
- prefabs_needed: &mut HashSet<Resource>,
+ prefabs: &mut DemandMap<Resource, Arc<RPrefab>>,
) {
let mut rpass = commands.begin_render_pass(&RenderPassDescriptor {
label: None,
@@ -112,6 +165,14 @@ impl ScenePipeline {
}),
},
})],
+ depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
+ view: &self.depth,
+ depth_ops: Some(Operations {
+ load: LoadOp::Clear(0.),
+ store: StoreOp::Store,
+ }),
+ stencil_ops: None,
+ }),
..Default::default()
});
@@ -127,14 +188,14 @@ impl ScenePipeline {
ob.rot.z,
))
* Mat4::from_translation(ob.pos.into());
- if let Some(prefab) = prefabs.get(&ob.res) {
+ if let Some(prefab) = prefabs.try_get(ob.res) {
for (affine, part) in &prefab.0 {
let part_projection = prefab_projection
* Mat4::from_mat3a(affine.matrix3)
* Mat4::from_translation(affine.translation.into());
let projection = part_projection.to_cols_array().map(|v| v.to_le_bytes());
- rpass.set_bind_group(0, &self.bind_group, &[]);
+ rpass.set_bind_group(0, &*part.texture, &[]);
rpass.set_pipeline(&self.pipeline);
rpass.set_push_constants(ShaderStages::VERTEX, 0, projection.as_flattened());
rpass.set_index_buffer(part.index.slice(..), IndexFormat::Uint16);
@@ -148,8 +209,6 @@ impl ScenePipeline {
rpass.set_vertex_buffer(7, part.texcoord[1].slice(..));
rpass.draw_indexed(0..part.index_count, 0, 0..1);
}
- } else {
- prefabs_needed.insert(ob.res);
}
}
}
diff --git a/client/src/shader.wgsl b/client/src/shader.wgsl
index d2b2d9f..b40bf57 100644
--- a/client/src/shader.wgsl
+++ b/client/src/shader.wgsl
@@ -15,6 +15,8 @@ struct VertexOut {
@location(1) uv: vec2<f32>,
}
+@group(0) @binding(0) var tex_albedo: texture_2d<f32>;
+@group(0) @binding(1) var tex_albedo_sampler: sampler;
var<push_constant> project: mat4x4<f32>;
@vertex
@@ -30,5 +32,5 @@ fn vs_main(vi: VertexIn) -> VertexOut {
}
@fragment
fn fs_main(vo: VertexOut) -> @location(0) vec4<f32> {
- return vec4<f32>(vo.normal, 1.0);
+ return textureSample(tex_albedo, tex_albedo_sampler, vo.uv);
}
diff --git a/client/src/state.rs b/client/src/state.rs
index e8188d8..a370264 100644
--- a/client/src/state.rs
+++ b/client/src/state.rs
@@ -26,6 +26,9 @@ impl<'a> State<'a> {
warn!("draw failed: {e:?}");
}
}
+ pub fn resize(&mut self, width: u32, height: u32) {
+ self.renderer.resize(width, height);
+ }
pub fn update(&mut self) -> Result<()> {
for p in self.network.packet_recv.try_iter() {
self.downloader.packet(&p)?;
diff --git a/client/src/window.rs b/client/src/window.rs
index 2430479..6ee7fa4 100644
--- a/client/src/window.rs
+++ b/client/src/window.rs
@@ -41,7 +41,7 @@ impl ApplicationHandler for WindowState {
if let Some((win, sta)) = &mut self.window {
match event {
WindowEvent::Resized(size) => {
- sta.renderer.resize(size.width, size.height);
+ sta.resize(size.width, size.height);
}
WindowEvent::RedrawRequested => {
sta.draw();