/* 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 . */ use crate::state::State; use glam::Vec3; use log::{info, warn}; use std::net::TcpStream; use winit::{ application::ApplicationHandler, event::{DeviceEvent, ElementState, WindowEvent}, event_loop::ActiveEventLoop, keyboard::{KeyCode, PhysicalKey}, window::{CursorGrabMode, Window, WindowAttributes, WindowId}, }; pub struct WindowState { init: Option, window: Option<(Window, State<'static>)>, lock: bool, } impl WindowState { pub fn new(init: TcpStream) -> Self { Self { window: None, init: Some(init), lock: false, } } } impl ApplicationHandler for WindowState { fn resumed(&mut self, event_loop: &ActiveEventLoop) { info!("app resumed"); let win = event_loop .create_window(WindowAttributes::default().with_maximized(true)) .unwrap(); let sta = State::new(self.init.take().unwrap(), unsafe { std::mem::transmute::<&Window, &'static Window>(&win) }) .unwrap(); self.window = Some((win, sta)) } fn window_event( &mut self, event_loop: &ActiveEventLoop, _window_id: WindowId, event: WindowEvent, ) { if let Some((win, sta)) = &mut self.window { match event { WindowEvent::Resized(size) => { sta.resize(size.width, size.height); } WindowEvent::RedrawRequested => { sta.draw(); win.request_redraw(); } WindowEvent::KeyboardInput { event, .. } => { if event.repeat { return; } if event.state == ElementState::Pressed { match event.physical_key { PhysicalKey::Code(KeyCode::Escape) => { win.set_cursor_grab(if self.lock { CursorGrabMode::None } else { CursorGrabMode::Locked }) .unwrap(); self.lock = !self.lock; } _ => (), } } sta.delta.move_dir += match event.physical_key { PhysicalKey::Code(KeyCode::KeyW) => Vec3::X, PhysicalKey::Code(KeyCode::KeyS) => Vec3::NEG_X, PhysicalKey::Code(KeyCode::KeyA) => Vec3::NEG_Z, PhysicalKey::Code(KeyCode::KeyD) => Vec3::Z, _ => Vec3::ZERO, } * match event.state { ElementState::Pressed => 1., ElementState::Released => -1., }; } WindowEvent::CloseRequested => { event_loop.exit(); } _ => (), } } } fn device_event( &mut self, _event_loop: &ActiveEventLoop, _device_id: winit::event::DeviceId, event: winit::event::DeviceEvent, ) { if let Some((_win, sta)) = &mut self.window { match event { DeviceEvent::MouseMotion { delta } => { sta.delta.mouse_acc.x += delta.0 as f32; sta.delta.mouse_acc.y += delta.1 as f32; } _ => (), } } } fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { if let Some((_win, sta)) = &mut self.window { if let Err(e) = sta.update() { warn!("update failed: {e:#}") } } } } impl Drop for WindowState { fn drop(&mut self) { if let Some((win, sta)) = self.window.take() { drop(sta); drop(win) } } }