use std::error::Error; use super::settings_scene::SettingsScene; use crate::core::app::DEPTH_IMAGE_ID; use crate::core::app::context::ApplicationContext; 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::render_pass_manager::{RenderPassConfig, RenderPassManager}; use crate::core::render::texture::Texture; use crate::core::scene::Scene; use crate::game::assets::square::Square; use egui_winit_vulkano::egui; use glam::EulerRot; use glam::Quat; use glam::Vec3; use vulkano::{ command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract}, sync::GpuFuture, }; use winit::window::CursorGrabMode; pub struct MainSceneState { square: Square, instances: Vec, camera: Camera3D, texture: Texture, speed: f32, } #[derive(Default)] pub struct MainScene { state: Option, } impl Scene for MainScene { fn loaded(&self) -> bool { self.state.is_some() } fn load( &mut self, app_context: &mut ApplicationContext, ) -> Result<(), Box> { let depth_image_view = app_context.with_renderer_mut(|renderer| { renderer.get_additional_image_view(DEPTH_IMAGE_ID).clone() }); let swapchain_image_view = app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone()); let square = Square::new( &app_context.device, &app_context.memory_allocator, swapchain_image_view.format(), depth_image_view.format(), )?; let num_instances = 100; let instance_size = 10.0; let instance_spacing = 10.0; let num_instances_per_row = (num_instances as f32 / instance_spacing).ceil() as u32; let instances: Vec = (0..num_instances) .map(|i| Transform { position: Vec3::new( (i % num_instances_per_row) as f32 * (instance_spacing + instance_size), 0.0, (i / num_instances_per_row) as f32 * (instance_spacing + instance_size), ), rotation: Quat::from_euler( EulerRot::XYZ, 0.0, rand::random_range(0.0..=360.0), 0.0, ), scale: Vec3::new(instance_size, instance_size, instance_size), }) .collect(); let texture = { let mut uploads = AutoCommandBufferBuilder::primary( app_context.command_buffer_allocator.clone(), app_context.graphics_queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, )?; let texture = Texture::from_file( &app_context.device, &app_context.memory_allocator, &mut uploads, "res/textures/wooden-crate.jpg", )?; let _ = uploads .build()? .execute(app_context.graphics_queue.clone())?; texture }; let camera = app_context.with_renderer(|renderer| { Camera3D::new( renderer.aspect_ratio(), std::f32::consts::FRAC_PI_2, 0.01, 1000.0, ) }); self.state = Some(MainSceneState { square, instances, camera, texture, speed: 50.0, }); Ok(()) } fn update(&mut self, app_context: &mut ApplicationContext) -> Result<(), Box> { let state = self.state.as_mut().unwrap(); app_context.with_input_manager(|input_manager| { app_context.with_timer(|timer| { state.camera.update( input_manager, timer, state.speed, 10.0, app_context.get_aspect_ratio(), ); }); }); if app_context .with_input_manager(|input_manager| input_manager.get_virtual_input_state("mouse_left")) > 0.0 { let _ = app_context .event_loop_proxy .send_event(UserEvent::CursorVisible(app_context.window_id, false)); let _ = app_context .event_loop_proxy .send_event(UserEvent::CursorGrabMode( app_context.window_id, CursorGrabMode::Locked, )); } if app_context.with_input_manager(|input_manager| { input_manager.get_virtual_input_state("mouse_right") }) > 0.0 { let _ = app_context .event_loop_proxy .send_event(UserEvent::CursorVisible(app_context.window_id, true)); let _ = app_context .event_loop_proxy .send_event(UserEvent::CursorGrabMode( app_context.window_id, CursorGrabMode::None, )); } Ok(()) } fn render( &mut self, before_future: Box, app_context: &mut ApplicationContext, ) -> Result, Box> { let state = self.state.as_ref().ok_or("State not loaded")?; let mut builder = AutoCommandBufferBuilder::primary( app_context.command_buffer_allocator.clone(), app_context.graphics_queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, )?; { let swapchain_image_view = app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone()); let depth_image_view = app_context.with_renderer_mut(|renderer| { renderer.get_additional_image_view(DEPTH_IMAGE_ID).clone() }); let config = RenderPassConfig::default(); RenderPassManager::begin_standard_rendering( &mut builder, &config, swapchain_image_view, Some(depth_image_view), app_context.get_window_size(), )?; } // Create camera uniform using the actual camera let camera_uniform = state.camera.create_buffer(&app_context.memory_allocator)?; let transform_uniform = Transform::create_buffer(&app_context.memory_allocator, &state.instances)?; state .square .render( &mut builder, &app_context.descriptor_set_allocator, &camera_uniform, &transform_uniform, &state.texture, ) .unwrap(); RenderPassManager::end_rendering(&mut builder)?; let command_buffer = builder.build()?; let render_future = before_future.then_execute(app_context.graphics_queue.clone(), command_buffer)?; let swapchain_image_view = app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone()); let input_manager_status = app_context.with_input_manager(|input_manager| format!("{:#?}", input_manager)); let event_loop_proxy = app_context.event_loop_proxy.clone(); let delta_time = app_context.get_delta_time(); let window_id = app_context.window_id; let window_size = app_context.get_window_size(); let render_future = app_context.with_gui_mut(|gui| { gui.immediate_ui(|gui| { let ctx = gui.context(); egui::TopBottomPanel::top("top_panel").show(&ctx, |ui| { ui.horizontal(|ui| { ui.heading("Vulkan Test - Moteur 3D"); ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { if ui.button("Paramètres").clicked() { let _ = event_loop_proxy.send_event(UserEvent::ChangeScene( window_id, Box::new(SettingsScene::default()), )); } if ui.button("Quitter").clicked() { let _ = event_loop_proxy.send_event(UserEvent::Exit(window_id)); } }); }); }); egui::SidePanel::left("side_panel").show(&ctx, |ui| { ui.heading("Informations"); ui.separator(); ui.label(format!("Résolution: {:?}", window_size)); ui.label(format!("Delta Time: {:.2}ms", delta_time * 1000.0)); ui.separator(); ui.label("Position caméra:"); let position = state.camera.get_position(); ui.label(format!(" X: {:.2}", position[0])); ui.label(format!(" Y: {:.2}", position[1])); ui.label(format!(" Z: {:.2}", position[2])); ui.separator(); ui.label("Rotation caméra:"); let rotation = state.camera.get_rotation(); ui.label(format!(" Yaw: {:.2}°", rotation.y.to_degrees())); ui.label(format!(" Pitch: {:.2}°", rotation.x.to_degrees())); ui.separator(); ui.label(input_manager_status); }); }); gui.draw_on_image(render_future, swapchain_image_view.clone()) }); Ok(render_future) } fn unload(&mut self) { self.state = None; } }