use std::{ cell::RefCell, rc::Rc, sync::{Arc, RwLock}, }; use egui_winit_vulkano::Gui; use vulkano::{ command_buffer::allocator::StandardCommandBufferAllocator, descriptor_set::allocator::StandardDescriptorSetAllocator, device::{Device, Queue}, instance::Instance, memory::allocator::StandardMemoryAllocator, }; use vulkano_util::{renderer::VulkanoWindowRenderer, window::VulkanoWindows}; use winit::{event_loop::EventLoopProxy, monitor::MonitorHandle, window::WindowId}; use crate::core::{input::InputManager, render::vulkan_context::VulkanContext, timer::Timer}; use super::user_event::UserEvent; /// Contexte d'application unifié avec Arc> pour la mutabilité partagée #[derive(Clone)] pub struct WindowContext { // Données Vulkan (immutables) pub vulkan_context: Arc, pub device: Arc, pub instance: Arc, pub graphics_queue: Arc, pub compute_queue: Arc, pub transfer_queue: Option>, pub memory_allocator: Arc, pub command_buffer_allocator: Arc, pub descriptor_set_allocator: Arc, pub event_loop_proxy: EventLoopProxy, pub window_id: WindowId, // Données mutables partagées avec Arc> pub vulkano_windows: Rc>, pub input_manager: Arc>, pub timer: Arc>, pub gui: Rc>, } impl WindowContext { pub fn new( vulkan_context: Arc, vulkano_windows: Rc>, input_manager: Arc>, timer: Arc>, gui: Rc>, event_loop_proxy: EventLoopProxy, window_id: WindowId, ) -> Self { let vulkano_context_inner = vulkan_context.vulkano_context(); Self { // Données Vulkan vulkan_context: vulkan_context.clone(), device: vulkano_context_inner.device().clone(), instance: vulkano_context_inner.instance().clone(), graphics_queue: vulkano_context_inner.graphics_queue().clone(), compute_queue: vulkano_context_inner.compute_queue().clone(), transfer_queue: vulkano_context_inner.transfer_queue().cloned(), memory_allocator: vulkano_context_inner.memory_allocator().clone(), command_buffer_allocator: vulkan_context.command_buffer_allocator().clone(), descriptor_set_allocator: vulkan_context.descriptor_set_allocator().clone(), event_loop_proxy, window_id, // Données mutables partagées vulkano_windows, input_manager, timer, gui, } } /// Extrait les résolutions d'un moniteur donné fn extract_resolutions_from_monitor(monitor: MonitorHandle) -> Vec<(u32, u32)> { let video_modes: Vec<_> = monitor.video_modes().collect(); let resolutions: Vec<(u32, u32)> = video_modes .into_iter() .map(|mode| { let size = mode.size(); (size.width, size.height) }) .collect(); tracing::trace!( "Modes vidéo trouvés pour {:?}: {:?}", monitor.name(), resolutions ); resolutions } /// Récupère les résolutions disponibles pub fn get_available_resolutions(&self) -> Vec<(u32, u32)> { self.with_renderer(|renderer| { renderer .window() .current_monitor() .map(Self::extract_resolutions_from_monitor) .unwrap_or_default() }) } /// Récupère le delta time actuel depuis le timer pub fn get_delta_time(&self) -> f32 { self.with_timer(|timer| timer.delta_time()) } /// Récupère la taille de la fenêtre depuis le renderer pub fn get_window_size(&self) -> [f32; 2] { self.with_renderer(|renderer| renderer.window_size()) } /// Récupère l'aspect ratio depuis le renderer pub fn get_aspect_ratio(&self) -> f32 { self.with_renderer(|renderer| renderer.aspect_ratio()) } pub fn with_renderer(&self, f: F) -> T where F: FnOnce(&VulkanoWindowRenderer) -> T, { let vulkano_windows = self.vulkano_windows.borrow_mut(); let renderer = vulkano_windows .get_renderer(self.window_id) .expect("Failed to get renderer"); f(renderer) } /// Méthode utilitaire pour accéder au renderer de manière thread-safe pub fn with_renderer_mut(&mut self, f: F) -> T where F: FnOnce(&mut VulkanoWindowRenderer) -> T, { let mut vulkano_windows = self.vulkano_windows.borrow_mut(); let renderer = vulkano_windows .get_renderer_mut(self.window_id) .expect("Failed to get renderer"); f(renderer) } /// Méthode utilitaire pour accéder au gui de manière thread-safe pub fn with_gui(&self, f: F) -> T where F: FnOnce(&Gui) -> T, { let gui = self.gui.borrow(); f(&gui) } /// Méthode utilitaire pour accéder au gui de manière thread-safe pub fn with_gui_mut(&mut self, f: F) -> T where F: FnOnce(&mut Gui) -> T, { let mut gui = self.gui.borrow_mut(); f(&mut gui) } /// Méthode utilitaire pour accéder à l'input manager de manière thread-safe pub fn with_input_manager(&self, f: F) -> T where F: FnOnce(&InputManager) -> T, { let input_manager = self .input_manager .read() .expect("Failed to lock input_manager"); f(&input_manager) } /// Méthode utilitaire pour accéder au timer de manière thread-safe pub fn with_timer(&self, f: F) -> T where F: FnOnce(&Timer) -> T, { let timer = self.timer.read().expect("Failed to lock timer"); f(&timer) } }