vulkano_test/src/game/scenes/main_scene.rs
Florian RICHER 1568223b9d
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 9m20s
some cleanup from clippy
2025-05-30 22:21:34 +02:00

288 lines
9.7 KiB
Rust

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<Transform>,
camera: Camera3D,
texture: Texture,
speed: f32,
}
#[derive(Default)]
pub struct MainScene {
state: Option<MainSceneState>,
}
impl Scene for MainScene {
fn loaded(&self) -> bool {
self.state.is_some()
}
fn load(
&mut self,
app_context: &mut ApplicationContext,
) -> Result<(), Box<dyn std::error::Error>> {
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<Transform> = (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<dyn Error>> {
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<dyn GpuFuture>,
app_context: &mut ApplicationContext,
) -> Result<Box<dyn GpuFuture>, Box<dyn Error>> {
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;
}
}