winit: Use user event
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 8m47s

This commit is contained in:
Florian RICHER 2025-05-29 21:38:07 +02:00
parent 6a6b1821a4
commit f1ae54bc73
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
8 changed files with 227 additions and 29 deletions

View file

@ -6,8 +6,9 @@ use super::scene::SceneContext;
use crate::core::input::InputManager; use crate::core::input::InputManager;
use crate::core::scene::SceneManager; use crate::core::scene::SceneManager;
use crate::core::timer::Timer; 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 egui_winit_vulkano::{Gui, GuiConfig};
use user_event::UserEvent;
use vulkano::format::Format; use vulkano::format::Format;
use vulkano::image::ImageUsage; use vulkano::image::ImageUsage;
use vulkano::swapchain::PresentMode; use vulkano::swapchain::PresentMode;
@ -15,34 +16,42 @@ use vulkano_util::context::VulkanoContext;
use vulkano_util::window::{VulkanoWindows, WindowDescriptor}; use vulkano_util::window::{VulkanoWindows, WindowDescriptor};
use winit::application::ApplicationHandler; use winit::application::ApplicationHandler;
use winit::event::WindowEvent; use winit::event::WindowEvent;
use winit::event_loop::ActiveEventLoop; use winit::event_loop::{ActiveEventLoop, EventLoopProxy};
use winit::window::WindowId; use winit::window::WindowId;
pub mod user_event;
pub const DEPTH_IMAGE_ID: usize = 0; pub const DEPTH_IMAGE_ID: usize = 0;
pub struct App { pub struct App {
vulkan_context: Arc<VulkanContext>, vulkan_context: Arc<VulkanContext>,
vulkano_windows: Arc<VulkanoWindows>, vulkano_windows: Arc<VulkanoWindows>,
gui: HashMap<WindowId, Gui>, gui: HashMap<WindowId, Gui>,
scene_manager: SceneManager, scene_manager: HashMap<WindowId, SceneManager>,
input_manager: Arc<InputManager>, input_manager: Arc<InputManager>,
timer: Arc<Timer>, timer: Arc<Timer>,
event_loop_proxy: EventLoopProxy<UserEvent>,
} }
impl App { 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<UserEvent>,
) -> Self {
Self { Self {
vulkan_context: Arc::new(VulkanContext::new(vulkano_context)), vulkan_context: Arc::new(VulkanContext::new(vulkano_context)),
vulkano_windows: Arc::new(VulkanoWindows::default()), vulkano_windows: Arc::new(VulkanoWindows::default()),
gui: HashMap::new(), gui: HashMap::new(),
input_manager: Arc::new(input_manager), input_manager: Arc::new(input_manager),
scene_manager: SceneManager::new(), scene_manager: HashMap::new(),
timer: Arc::new(Timer::new()), timer: Arc::new(Timer::new()),
event_loop_proxy,
} }
} }
} }
impl ApplicationHandler for App { impl ApplicationHandler<UserEvent> for App {
fn resumed(&mut self, event_loop: &ActiveEventLoop) { fn resumed(&mut self, event_loop: &ActiveEventLoop) {
if let Some(vulkano_windows) = Arc::get_mut(&mut self.vulkano_windows) { if let Some(vulkano_windows) = Arc::get_mut(&mut self.vulkano_windows) {
let window_id = vulkano_windows.create_window( let window_id = vulkano_windows.create_window(
@ -81,10 +90,12 @@ impl ApplicationHandler for App {
) )
}; };
self.gui.insert(window_id, gui); self.gui.insert(window_id, gui);
}
self.scene_manager let mut scene_manager = SceneManager::new();
.load_scene(Box::new(MainScene::default())); scene_manager.load_scene(Box::new(TestScene::default()));
self.scene_manager.insert(window_id, scene_manager);
}
} }
fn device_event( fn device_event(
@ -139,13 +150,16 @@ impl ApplicationHandler for App {
&self.vulkan_context, &self.vulkan_context,
&self.input_manager, &self.input_manager,
&self.timer, &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) .load_scene_if_not_loaded(&scene_context)
.unwrap(); .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(); scene.update(&scene_context).unwrap();
let acquire_future = renderer.acquire(None, |_| {}).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(); let window = self.vulkano_windows.get_primary_window().unwrap();
window.request_redraw(); 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);
}
}
}
} }

View file

@ -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<dyn Scene>),
}

View file

@ -9,12 +9,19 @@ use vulkano::{
memory::allocator::StandardMemoryAllocator, memory::allocator::StandardMemoryAllocator,
}; };
use vulkano_util::renderer::VulkanoWindowRenderer; use vulkano_util::renderer::VulkanoWindowRenderer;
use winit::{
use crate::core::{ event_loop::EventLoopProxy,
app::DEPTH_IMAGE_ID, input::InputManager, render::vulkan_context::VulkanContext, timer::Timer, 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<Instance>, pub instance: Arc<Instance>,
pub device: Arc<Device>, pub device: Arc<Device>,
pub graphics_queue: Arc<Queue>, pub graphics_queue: Arc<Queue>,
@ -29,22 +36,28 @@ pub struct SceneContext {
pub depth_stencil_image_view: Arc<ImageView>, pub depth_stencil_image_view: Arc<ImageView>,
pub input_manager: Arc<InputManager>, pub input_manager: Arc<InputManager>,
pub timer: Arc<Timer>, pub timer: Arc<Timer>,
pub event_loop_proxy: &'a EventLoopProxy<UserEvent>,
pub window_id: WindowId,
} }
impl impl<'a>
From<( From<(
&mut VulkanoWindowRenderer, &mut VulkanoWindowRenderer,
&Arc<VulkanContext>, &Arc<VulkanContext>,
&Arc<InputManager>, &Arc<InputManager>,
&Arc<Timer>, &Arc<Timer>,
)> for SceneContext WindowId,
&'a EventLoopProxy<UserEvent>,
)> for SceneContext<'a>
{ {
fn from( fn from(
(renderer, vulkan_context, input_manager, timer): ( (renderer, vulkan_context, input_manager, timer, window_id, event_loop_proxy): (
&mut VulkanoWindowRenderer, &mut VulkanoWindowRenderer,
&Arc<VulkanContext>, &Arc<VulkanContext>,
&Arc<InputManager>, &Arc<InputManager>,
&Arc<Timer>, &Arc<Timer>,
WindowId,
&'a EventLoopProxy<UserEvent>,
), ),
) -> Self { ) -> Self {
let (command_buffer_allocator, descriptor_set_allocator) = { let (command_buffer_allocator, descriptor_set_allocator) = {
@ -81,6 +94,8 @@ impl
depth_stencil_image_view: renderer.get_additional_image_view(DEPTH_IMAGE_ID), depth_stencil_image_view: renderer.get_additional_image_view(DEPTH_IMAGE_ID),
input_manager: input_manager.clone(), input_manager: input_manager.clone(),
timer: timer.clone(), timer: timer.clone(),
event_loop_proxy,
window_id,
} }
} }
} }

View file

@ -1,2 +1,2 @@
pub mod assets; pub mod assets;
pub mod main_scene; pub mod scenes;

View file

@ -1,31 +1,26 @@
use std::{error::Error, sync::Arc}; 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::camera::Camera3D;
use crate::core::render::primitives::transform::Transform; use crate::core::render::primitives::transform::Transform;
use crate::core::render::texture::Texture; use crate::core::render::texture::Texture;
use crate::core::scene::Scene; use crate::core::scene::Scene;
use crate::core::scene::SceneContext; use crate::core::scene::SceneContext;
use crate::game::assets::square::Square;
use egui_winit_vulkano::{Gui, egui}; use egui_winit_vulkano::{Gui, egui};
use glam::EulerRot; use glam::EulerRot;
use glam::Quat; use glam::Quat;
use glam::Vec3; 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::{ use vulkano::{
command_buffer::{ command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract, AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract,
RenderingAttachmentInfo, RenderingInfo, RenderingAttachmentInfo, RenderingInfo,
}, },
image::view::ImageView,
pipeline::graphics::viewport::Viewport, pipeline::graphics::viewport::Viewport,
render_pass::{AttachmentLoadOp, AttachmentStoreOp}, render_pass::{AttachmentLoadOp, AttachmentStoreOp},
sync::GpuFuture, sync::GpuFuture,
}; };
use winit::window::CursorGrabMode;
use super::assets::square::Square;
pub struct MainSceneState { pub struct MainSceneState {
square: Square, square: Square,
@ -119,6 +114,38 @@ impl Scene for MainScene {
scene_context.aspect_ratio, 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(()) Ok(())
} }

2
src/game/scenes/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod main_scene;
pub mod test_scene;

View file

@ -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<MainSceneState>,
}
impl Scene for TestScene {
fn loaded(&self) -> bool {
self.state.is_some()
}
fn load(&mut self, scene_context: &SceneContext) -> Result<(), Box<dyn Error>> {
self.state = Some(MainSceneState {});
Ok(())
}
fn update(&mut self, scene_context: &SceneContext) -> Result<(), Box<dyn Error>> {
Ok(())
}
fn render(
&mut self,
acquire_future: Box<dyn GpuFuture>,
scene_context: &SceneContext,
gui: &mut Gui,
) -> Result<Box<dyn GpuFuture>, Box<dyn Error>> {
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) {}
}

View file

@ -77,10 +77,11 @@ fn main() {
let vulkano_context = VulkanoContext::new(vulkano_config); 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); 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) { match event_loop.run_app(&mut app) {
Ok(_) => {} Ok(_) => {}