use std::cell::RefCell; use std::sync::{Arc}; use std::time::Duration; use winit::event::{ElementState, WindowEvent}; use winit::keyboard::KeyCode; use crate::tacmap::TacticalMap; use crate::{GameState, ui}; use crate::wgpuctx::{RenderPassBuilder, SceneCtx, WgpuCtx}; use crate::eguictx::EguiCtx; pub struct GameWindow { window: Arc, wgpuctx: WgpuCtx, eguictx: EguiCtx, tactical_map: TacticalMap, ui_state: ui::State } impl GameWindow { pub fn new( instance: &wgpu::Instance, event_loop: &winit::event_loop::ActiveEventLoop) -> Result { let window_attrs = winit::window::Window::default_attributes() .with_title("Systemic 4X") .with_inner_size(winit::dpi::LogicalSize::new(640, 480)); let window = Arc::new(event_loop.create_window(window_attrs).unwrap()); let wgpuctx = pollster::block_on(WgpuCtx::new(instance, window.clone())); let eguictx = EguiCtx::new(&window, &wgpuctx); let tacmap = TacticalMap::new(&wgpuctx); let ui_state = ui::State{ camera_target: Some(0), topbar_sate: ui::topbar::TopBarState { current_system : Some(0), ..Default::default() }, ..Default::default() }; Ok(Self { window: window, wgpuctx: wgpuctx, eguictx: eguictx, tactical_map: tacmap, ui_state: ui_state }) } pub fn update( &mut self, game_state: &RefCell, dt: Duration) { let mut game_state = game_state.borrow_mut(); if self.ui_state.topbar_sate.do_auto_tick { game_state.timeman.auto_tick = self.ui_state.topbar_sate.auto_tick; }else{ game_state.timeman.auto_tick = None; } let current_system = match self.ui_state.topbar_sate.current_system { Some(id) => &game_state.solar_systems()[id], None => { return; } }; self.tactical_map.update( current_system, &mut self.ui_state, game_state.timeman().seconds(), dt); } pub fn keyboard_input( &mut self, key_code: KeyCode, key_state: ElementState) { self.tactical_map.keyboard_input(key_code, key_state); } pub fn render( &mut self, game_state: &RefCell) -> Result<(), wgpu::SurfaceError> { if !self.wgpuctx.is_ready() { return Ok(()); } let view = self.wgpuctx.prepare_surface(&wgpu::TextureViewDescriptor::default())?; let mut scene = SceneCtx::from_view_default(&self.wgpuctx, &view, Some("Systemic window scene")); self.eguictx.prepare(&self.window); let screen_size = egui::vec2( self.wgpuctx.surface_config().width as f32, self.wgpuctx.surface_config().height as f32); self.ui_state.render(game_state, &self.eguictx); if self.ui_state.topbar_sate.current_system.is_some() { let game_state = game_state.borrow(); let fleets_manager = game_state.fleets(); let current_system = &game_state.solar_systems()[self.ui_state.topbar_sate.current_system.unwrap()]; self.tactical_map.draw( &self.wgpuctx, fleets_manager, current_system, game_state.timeman())?; self.tactical_map.prepare(&mut scene); let mut pass = RenderPassBuilder::new(Some("Systemic window render pass"), &view) .clear_color(wgpu::Color { r: 0.0, g: 0.0, b: 0.1, a: 1.0 }) .build_from_scene(&mut scene); //Draw the tactical map canvas. self.tactical_map.paint(&mut pass); egui::CentralPanel::default() .frame(egui::Frame::new()) .show(self.eguictx.context(), |ui| { self.tactical_map.paint_labels( current_system, game_state.timeman().seconds(), screen_size, ui ); }); } self.eguictx.present( &self.window, &self.wgpuctx, scene.encoder_mut(), &view); scene.submit(&self.wgpuctx); self.wgpuctx.present_surface(); self.window.request_redraw(); Ok(()) } pub fn on_event( &mut self, event: &WindowEvent) { if self.eguictx.window_event(&self.window, event).consumed { return; } } pub fn resize( &mut self, width: u32, height: u32 ) { if width > 0 && height > 0 { self.wgpuctx.resize(width, height); self.tactical_map.resize(width, height); self.window.request_redraw(); } } pub fn size( &self) -> winit::dpi::PhysicalSize { self.window.inner_size() } }