diff options
-rw-r--r-- | Cargo.lock | 191 | ||||
-rw-r--r-- | client/Cargo.toml | 10 | ||||
-rw-r--r-- | client/src/main.rs | 3 | ||||
-rw-r--r-- | client/src/renderer.rs | 184 | ||||
-rw-r--r-- | client/src/skin_manager.rs | 146 | ||||
-rw-r--r-- | client/src/window.rs | 20 |
6 files changed, 363 insertions, 191 deletions
@@ -243,15 +243,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" [[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] name = "binrw" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -493,6 +484,7 @@ dependencies = [ "anyhow", "arrayvec 0.5.2", "env_logger 0.11.6", + "image", "libtw2-demo", "libtw2-event-loop", "libtw2-gamenet-common", @@ -501,9 +493,12 @@ dependencies = [ "libtw2-snapshot", "log 0.4.22", "pollster", - "twgame 0.9.3", + "twgame", "twgpu", - "twsnap 0.7.3", + "twmap", + "twsnap", + "twstorage", + "vek", "warn", "wgpu", "winit 0.30.8", @@ -636,9 +631,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "cursor-icon" @@ -1478,9 +1473,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", "simd-adler32", @@ -2065,25 +2060,6 @@ dependencies = [ ] [[package]] -name = "pre-rfc3243-libtw2-demo" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8d82220e0a2df5677108f03f4f83e713cb6cd60eb53ed8e5aaf57d219735f86" -dependencies = [ - "arrayvec 0.5.2", - "binrw", - "buffer", - "pre-rfc3243-libtw2-common", - "pre-rfc3243-libtw2-gamenet-common", - "pre-rfc3243-libtw2-huffman", - "pre-rfc3243-libtw2-packer", - "pre-rfc3243-libtw2-snapshot", - "thiserror", - "uuid 0.8.2", - "warn", -] - -[[package]] name = "pre-rfc3243-libtw2-gamenet-common" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2146,18 +2122,6 @@ dependencies = [ ] [[package]] -name = "pre-rfc3243-libtw2-huffman" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f42f3d7315871c61fb7bf12c317e3b2eb92870e46bc919eacabfc14420884fa3" -dependencies = [ - "arrayvec 0.5.2", - "buffer", - "itertools", - "pre-rfc3243-libtw2-common", -] - -[[package]] name = "pre-rfc3243-libtw2-packer" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2171,20 +2135,6 @@ dependencies = [ ] [[package]] -name = "pre-rfc3243-libtw2-snapshot" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b40486fb774b475e16d86a0ee769695b81b151759aa2fb66ad456d1a4216421" -dependencies = [ - "buffer", - "pre-rfc3243-libtw2-common", - "pre-rfc3243-libtw2-gamenet-snap", - "pre-rfc3243-libtw2-packer", - "vec_map", - "warn", -] - -[[package]] name = "presser" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2492,9 +2442,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" [[package]] name = "serde" @@ -2518,9 +2468,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.135" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", "memchr 2.7.4", @@ -2689,24 +2639,12 @@ dependencies = [ [[package]] name = "teehistorian" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39af9384bec948ccd9d6d5777bbef8532ff5cabda9972b0cccff84a06139885" -dependencies = [ - "arrayvec 0.7.6", - "nom", - "serde", - "uuid 1.11.1", -] - -[[package]] -name = "teehistorian" version = "0.12.0" dependencies = [ "arrayvec 0.7.6", "nom", "serde", - "uuid 1.11.1", + "uuid 1.12.1", ] [[package]] @@ -2834,28 +2772,6 @@ checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" [[package]] name = "twgame" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59204ffd091cdd6d2cff73851671842c291b9795d9cfb34ff5a802ec1d5a658" -dependencies = [ - "arrayvec 0.7.6", - "bitflags 2.7.0", - "hashbrown 0.14.5", - "indexmap", - "ndarray", - "rand", - "rand_pcg", - "serde", - "serde_json", - "twgame-core 0.3.0", - "twmap", - "twsnap 0.2.1", - "uuid 1.11.1", - "vek", -] - -[[package]] -name = "twgame" version = "0.9.3" dependencies = [ "arrayvec 0.7.6", @@ -2869,35 +2785,14 @@ dependencies = [ "serde", "serde_json", "slotmap", - "twgame-core 0.7.1", + "twgame-core", "twmap", - "uuid 1.11.1", + "uuid 1.12.1", "vek", ] [[package]] name = "twgame-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd991e8dbf1c167325bfd7635801a81a01894adfc6cf64f3c4961af2747ff33a" -dependencies = [ - "bincode", - "bitflags 2.7.0", - "buffer", - "hex", - "pre-rfc3243-libtw2-gamenet-ddnet", - "pre-rfc3243-libtw2-gamenet-teeworlds-0-7", - "pre-rfc3243-libtw2-packer", - "serde", - "teehistorian 0.11.1", - "twsnap 0.2.1", - "uuid 1.11.1", - "vek", - "warn", -] - -[[package]] -name = "twgame-core" version = "0.7.1" dependencies = [ "hex", @@ -2906,8 +2801,8 @@ dependencies = [ "pre-rfc3243-libtw2-gamenet-teeworlds-0-7", "pre-rfc3243-libtw2-packer", "serde", - "teehistorian 0.12.0", - "twsnap 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "teehistorian", + "twsnap", "vek", "warn", ] @@ -2922,9 +2817,9 @@ dependencies = [ "ndarray", "rand_core", "rand_pcg", - "twgame 0.4.0", + "twgame", "twmap", - "twsnap 0.2.1", + "twsnap", "vek", "wgpu", "winit 0.29.15", @@ -2933,8 +2828,6 @@ dependencies = [ [[package]] name = "twmap" version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420a7fab81c01d4a646f24834492d9ee8f606e491fa81610a192b5be0bbd7688" dependencies = [ "az", "bitflags 2.7.0", @@ -2957,25 +2850,6 @@ dependencies = [ [[package]] name = "twsnap" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07891b4605bd1ca12054f2c601b24c3160e486b0a0e24447a432aac210cf54a2" -dependencies = [ - "arrayvec 0.7.6", - "bitflags 2.7.0", - "fixed", - "hashbrown 0.14.5", - "num_enum", - "pre-rfc3243-libtw2-common", - "pre-rfc3243-libtw2-demo", - "pre-rfc3243-libtw2-gamenet-ddnet", - "serde", - "vek", - "warn", -] - -[[package]] -name = "twsnap" version = "0.7.3" dependencies = [ "arrayvec 0.7.6", @@ -2992,25 +2866,6 @@ dependencies = [ ] [[package]] -name = "twsnap" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ffb55636a9828dda08ad4f9d7e2a232007dc339b949d412709941646665cbbb" -dependencies = [ - "arrayvec 0.7.6", - "bitflags 2.7.0", - "fixed", - "hashbrown 0.14.5", - "num_enum", - "pre-rfc3243-libtw2-common", - "pre-rfc3243-libtw2-demo", - "pre-rfc3243-libtw2-gamenet-ddnet", - "serde", - "vek", - "warn", -] - -[[package]] name = "twstorage" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3072,9 +2927,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b913a3b5fe84142e269d63cc62b64319ccaf89b748fc31fe025177f767a756c4" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" dependencies = [ "getrandom", "serde", diff --git a/client/Cargo.toml b/client/Cargo.toml index 8101167..93c1431 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -13,16 +13,26 @@ xdg = "2.5.2" wgpu = "23.0.1" pollster = "0.4.0" winit = "0.30.8" +vek = { version = "0.16.1", default-features = false, features = [ + "bytemuck", + "az", + "rgba", + "std", + "uv", +] } +image = "0.24.9" twgame = { path = "../../twgame/twgame" } twgpu = { path = "../../twgpu/twgpu" } twsnap = { path = "../../twsnap" } +twmap = { path = "../../twmap/twmap" } libtw2-gamenet-ddnet = { path = "../../libtw2/gamenet/ddnet" } libtw2-gamenet-common = { path = "../../libtw2/gamenet/common" } libtw2-event-loop = { path = "../../libtw2/event-loop" } libtw2-packer = { path = "../../libtw2/packer" } libtw2-demo = { path = "../../libtw2/demo" } libtw2-snapshot = { path = "../../libtw2/snapshot" } +twstorage = "0.1.1" # pre-rfc3243-libtw2-gamenet-ddnet = "*" # pre-rfc3243-libtw2-gamenet-common = "*" diff --git a/client/src/main.rs b/client/src/main.rs index 8373db9..5a52620 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -6,11 +6,12 @@ use winit::event_loop::EventLoop; pub mod client; pub mod renderer; pub mod window; +pub mod skin_manager; fn main() -> Result<()> { env_logger::init_from_env("LOG"); - Client::new()?; + // Client::new()?; let evloop = EventLoop::new()?; evloop.run_app(&mut WindowState::new())?; diff --git a/client/src/renderer.rs b/client/src/renderer.rs index c8f7f0b..b213307 100644 --- a/client/src/renderer.rs +++ b/client/src/renderer.rs @@ -1,22 +1,44 @@ -use std::sync::Arc; - +use crate::skin_manager::{SkinManager, init_sprite_textures}; use anyhow::{Result, anyhow}; +use log::warn; use pollster::FutureExt; +use std::{sync::Arc, time::Instant}; use twgpu::{ - Camera, GpuCamera, - map::{GpuMapData, GpuMapStatic}, - shared::Rng, - sprites::{ParticleData, SpriteTextures, SpritesData, SpritesStatic}, + Camera, GpuCamera, TwRenderPass, + blit::Blit, + buffer::GpuBuffer, + map::{GpuMapData, GpuMapRender, GpuMapStatic}, + sprites::{ParticleData, ParticleGroup, SpriteTextures, SpritesData, SpritesStatic}, textures::Samplers, }; +use twmap::TwMap; +use vek::Vec2; use wgpu::{ - Backends, DeviceDescriptor, Features, Instance, InstanceDescriptor, Limits, MemoryHints, - PowerPreference, RequestAdapterOptions, TextureFormat, + Backends, Color, CommandEncoderDescriptor, Device, DeviceDescriptor, Features, Instance, + InstanceDescriptor, Limits, LoadOp, MaintainBase, MemoryHints, Operations, PowerPreference, + Queue, RenderPassColorAttachment, RenderPassDescriptor, RequestAdapterOptions, StoreOp, + Surface, SurfaceConfiguration, TextureFormat, TextureViewDescriptor, }; -use winit::window::Window; +use winit::{dpi::PhysicalSize, window::Window}; pub struct Renderer<'a> { + device: Arc<Device>, + queue: Arc<Queue>, window: &'a Window, + surface: Surface<'a>, + surface_configuration: SurfaceConfiguration, + twmap: TwMap, + map_render: GpuMapRender, + map_data: GpuMapData, + camera: Camera, + sprites_data: SpritesData, + particle_data: ParticleData, + skin_manager: SkinManager, + sprites_static: SpritesStatic, + sprite_textures: SpriteTextures, + gpu_camera: Arc<GpuBuffer<Camera>>, + start: Instant, + need_reconfigure: bool, } impl<'a> Renderer<'a> { @@ -51,9 +73,17 @@ impl<'a> Renderer<'a> { None, ) .block_on()?; + let device = Arc::new(device); + let queue = Arc::new(queue); + + let mut twmap = TwMap::parse(include_bytes!( + "/home/muffin/etc/ddnet-maps/types/novice/maps/Mint.map" + ))?; + + twmap.load()?; let samplers = Arc::new(Samplers::new(&device)); - let mut camera = Camera::new(1.); + let camera = Camera::new(1.); let gpu_camera = Arc::new(GpuCamera::upload(&camera, &device)); let map_static = GpuMapStatic::new(texture_format, &device); @@ -62,15 +92,133 @@ impl<'a> Renderer<'a> { map_static.prepare_render(&twmap, &map_data, &gpu_camera, &samplers, &device); let sprites_static = SpritesStatic::new(texture_format, &device); - let mut sprites_data = SpritesData::new(&device); - let mut particle_data = ParticleData::new(demo.current_time(), &device); - let mut textures = SpriteTextures::new(&device, &queue, &gpu_camera, &samplers); - let mut rng = Rng::new(0); - init_sprite_textures(&mut textures, twmap.version, &device, &queue)?; + let sprites_data = SpritesData::new(&device); + let particle_data = ParticleData::new(0.0, &device); + let mut sprite_textures = SpriteTextures::new(&device, &queue, &gpu_camera, &samplers); + init_sprite_textures(&mut sprite_textures, twmap.version, &device, &queue)?; let blit = Arc::new(Blit::new(&device)); - let mut skin_manager = SkinManager::new(blit, &mut textures, device.clone(), queue.clone()); + let skin_manager = + SkinManager::new(blit, &mut sprite_textures, device.clone(), queue.clone()); + + let surface_configuration = surface + .get_default_config(&adapter, 256, 256) + .ok_or(anyhow!("no surface config"))?; + + surface.configure(&device, &surface_configuration); + + Ok(Self { + start: Instant::now(), + map_data, + sprites_static, + window, + device, + queue, + twmap, + surface, + surface_configuration, + map_render, + camera, + gpu_camera, + particle_data, + skin_manager, + sprites_data, + sprite_textures, + need_reconfigure: false, + }) + } + pub fn resize(&mut self, size: PhysicalSize<u32>) { + self.surface_configuration.width = size.width; + self.surface_configuration.height = size.height; + self.camera + .switch_aspect_ratio(size.width as f32 / size.height as f32); + self.reconfigure(); + } + pub fn reconfigure(&mut self) { + self.surface + .configure(&self.device, &self.surface_configuration); + self.need_reconfigure = false; + } + + pub fn redraw(&mut self) -> Result<()> { + if self.need_reconfigure { + self.reconfigure(); + } + let target = self.surface.get_current_texture()?; + if target.suboptimal { + warn!("suboptimal surface, need reconfigure"); + self.need_reconfigure = true; + } + + let time = self.start.elapsed().as_micros() as i64; + let size = Vec2::new( + self.surface_configuration.width, + self.surface_configuration.height, + ); + self.map_data + .update(&self.twmap, &self.camera, size, time, time, &self.queue); + self.gpu_camera.update(&self.camera, &self.queue); + + let target_view = target + .texture + .create_view(&TextureViewDescriptor::default()); + + let mut commands = self + .device + .create_command_encoder(&CommandEncoderDescriptor { label: None }); + + { + let rpass = commands.begin_render_pass(&RenderPassDescriptor { + label: None, + color_attachments: &[Some(RenderPassColorAttachment { + view: &target_view, + resolve_target: None, + ops: Operations { + load: LoadOp::Clear(Color::BLACK), + store: StoreOp::Store, + }, + })], + ..Default::default() + }); + let mut rpass = TwRenderPass::new(rpass, size, &self.camera); + self.map_render.render_background(&mut rpass); + self.sprites_static.render_particles( + &self.particle_data, + ParticleGroup::Trails, + &self.sprite_textures, + &mut rpass.render_pass, + ); + self.sprites_static.render( + &self.sprites_data, + &self.sprite_textures, + &mut rpass.render_pass, + ); + self.map_render.render_foreground(&mut rpass); + self.sprites_static.render_particles( + &self.particle_data, + ParticleGroup::Explosions, + &self.sprite_textures, + &mut rpass.render_pass, + ); + self.sprites_static.render_particles( + &self.particle_data, + ParticleGroup::Extra, + &self.sprite_textures, + &mut rpass.render_pass, + ); + self.sprites_static.render_particles( + &self.particle_data, + ParticleGroup::General, + &self.sprite_textures, + &mut rpass.render_pass, + ); + } + + let submission = self.queue.submit(Some(commands.finish())); + self.device + .poll(MaintainBase::WaitForSubmissionIndex(submission)); + + target.present(); - Self { window } + Ok(()) } - pub fn redraw() {} } diff --git a/client/src/skin_manager.rs b/client/src/skin_manager.rs new file mode 100644 index 0000000..1f6624d --- /dev/null +++ b/client/src/skin_manager.rs @@ -0,0 +1,146 @@ +// Adapted from twgpu-tools +// AGPL-3.0-only, Copyright 2025 Patiga + +use anyhow::Result; +use image::{ImageFormat, RgbaImage}; +use std::{collections::HashSet, io::BufReader, sync::Arc}; +use twgpu::{ + blit::Blit, + sprites::{AtlasToken, SpriteTextures, TeeSprite}, +}; +use wgpu::{Device, Queue, Texture}; + +pub fn load_png(path: &str, version: twmap::Version) -> Result<RgbaImage> { + let file = twstorage::read_file(path, version.into())?; + let reader = image::io::Reader::with_format(BufReader::new(file), ImageFormat::Png); + Ok(reader.decode()?.into_rgba8()) +} + +pub fn init_sprite_textures( + textures: &mut SpriteTextures, + version: twmap::Version, + device: &Device, + queue: &Queue, +) -> Result<()> { + println!("Loading sprite textures from filesystem"); + let game = load_png("game.png", version)?; + let particles = load_png("particles.png", version)?; + let emoticons = load_png("emoticons.png", version)?; + let extras = load_png("extras.png", version)?; + textures.game_skin = textures.register_atlas_image(&game, device, queue); + textures.particles = textures.register_atlas_image(&particles, device, queue); + textures.emoticons = textures.register_atlas_image(&emoticons, device, queue); + textures.extras = textures.register_atlas_image(&extras, device, queue); + Ok(()) +} + +type SkinResult = Result<(String, Vec<Texture>), (String, String)>; + +pub struct SkinManager { + known: HashSet<String>, + handles: Vec<std::thread::JoinHandle<SkinResult>>, + blit: Arc<Blit>, + device: Arc<Device>, + queue: Arc<Queue>, +} + +fn load_skin(name: &str, blit: &Blit, device: &Device, queue: &Queue) -> Result<Vec<Texture>> { + // TODO check filename + let path = format!("skins/{name}.png"); + let path2 = format!("downloadedskins/{name}.png"); + let image = match load_png(&path, twmap::Version::DDNet06) { + Err(_) => load_png(&path2, twmap::Version::DDNet06)?, + Ok(img) => img, + }; + + let texture = blit.upload_mipmapped_atlas::<TeeSprite>(&image, device, queue); + Ok(texture) +} + +impl SkinManager { + pub fn new( + blit: Arc<Blit>, + textures: &mut SpriteTextures, + device: Arc<Device>, + queue: Arc<Queue>, + ) -> Self { + let mut manager = Self { + known: HashSet::new(), + handles: Vec::new(), + blit, + device, + queue, + }; + if let Some(default) = manager.load_skin("default", textures) { + textures.default_skin = default; + } + if let Some(ninja) = manager.load_skin("x_ninja", textures) { + textures.ninja_skin = ninja; + } + manager + } + + pub fn load_skin( + &mut self, + name: &str, + textures: &mut SpriteTextures, + ) -> Option<AtlasToken<TeeSprite>> { + let texture = match load_skin(name, &self.blit, &self.device, &self.queue) { + Ok(texture) => texture, + Err(err) => { + println!("Error loading skin '{name}': {err}"); + return None; + } + }; + self.known.insert(name.to_string()); + let token = textures.register_skin_texture(texture, name.to_string(), &self.device); + Some(token) + } + + pub fn queue_load_skin(&mut self, name: String) { + let device = self.device.clone(); + let queue = self.queue.clone(); + let blit = self.blit.clone(); + let handle = std::thread::spawn(move || match load_skin(&name, &blit, &device, &queue) { + Err(err) => Err((name, err.to_string())), + Ok(texture) => Ok((name, texture)), + }); + self.handles.push(handle); + } + + pub fn wait_for_queued(&mut self, textures: &mut SpriteTextures) { + while let Some(handle) = self.handles.pop() { + match handle.join().unwrap() { + Ok((name, texture)) => { + textures.register_skin_texture(texture, name, &self.device); + } + Err((name, err)) => println!("Error with skin '{name}': {err}"), + } + } + } + + pub fn poll_queued(&mut self, textures: &mut SpriteTextures) { + while !self.handles.is_empty() { + if self.handles[0].is_finished() { + match self.handles.remove(0).join().unwrap() { + Ok((name, texture)) => { + textures.register_skin_texture(texture, name, &self.device); + } + Err((name, err)) => println!("Error with skin '{name}': {err}"), + } + } else { + return; + } + } + } + + pub fn queue_snap_skins(&mut self, snap: &twsnap::Snap) { + for player in snap.players.values() { + if !self.known.contains(player.skin.as_str()) { + println!("New skin: '{}'", player.skin); + self.known.insert(player.skin.to_string()); + self.queue_load_skin(player.skin.to_string()); + } + } + } +} diff --git a/client/src/window.rs b/client/src/window.rs index d0296e7..0bcac6a 100644 --- a/client/src/window.rs +++ b/client/src/window.rs @@ -1,4 +1,5 @@ use crate::renderer::Renderer; +use log::warn; use winit::{ application::ApplicationHandler, event::WindowEvent, @@ -20,19 +21,30 @@ impl ApplicationHandler for WindowState { let window = event_loop .create_window(WindowAttributes::default().with_maximized(true)) .unwrap(); - let renderer = Renderer::new(unsafe { std::mem::transmute(&window) }); + let renderer = Renderer::new(unsafe { std::mem::transmute(&window) }).unwrap(); self.window = Some((window, renderer)) } fn window_event( &mut self, event_loop: &ActiveEventLoop, - window_id: WindowId, + _window_id: WindowId, event: WindowEvent, ) { - if let Some((win, ren)) = &self.window { + if let Some((win, ren)) = &mut self.window { match event { - WindowEvent::RedrawRequested => {} + WindowEvent::CloseRequested => { + event_loop.exit(); + } + WindowEvent::Resized(size) => { + ren.resize(size); + } + WindowEvent::RedrawRequested => { + if let Err(e) = ren.redraw() { + warn!("{e:?}") + } + win.request_redraw(); + } _ => (), } } |