diff --git a/src/core/app.rs b/src/core/app/mod.rs similarity index 75% rename from src/core/app.rs rename to src/core/app/mod.rs index 93ef9bc..ab548f8 100644 --- a/src/core/app.rs +++ b/src/core/app/mod.rs @@ -6,8 +6,9 @@ use super::scene::SceneContext; use crate::core::input::InputManager; use crate::core::scene::SceneManager; use crate::core::timer::Timer; -use crate::game::main_scene::MainScene; +use crate::game::scenes::test_scene::TestScene; use egui_winit_vulkano::{Gui, GuiConfig}; +use user_event::UserEvent; use vulkano::format::Format; use vulkano::image::ImageUsage; use vulkano::swapchain::PresentMode; @@ -15,34 +16,42 @@ use vulkano_util::context::VulkanoContext; use vulkano_util::window::{VulkanoWindows, WindowDescriptor}; use winit::application::ApplicationHandler; use winit::event::WindowEvent; -use winit::event_loop::ActiveEventLoop; +use winit::event_loop::{ActiveEventLoop, EventLoopProxy}; use winit::window::WindowId; +pub mod user_event; + pub const DEPTH_IMAGE_ID: usize = 0; pub struct App { vulkan_context: Arc, vulkano_windows: Arc, gui: HashMap, - scene_manager: SceneManager, + scene_manager: HashMap, input_manager: Arc, timer: Arc, + event_loop_proxy: EventLoopProxy, } impl App { - pub fn new(vulkano_context: VulkanoContext, input_manager: InputManager) -> Self { + pub fn new( + vulkano_context: VulkanoContext, + input_manager: InputManager, + event_loop_proxy: EventLoopProxy, + ) -> Self { Self { vulkan_context: Arc::new(VulkanContext::new(vulkano_context)), vulkano_windows: Arc::new(VulkanoWindows::default()), gui: HashMap::new(), input_manager: Arc::new(input_manager), - scene_manager: SceneManager::new(), + scene_manager: HashMap::new(), timer: Arc::new(Timer::new()), + event_loop_proxy, } } } -impl ApplicationHandler for App { +impl ApplicationHandler 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( @@ -81,10 +90,12 @@ impl ApplicationHandler for App { ) }; self.gui.insert(window_id, gui); - } - self.scene_manager - .load_scene(Box::new(MainScene::default())); + let mut scene_manager = SceneManager::new(); + scene_manager.load_scene(Box::new(TestScene::default())); + + self.scene_manager.insert(window_id, scene_manager); + } } fn device_event( @@ -139,13 +150,16 @@ impl ApplicationHandler for App { &self.vulkan_context, &self.input_manager, &self.timer, + id, + &self.event_loop_proxy, )); - self.scene_manager + let scene_manager = self.scene_manager.get_mut(&id).unwrap(); + scene_manager .load_scene_if_not_loaded(&scene_context) .unwrap(); - if let Some(scene) = self.scene_manager.current_scene_mut() { + if let Some(scene) = scene_manager.current_scene_mut() { scene.update(&scene_context).unwrap(); let acquire_future = renderer.acquire(None, |_| {}).unwrap(); @@ -164,4 +178,23 @@ impl ApplicationHandler for App { let window = self.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(); + 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(); + 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); + } + } + } } diff --git a/src/core/app/user_event.rs b/src/core/app/user_event.rs new file mode 100644 index 0000000..316ac4c --- /dev/null +++ b/src/core/app/user_event.rs @@ -0,0 +1,9 @@ +use winit::window::{CursorGrabMode, WindowId}; + +use crate::core::scene::Scene; + +pub enum UserEvent { + CursorGrabMode(WindowId, CursorGrabMode), + CursorVisible(WindowId, bool), + ChangeScene(WindowId, Box), +} diff --git a/src/core/scene/context.rs b/src/core/scene/context.rs index 545f39c..4e0dab3 100644 --- a/src/core/scene/context.rs +++ b/src/core/scene/context.rs @@ -9,12 +9,19 @@ use vulkano::{ memory::allocator::StandardMemoryAllocator, }; use vulkano_util::renderer::VulkanoWindowRenderer; - -use crate::core::{ - app::DEPTH_IMAGE_ID, input::InputManager, render::vulkan_context::VulkanContext, timer::Timer, +use winit::{ + event_loop::EventLoopProxy, + window::{Window, WindowId}, }; -pub struct SceneContext { +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, pub device: Arc, pub graphics_queue: Arc, @@ -29,22 +36,28 @@ pub struct SceneContext { pub depth_stencil_image_view: Arc, pub input_manager: Arc, pub timer: Arc, + pub event_loop_proxy: &'a EventLoopProxy, + pub window_id: WindowId, } -impl +impl<'a> From<( &mut VulkanoWindowRenderer, &Arc, &Arc, &Arc, - )> for SceneContext + WindowId, + &'a EventLoopProxy, + )> for SceneContext<'a> { fn from( - (renderer, vulkan_context, input_manager, timer): ( + (renderer, vulkan_context, input_manager, timer, window_id, event_loop_proxy): ( &mut VulkanoWindowRenderer, &Arc, &Arc, &Arc, + WindowId, + &'a EventLoopProxy, ), ) -> Self { let (command_buffer_allocator, descriptor_set_allocator) = { @@ -81,6 +94,8 @@ impl 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, } } } diff --git a/src/game/mod.rs b/src/game/mod.rs index e8924d3..065e8e4 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -1,2 +1,2 @@ pub mod assets; -pub mod main_scene; +pub mod scenes; diff --git a/src/game/main_scene.rs b/src/game/scenes/main_scene.rs similarity index 85% rename from src/game/main_scene.rs rename to src/game/scenes/main_scene.rs index 22c851b..bad12d0 100644 --- a/src/game/main_scene.rs +++ b/src/game/scenes/main_scene.rs @@ -1,31 +1,26 @@ use std::{error::Error, sync::Arc}; +use crate::core::app::user_event::UserEvent; use crate::core::render::primitives::camera::Camera3D; use crate::core::render::primitives::transform::Transform; use crate::core::render::texture::Texture; use crate::core::scene::Scene; use crate::core::scene::SceneContext; +use crate::game::assets::square::Square; use egui_winit_vulkano::{Gui, egui}; use glam::EulerRot; use glam::Quat; use glam::Vec3; -use vulkano::format::Format; -use vulkano::image::Image; -use vulkano::image::ImageCreateInfo; -use vulkano::image::ImageUsage; -use vulkano::memory::allocator::AllocationCreateInfo; use vulkano::{ command_buffer::{ AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract, RenderingAttachmentInfo, RenderingInfo, }, - image::view::ImageView, pipeline::graphics::viewport::Viewport, render_pass::{AttachmentLoadOp, AttachmentStoreOp}, sync::GpuFuture, }; - -use super::assets::square::Square; +use winit::window::CursorGrabMode; pub struct MainSceneState { square: Square, @@ -119,6 +114,38 @@ impl Scene for MainScene { scene_context.aspect_ratio, ); + if scene_context + .input_manager + .get_virtual_input_state("mouse_left") + > 0.0 + { + let _ = scene_context + .event_loop_proxy + .send_event(UserEvent::CursorVisible(scene_context.window_id, false)); + let _ = scene_context + .event_loop_proxy + .send_event(UserEvent::CursorGrabMode( + scene_context.window_id, + CursorGrabMode::Locked, + )); + } + + if scene_context + .input_manager + .get_virtual_input_state("mouse_right") + > 0.0 + { + let _ = scene_context + .event_loop_proxy + .send_event(UserEvent::CursorVisible(scene_context.window_id, true)); + let _ = scene_context + .event_loop_proxy + .send_event(UserEvent::CursorGrabMode( + scene_context.window_id, + CursorGrabMode::None, + )); + } + Ok(()) } diff --git a/src/game/scenes/mod.rs b/src/game/scenes/mod.rs new file mode 100644 index 0000000..e5c4945 --- /dev/null +++ b/src/game/scenes/mod.rs @@ -0,0 +1,2 @@ +pub mod main_scene; +pub mod test_scene; diff --git a/src/game/scenes/test_scene.rs b/src/game/scenes/test_scene.rs new file mode 100644 index 0000000..9ed8707 --- /dev/null +++ b/src/game/scenes/test_scene.rs @@ -0,0 +1,111 @@ +use std::error::Error; + +use crate::core::app::user_event::UserEvent; +use crate::core::scene::Scene; +use crate::core::scene::SceneContext; +use egui_winit_vulkano::{Gui, egui}; +use vulkano::command_buffer::AutoCommandBufferBuilder; +use vulkano::command_buffer::CommandBufferUsage; +use vulkano::command_buffer::RenderingAttachmentInfo; +use vulkano::command_buffer::RenderingInfo; +use vulkano::pipeline::graphics::viewport::Viewport; +use vulkano::render_pass::AttachmentLoadOp; +use vulkano::render_pass::AttachmentStoreOp; +use vulkano::sync::GpuFuture; + +use super::main_scene::MainScene; + +pub struct MainSceneState {} + +#[derive(Default)] +pub struct TestScene { + state: Option, +} + +impl Scene for TestScene { + fn loaded(&self) -> bool { + self.state.is_some() + } + + fn load(&mut self, scene_context: &SceneContext) -> Result<(), Box> { + self.state = Some(MainSceneState {}); + + Ok(()) + } + + fn update(&mut self, scene_context: &SceneContext) -> Result<(), Box> { + Ok(()) + } + + fn render( + &mut self, + acquire_future: Box, + scene_context: &SceneContext, + gui: &mut Gui, + ) -> Result, Box> { + let mut builder = AutoCommandBufferBuilder::primary( + scene_context.command_buffer_allocator.clone(), + scene_context.graphics_queue.queue_family_index(), + CommandBufferUsage::OneTimeSubmit, + )?; + + { + let viewport = Viewport { + offset: [0.0, 0.0], + extent: scene_context.window_size, + depth_range: 0.0..=1.0, + }; + + builder + .begin_rendering(RenderingInfo { + color_attachments: vec![Some(RenderingAttachmentInfo { + load_op: AttachmentLoadOp::Clear, + store_op: AttachmentStoreOp::Store, + clear_value: Some([0.0, 0.0, 0.0, 1.0].into()), + ..RenderingAttachmentInfo::image_view( + scene_context.swapchain_image_view.clone(), + ) + })], + depth_attachment: Some(RenderingAttachmentInfo { + load_op: AttachmentLoadOp::Clear, + store_op: AttachmentStoreOp::DontCare, + clear_value: Some([1.0].into()), + ..RenderingAttachmentInfo::image_view( + scene_context.depth_stencil_image_view.clone(), + ) + }), + ..Default::default() + })? + .set_viewport(0, [viewport].into_iter().collect())?; + } + + builder.end_rendering()?; + + let command_buffer = builder.build()?; + + let render_future = + acquire_future.then_execute(scene_context.graphics_queue.clone(), command_buffer)?; + + gui.immediate_ui(|gui| { + let ctx = gui.context(); + + egui::CentralPanel::default().show(&ctx, |ui| { + if ui.button("Start Game").clicked() { + let _ = scene_context + .event_loop_proxy + .send_event(UserEvent::ChangeScene( + scene_context.window_id, + Box::new(MainScene::default()), + )); + } + }); + }); + + let render_future = + gui.draw_on_image(render_future, scene_context.swapchain_image_view.clone()); + + Ok(render_future) + } + + fn unload(&mut self) {} +} diff --git a/src/main.rs b/src/main.rs index ffe5f72..1ea49c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -77,10 +77,11 @@ fn main() { let vulkano_context = VulkanoContext::new(vulkano_config); - let event_loop = EventLoop::new().unwrap(); + let event_loop = EventLoop::with_user_event().build().unwrap(); event_loop.set_control_flow(ControlFlow::Poll); + let proxy = event_loop.create_proxy(); - let mut app = core::app::App::new(vulkano_context, input_manager); + let mut app = core::app::App::new(vulkano_context, input_manager, proxy); match event_loop.run_app(&mut app) { Ok(_) => {}