use std::sync::{Arc, Mutex}; 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, window::{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 ApplicationContext { // 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: Arc>, pub input_manager: Arc>, pub timer: Arc>, pub gui: Arc>, } impl ApplicationContext { pub fn new( vulkan_context: Arc, vulkano_windows: Arc>, input_manager: Arc>, timer: Arc>, gui: Arc>, 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, } } /// Récupère les résolutions disponibles du moniteur (méthode utilitaire statique) fn get_monitor_resolutions(window: &Window) -> Vec<(u32, u32)> { // Première tentative : moniteur actuel if let Some(monitor) = window.current_monitor() { let resolutions = Self::extract_resolutions_from_monitor(&monitor); if !resolutions.is_empty() { log::debug!( "Résolutions trouvées via moniteur actuel: {:?}", resolutions ); return resolutions; } } // Deuxième tentative : tous les moniteurs disponibles log::debug!("Tentative de récupération via tous les moniteurs disponibles..."); let mut all_resolutions = Vec::new(); for monitor in window.available_monitors() { let resolutions = Self::extract_resolutions_from_monitor(&monitor); all_resolutions.extend(resolutions); } if !all_resolutions.is_empty() { // Supprime les doublons et trie all_resolutions.sort_unstable(); all_resolutions.dedup(); all_resolutions.sort_by(|a, b| (b.0 * b.1).cmp(&(a.0 * a.1))); log::debug!( "Résolutions trouvées via tous les moniteurs: {:?}", all_resolutions ); return all_resolutions; } // Aucune résolution détectée - retourne un vecteur vide log::warn!("Aucune résolution détectée pour cette fenêtre"); Vec::new() } /// Extrait les résolutions d'un moniteur donné fn extract_resolutions_from_monitor( monitor: &winit::monitor::MonitorHandle, ) -> Vec<(u32, u32)> { let video_modes: Vec<_> = monitor.video_modes().collect(); if video_modes.is_empty() { log::debug!( "Aucun mode vidéo trouvé pour le moniteur {:?}", monitor.name() ); return Vec::new(); } let resolutions: Vec<(u32, u32)> = video_modes .into_iter() .map(|mode| { let size = mode.size(); (size.width, size.height) }) .collect(); log::debug!( "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| Self::get_monitor_resolutions(&renderer.window())) } /// 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 .lock() .expect("Failed to lock vulkano_windows"); 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 .lock() .expect("Failed to lock vulkano_windows"); 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.lock().unwrap(); 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.lock().unwrap(); 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.lock().unwrap(); 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.lock().unwrap(); f(&timer) } }