Refactor app context and render pass manager
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 9m10s

This commit is contained in:
Florian RICHER 2025-05-30 19:04:46 +02:00
parent f1ae54bc73
commit 2c169548b9
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
12 changed files with 846 additions and 466 deletions

230
src/core/app/context.rs Normal file
View file

@ -0,0 +1,230 @@
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)
}
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)
}
pub fn with_gui<T, F>(&self, f: F) -> T
where
F: FnOnce(&Gui) -> T,
{
let gui = self.gui.lock().unwrap();
f(&gui)
}
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)
}
}

View file

@ -1,12 +1,11 @@
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use super::render::vulkan_context::VulkanContext;
use super::scene::SceneContext;
use crate::core::input::InputManager;
use crate::core::scene::SceneManager;
use crate::core::scene::manager::SceneManager;
use crate::core::timer::Timer;
use crate::game::scenes::test_scene::TestScene;
use crate::game::scenes::main_scene::MainScene;
use egui_winit_vulkano::{Gui, GuiConfig};
use user_event::UserEvent;
use vulkano::format::Format;
@ -19,18 +18,23 @@ use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, EventLoopProxy};
use winit::window::WindowId;
use self::context::ApplicationContext;
pub mod context;
pub mod user_event;
pub const DEPTH_IMAGE_ID: usize = 0;
pub struct App {
vulkan_context: Arc<VulkanContext>,
vulkano_windows: Arc<VulkanoWindows>,
gui: HashMap<WindowId, Gui>,
vulkano_windows: Arc<Mutex<VulkanoWindows>>,
gui: HashMap<WindowId, Arc<Mutex<Gui>>>,
scene_manager: HashMap<WindowId, SceneManager>,
input_manager: Arc<InputManager>,
timer: Arc<Timer>,
input_manager: Arc<Mutex<InputManager>>,
timer: Arc<Mutex<Timer>>,
event_loop_proxy: EventLoopProxy<UserEvent>,
// Context d'application partagé par fenêtre - architecture unifiée
app_contexts: HashMap<WindowId, Arc<Mutex<ApplicationContext>>>,
}
impl App {
@ -41,61 +45,61 @@ impl App {
) -> Self {
Self {
vulkan_context: Arc::new(VulkanContext::new(vulkano_context)),
vulkano_windows: Arc::new(VulkanoWindows::default()),
vulkano_windows: Arc::new(Mutex::new(VulkanoWindows::default())),
gui: HashMap::new(),
input_manager: Arc::new(input_manager),
input_manager: Arc::new(Mutex::new(input_manager)),
scene_manager: HashMap::new(),
timer: Arc::new(Timer::new()),
timer: Arc::new(Mutex::new(Timer::new())),
event_loop_proxy,
app_contexts: HashMap::new(),
}
}
}
impl ApplicationHandler<UserEvent> for App {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
if let Some(vulkano_windows) = Arc::get_mut(&mut self.vulkano_windows) {
let window_id = vulkano_windows.create_window(
let mut vulkano_windows = self.vulkano_windows.lock().unwrap();
let window_id = vulkano_windows.create_window(
event_loop,
&self.vulkan_context.vulkano_context(),
&WindowDescriptor {
title: "Rust ASH Test".to_string(),
width: 800.0,
height: 600.0,
present_mode: PresentMode::Fifo,
cursor_visible: false,
cursor_locked: true,
..Default::default()
},
|_| {},
);
let renderer = vulkano_windows.get_renderer_mut(window_id).unwrap();
renderer.add_additional_image_view(
DEPTH_IMAGE_ID,
Format::D16_UNORM,
ImageUsage::DEPTH_STENCIL_ATTACHMENT,
);
let gui = {
Gui::new(
event_loop,
self.vulkan_context.vulkano_context(),
&WindowDescriptor {
title: "Rust ASH Test".to_string(),
width: 800.0,
height: 600.0,
present_mode: PresentMode::Fifo,
cursor_visible: false,
cursor_locked: true,
renderer.surface(),
renderer.graphics_queue(),
renderer.swapchain_format(),
GuiConfig {
is_overlay: true,
allow_srgb_render_target: true,
..Default::default()
},
|_| {},
);
)
};
self.gui.insert(window_id, Arc::new(Mutex::new(gui)));
let renderer = vulkano_windows.get_renderer_mut(window_id).unwrap();
renderer.add_additional_image_view(
DEPTH_IMAGE_ID,
Format::D16_UNORM,
ImageUsage::DEPTH_STENCIL_ATTACHMENT,
);
let mut scene_manager = SceneManager::new();
scene_manager.load_scene(Box::new(MainScene::default()));
let gui = {
Gui::new(
event_loop,
renderer.surface(),
renderer.graphics_queue(),
renderer.swapchain_format(),
GuiConfig {
is_overlay: true,
allow_srgb_render_target: true,
..Default::default()
},
)
};
self.gui.insert(window_id, gui);
let mut scene_manager = SceneManager::new();
scene_manager.load_scene(Box::new(TestScene::default()));
self.scene_manager.insert(window_id, scene_manager);
}
self.scene_manager.insert(window_id, scene_manager);
}
fn device_event(
@ -104,23 +108,17 @@ impl ApplicationHandler<UserEvent> for App {
_device_id: winit::event::DeviceId,
event: winit::event::DeviceEvent,
) {
match Arc::get_mut(&mut self.input_manager) {
Some(input_manager) => input_manager.process_device_event(&event),
None => log::error!("Failed to get a mutable reference to the input manager"),
}
let mut input_manager = self.input_manager.lock().unwrap();
input_manager.process_device_event(&event);
}
fn window_event(&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) {
let renderer = Arc::get_mut(&mut self.vulkano_windows)
.unwrap()
.get_renderer_mut(id)
.unwrap();
let gui = self.gui.get_mut(&id).unwrap();
if !gui.update(&event) {
match Arc::get_mut(&mut self.input_manager) {
Some(input_manager) => input_manager.process_window_event(&event),
None => log::error!("Failed to get a mutable reference to the input manager"),
{
let gui = self.gui.get_mut(&id).unwrap();
let mut gui = gui.lock().unwrap();
if !gui.update(&event) {
let mut input_manager = self.input_manager.lock().unwrap();
input_manager.process_window_event(&event);
}
}
@ -129,45 +127,64 @@ impl ApplicationHandler<UserEvent> for App {
log::debug!("The close button was pressed; stopping");
event_loop.exit();
}
WindowEvent::Resized(_) => {
renderer.resize();
}
WindowEvent::ScaleFactorChanged { .. } => {
renderer.resize();
WindowEvent::Resized(_) | WindowEvent::ScaleFactorChanged { .. } => {
let mut vulkano_windows = self.vulkano_windows.lock().unwrap();
vulkano_windows.get_renderer_mut(id).unwrap().resize();
}
WindowEvent::RedrawRequested => {
match Arc::get_mut(&mut self.input_manager) {
Some(input_manager) => input_manager.update(),
None => log::error!("Failed to get a mutable reference to the input manager"),
{
let mut input_manager = self
.input_manager
.lock()
.expect("Failed to lock input manager");
input_manager.update();
}
match Arc::get_mut(&mut self.timer) {
Some(timer) => timer.update(),
None => log::error!("Failed to get a mutable reference to the timer"),
{
let mut timer = self.timer.lock().expect("Failed to lock timer");
timer.update();
}
let mut scene_context = SceneContext::from((
&mut *renderer,
&self.vulkan_context,
&self.input_manager,
&self.timer,
id,
&self.event_loop_proxy,
));
// Créer ou mettre à jour le contexte d'application
let app_context = self
.app_contexts
.entry(id)
.or_insert_with(|| {
Arc::new(Mutex::new(ApplicationContext::new(
self.vulkan_context.clone(),
self.vulkano_windows.clone(),
self.input_manager.clone(),
self.timer.clone(),
self.gui.get(&id).unwrap().clone(),
self.event_loop_proxy.clone(),
id,
)))
})
.clone();
let scene_manager = self.scene_manager.get_mut(&id).unwrap();
scene_manager
.load_scene_if_not_loaded(&scene_context)
.unwrap();
if let Some(scene) = scene_manager.current_scene_mut() {
scene.update(&scene_context).unwrap();
// Utiliser le contexte partagé pour les scènes
{
let mut context = app_context.lock().unwrap();
let acquire_future = renderer.acquire(None, |_| {}).unwrap();
// Update the swapchain image view to the current one after acquiring the next image
scene_context.swapchain_image_view = renderer.swapchain_image_view();
scene_manager
.load_scene_if_not_loaded(&mut context)
.unwrap();
let acquire_future = scene.render(acquire_future, &scene_context, gui).unwrap();
renderer.present(acquire_future, true);
if let Some(scene) = scene_manager.current_scene_mut() {
scene.update(&mut context).unwrap();
let acquire_future = context
.with_renderer_mut(|renderer| renderer.acquire(None, |_| {}).unwrap());
let acquire_future = scene.render(acquire_future, &mut context).unwrap();
context.with_renderer_mut(|renderer| {
renderer.present(acquire_future, true);
});
} else {
log::warn!("No current scene found for update!");
}
}
}
_ => {}
@ -175,25 +192,46 @@ impl ApplicationHandler<UserEvent> for App {
}
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
let window = self.vulkano_windows.get_primary_window().unwrap();
let vulkano_windows = self.vulkano_windows.lock().unwrap();
let window = vulkano_windows.get_primary_window().unwrap();
window.request_redraw();
}
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) {
match event {
UserEvent::CursorGrabMode(window_id, grab) => {
let window = self.vulkano_windows.get_window(window_id).unwrap();
let vulkano_windows = self.vulkano_windows.lock().unwrap();
let window = vulkano_windows.get_window(window_id).unwrap();
if let Err(e) = window.set_cursor_grab(grab) {
log::error!("Failed to set cursor grab: {}", e);
}
}
UserEvent::CursorVisible(window_id, visible) => {
let window = self.vulkano_windows.get_window(window_id).unwrap();
let vulkano_windows = self.vulkano_windows.lock().unwrap();
let window = vulkano_windows.get_window(window_id).unwrap();
window.set_cursor_visible(visible);
}
UserEvent::ChangeScene(window_id, scene) => {
let scene_manager = self.scene_manager.get_mut(&window_id).unwrap();
scene_manager.load_scene(scene);
if let Some(scene_manager) = self.scene_manager.get_mut(&window_id) {
scene_manager.load_scene(scene);
}
}
UserEvent::ChangeResolution(window_id, width, height) => {
let mut vulkano_windows = self.vulkano_windows.lock().unwrap();
let window = vulkano_windows.get_window(window_id).unwrap();
let _ = window.request_inner_size(winit::dpi::LogicalSize::new(width, height));
let renderer = vulkano_windows.get_renderer_mut(window_id).unwrap();
renderer.resize();
log::info!(
"Resolution changed to {}x{} for window {:?}",
width,
height,
window_id
);
}
UserEvent::Exit(window_id) => {
log::info!("Exit requested for window {:?}", window_id);
event_loop.exit();
}
}
}

View file

@ -6,4 +6,6 @@ pub enum UserEvent {
CursorGrabMode(WindowId, CursorGrabMode),
CursorVisible(WindowId, bool),
ChangeScene(WindowId, Box<dyn Scene>),
ChangeResolution(WindowId, f32, f32),
Exit(WindowId),
}

View file

@ -1,3 +1,4 @@
pub mod primitives;
pub mod render_pass_manager;
pub mod texture;
pub mod vulkan_context;

View file

@ -0,0 +1,113 @@
use std::sync::Arc;
use vulkano::{
command_buffer::{AutoCommandBufferBuilder, RenderingAttachmentInfo, RenderingInfo},
image::view::ImageView,
pipeline::graphics::viewport::Viewport,
render_pass::{AttachmentLoadOp, AttachmentStoreOp},
};
/// Types de render passes disponibles
#[derive(Debug, Clone)]
pub enum RenderPassType {
Standard,
ShadowMap,
PostProcess,
}
/// Configuration pour un render pass
#[derive(Debug, Clone)]
pub struct RenderPassConfig {
pub pass_type: RenderPassType,
pub clear_color: Option<[f32; 4]>,
pub clear_depth: Option<f32>,
pub load_op: AttachmentLoadOp,
pub store_op: AttachmentStoreOp,
}
impl Default for RenderPassConfig {
fn default() -> Self {
Self {
pass_type: RenderPassType::Standard,
clear_color: Some([0.0, 0.0, 0.0, 1.0]),
clear_depth: Some(1.0),
load_op: AttachmentLoadOp::Clear,
store_op: AttachmentStoreOp::Store,
}
}
}
/// Gestionnaire de render passes réutilisable
pub struct RenderPassManager;
impl RenderPassManager {
/// Commence un render pass standard avec les paramètres donnés
pub fn begin_standard_rendering(
builder: &mut AutoCommandBufferBuilder<vulkano::command_buffer::PrimaryAutoCommandBuffer>,
config: &RenderPassConfig,
color_attachment: Arc<ImageView>,
depth_attachment: Option<Arc<ImageView>>,
window_size: [f32; 2],
) -> Result<(), Box<dyn std::error::Error>> {
let viewport = Viewport {
offset: [0.0, 0.0],
extent: window_size,
depth_range: 0.0..=1.0,
};
let mut rendering_info = RenderingInfo {
color_attachments: vec![Some(RenderingAttachmentInfo {
load_op: config.load_op,
store_op: config.store_op,
clear_value: config.clear_color.map(|c| c.into()),
..RenderingAttachmentInfo::image_view(color_attachment)
})],
depth_attachment: None,
..Default::default()
};
if let Some(depth_view) = depth_attachment {
rendering_info.depth_attachment = Some(RenderingAttachmentInfo {
load_op: AttachmentLoadOp::Clear,
store_op: AttachmentStoreOp::DontCare,
clear_value: config.clear_depth.map(|d| [d].into()),
..RenderingAttachmentInfo::image_view(depth_view)
});
}
builder
.begin_rendering(rendering_info)?
.set_viewport(0, [viewport].into_iter().collect())?;
Ok(())
}
/// Termine le render pass actuel
pub fn end_rendering(
builder: &mut AutoCommandBufferBuilder<vulkano::command_buffer::PrimaryAutoCommandBuffer>,
) -> Result<(), Box<dyn std::error::Error>> {
builder.end_rendering()?;
Ok(())
}
/// Crée une configuration pour un render pass shadow map
pub fn shadow_map_config() -> RenderPassConfig {
RenderPassConfig {
pass_type: RenderPassType::ShadowMap,
clear_color: None,
clear_depth: Some(1.0),
load_op: AttachmentLoadOp::Clear,
store_op: AttachmentStoreOp::Store,
}
}
/// Crée une configuration pour un render pass de post-processing
pub fn post_process_config() -> RenderPassConfig {
RenderPassConfig {
pass_type: RenderPassType::PostProcess,
clear_color: Some([0.0, 0.0, 0.0, 1.0]),
clear_depth: None,
load_op: AttachmentLoadOp::Load,
store_op: AttachmentStoreOp::Store,
}
}
}

View file

@ -1,101 +0,0 @@
use std::sync::Arc;
use vulkano::{
command_buffer::allocator::StandardCommandBufferAllocator,
descriptor_set::allocator::StandardDescriptorSetAllocator,
device::{Device, Queue},
image::view::ImageView,
instance::Instance,
memory::allocator::StandardMemoryAllocator,
};
use vulkano_util::renderer::VulkanoWindowRenderer;
use winit::{
event_loop::EventLoopProxy,
window::{Window, WindowId},
};
use crate::core::{
app::{DEPTH_IMAGE_ID, user_event::UserEvent},
input::InputManager,
render::vulkan_context::VulkanContext,
timer::Timer,
};
pub struct SceneContext<'a> {
pub instance: Arc<Instance>,
pub device: Arc<Device>,
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 window_size: [f32; 2],
pub aspect_ratio: f32,
pub swapchain_image_view: Arc<ImageView>,
pub depth_stencil_image_view: Arc<ImageView>,
pub input_manager: Arc<InputManager>,
pub timer: Arc<Timer>,
pub event_loop_proxy: &'a EventLoopProxy<UserEvent>,
pub window_id: WindowId,
}
impl<'a>
From<(
&mut VulkanoWindowRenderer,
&Arc<VulkanContext>,
&Arc<InputManager>,
&Arc<Timer>,
WindowId,
&'a EventLoopProxy<UserEvent>,
)> for SceneContext<'a>
{
fn from(
(renderer, vulkan_context, input_manager, timer, window_id, event_loop_proxy): (
&mut VulkanoWindowRenderer,
&Arc<VulkanContext>,
&Arc<InputManager>,
&Arc<Timer>,
WindowId,
&'a EventLoopProxy<UserEvent>,
),
) -> Self {
let (command_buffer_allocator, descriptor_set_allocator) = {
(
vulkan_context.command_buffer_allocator().clone(),
vulkan_context.descriptor_set_allocator().clone(),
)
};
let (instance, device, graphics_queue, compute_queue, transfer_queue, memory_allocator) = {
let vulkan_context = vulkan_context.vulkano_context();
(
vulkan_context.instance().clone(),
vulkan_context.device().clone(),
vulkan_context.graphics_queue().clone(),
vulkan_context.compute_queue().clone(),
vulkan_context.transfer_queue().cloned(),
vulkan_context.memory_allocator().clone(),
)
};
Self {
instance,
device,
graphics_queue,
compute_queue,
transfer_queue,
memory_allocator,
command_buffer_allocator,
descriptor_set_allocator,
window_size: renderer.window_size(),
aspect_ratio: renderer.aspect_ratio(),
swapchain_image_view: renderer.swapchain_image_view(),
depth_stencil_image_view: renderer.get_additional_image_view(DEPTH_IMAGE_ID),
input_manager: input_manager.clone(),
timer: timer.clone(),
event_loop_proxy,
window_id,
}
}
}

View file

@ -1,52 +1,84 @@
use std::error::Error;
use super::{Scene, SceneContext};
use crate::core::app::context::ApplicationContext;
use super::Scene;
pub struct SceneManager {
current_scene: Option<Box<dyn Scene>>,
scenes: Vec<Box<dyn Scene>>,
current_scene_index: Option<usize>,
}
impl SceneManager {
pub fn new() -> Self {
Self {
current_scene: None,
scenes: Vec::new(),
current_scene_index: None,
}
}
pub fn load_scene(&mut self, scene: Box<dyn Scene>) {
self.scenes.push(scene);
self.current_scene_index = Some(self.scenes.len() - 1);
}
pub fn replace_current_scene(&mut self, scene: Box<dyn Scene>) {
if let Some(index) = self.current_scene_index {
if index < self.scenes.len() {
self.scenes[index].unload();
self.scenes[index] = scene;
}
} else {
self.load_scene(scene);
}
}
pub fn current_scene(&self) -> Option<&Box<dyn Scene>> {
if let Some(index) = self.current_scene_index {
self.scenes.get(index)
} else {
None
}
}
pub fn current_scene_mut(&mut self) -> Option<&mut Box<dyn Scene>> {
log::debug!(
"current_scene_mut called - index: {:?}, scenes len: {}",
self.current_scene_index,
self.scenes.len()
);
if let Some(index) = self.current_scene_index {
log::debug!("Getting scene at index {}", index);
self.scenes.get_mut(index)
} else {
log::debug!("No current scene index set");
None
}
}
pub fn load_scene_if_not_loaded(
&mut self,
scene_context: &SceneContext,
app_context: &mut ApplicationContext,
) -> Result<(), Box<dyn Error>> {
if let Some(current_scene) = self.current_scene.as_mut() {
if !current_scene.loaded() {
current_scene.load(scene_context)?;
log::debug!("SceneManager::load_scene_if_not_loaded called");
log::debug!(
"Current scene index: {:?}, scenes count: {}",
self.current_scene_index,
self.scenes.len()
);
if let Some(scene) = self.current_scene_mut() {
log::debug!("Scene found, checking if loaded: {}", scene.loaded());
if !scene.loaded() {
log::debug!("Scene not loaded, loading...");
scene.load(app_context)?;
log::debug!("Scene loaded successfully");
} else {
log::debug!("Scene already loaded");
}
} else {
log::warn!("No scene found in SceneManager!");
}
Ok(())
}
pub fn load_scene(&mut self, scene: Box<dyn Scene>) {
if let Some(current_scene) = self.current_scene.as_mut() {
current_scene.unload();
}
self.current_scene = Some(scene);
}
pub fn current_scene(&self) -> Option<&Box<dyn Scene>> {
if let Some(current_scene) = self.current_scene.as_ref() {
if current_scene.loaded() {
return Some(current_scene);
}
}
None
}
pub fn current_scene_mut(&mut self) -> Option<&mut Box<dyn Scene>> {
if let Some(current_scene) = self.current_scene.as_mut() {
if current_scene.loaded() {
return Some(current_scene);
}
}
None
}
}

View file

@ -1,23 +1,19 @@
use std::{error::Error, sync::Arc};
use std::error::Error;
use egui_winit_vulkano::Gui;
use vulkano::{image::view::ImageView, sync::GpuFuture};
use vulkano::sync::GpuFuture;
mod context;
pub use context::SceneContext;
use crate::core::app::context::ApplicationContext;
mod manager;
pub use manager::SceneManager;
pub mod manager;
pub trait Scene {
fn loaded(&self) -> bool;
fn load(&mut self, scene_context: &SceneContext) -> Result<(), Box<dyn Error>>;
fn update(&mut self, scene_context: &SceneContext) -> Result<(), Box<dyn Error>>;
fn load(&mut self, app_context: &mut ApplicationContext) -> Result<(), Box<dyn Error>>;
fn update(&mut self, app_context: &mut ApplicationContext) -> Result<(), Box<dyn Error>>;
fn render(
&mut self,
acquire_future: Box<dyn GpuFuture>,
scene_context: &SceneContext,
gui: &mut Gui,
app_context: &mut ApplicationContext,
) -> Result<Box<dyn GpuFuture>, Box<dyn Error>>;
fn unload(&mut self);
}