vulkano_test/src/core/app/context.rs
Florian RICHER bc42892d39
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 9m39s
cleanup
2025-05-30 21:54:58 +02:00

233 lines
7.7 KiB
Rust

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<Mutex<>> pour la mutabilité partagée
#[derive(Clone)]
pub struct ApplicationContext {
// Données Vulkan (immutables)
pub vulkan_context: Arc<VulkanContext>,
pub device: Arc<Device>,
pub instance: Arc<Instance>,
pub graphics_queue: Arc<Queue>,
pub compute_queue: Arc<Queue>,
pub transfer_queue: Option<Arc<Queue>>,
pub memory_allocator: Arc<StandardMemoryAllocator>,
pub command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
pub descriptor_set_allocator: Arc<StandardDescriptorSetAllocator>,
pub event_loop_proxy: EventLoopProxy<UserEvent>,
pub window_id: WindowId,
// Données mutables partagées avec Arc<Mutex<>>
pub vulkano_windows: Arc<Mutex<VulkanoWindows>>,
pub input_manager: Arc<Mutex<InputManager>>,
pub timer: Arc<Mutex<Timer>>,
pub gui: Arc<Mutex<Gui>>,
}
impl ApplicationContext {
pub fn new(
vulkan_context: Arc<VulkanContext>,
vulkano_windows: Arc<Mutex<VulkanoWindows>>,
input_manager: Arc<Mutex<InputManager>>,
timer: Arc<Mutex<Timer>>,
gui: Arc<Mutex<Gui>>,
event_loop_proxy: EventLoopProxy<UserEvent>,
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<T, F>(&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<T, F>(&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<T, F>(&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<T, F>(&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<T, F>(&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<T, F>(&self, f: F) -> T
where
F: FnOnce(&Timer) -> T,
{
let timer = self.timer.lock().unwrap();
f(&timer)
}
}