o3 refactor

This commit is contained in:
reo 2025-07-22 21:12:05 +03:00
parent 341d531db3
commit 049f522bb1
19 changed files with 508 additions and 214 deletions

View file

@ -13,3 +13,4 @@ raidillon_ui = { path = "../raidillon_ui" }
raidillon_core = { path = "../raidillon_core" }
hecs = "0.10.5"
raidillon_input = { path = "../raidillon_input" }
glium = { version = "0.35.0", features = ["glutin_backend", "simple_window_builder"] }

View file

@ -0,0 +1,90 @@
use hecs::{World, Entity};
use glium::Surface;
use raidillon_render::{RenderSystem, window::DisplayHandle, Camera};
use raidillon_input::{InputSystem, CameraSystem, Action};
use raidillon_core::{Time, AssetManager, EventBus, SystemRegistry};
use glam::{Vec3, Quat};
pub struct Engine {
world: World,
assets: AssetManager,
events: EventBus<Action>,
systems: SystemRegistry<Action>,
render_system: RenderSystem,
input_system: InputSystem,
time: Time,
camera_entity: Entity,
}
impl Engine {
pub fn new(display: &DisplayHandle) -> anyhow::Result<Self> {
let mut world = World::new();
let mut assets = AssetManager::new();
let events = EventBus::new();
let mut systems = SystemRegistry::new();
let render_system = RenderSystem::new(display.clone())?;
let input_system = InputSystem::new();
let time = Time::new();
let tree_model = assets.load_model("resources/models/tree.gltf", render_system.display())?;
let ground_model = assets.load_model("resources/models/plane.gltf", render_system.display())?;
world.spawn((raidillon_ecs::Transform {
translation: Vec3::new(0.0, -2.5, -5.0),
rotation: Quat::IDENTITY,
scale: Vec3::splat(0.01),
}, tree_model));
world.spawn((raidillon_ecs::Transform {
translation: Vec3::new(0.0, -1.5, 0.0),
rotation: Quat::IDENTITY,
scale: Vec3::ONE,
}, ground_model));
let camera_entity = world.spawn((Camera {
eye: Vec3::new(0.0, 0.0, 2.0),
center: Vec3::ZERO,
up: Vec3::Y,
fovy: 60_f32.to_radians(),
aspect: 1280.0 / 720.0,
znear: 0.1,
zfar: 100.0,
},));
systems.add_system(CameraSystem::new(camera_entity));
Ok(Self {
world,
assets,
events,
systems,
render_system,
input_system,
time,
camera_entity,
})
}
pub fn handle_event<T>(&mut self, event: &winit::event::Event<T>) {
self.input_system.handle_event(event);
if let winit::event::Event::WindowEvent { event, .. } = event {
if let winit::event::WindowEvent::Resized(sz) = event {
if let Ok(mut cam) = self.world.query_one_mut::<&mut Camera>(self.camera_entity) {
cam.aspect = sz.width as f32 / sz.height as f32;
}
}
}
}
pub fn update(&mut self) {
self.time.tick();
let dt = self.time.delta_seconds();
self.input_system.update(&mut self.events);
self.systems.update_all(&mut self.world, &self.assets, &mut self.events, dt);
let _ = self.events.drain();
}
pub fn render_into<S: Surface>(&mut self, target: &mut S) {
self.render_system.render_into(&self.world, &self.assets, target);
}
}

View file

@ -1,168 +1,44 @@
use anyhow::Result;
use glam::{Quat, Vec3, EulerRot};
use raidillon_core::Time;
use raidillon_ecs::Transform;
use raidillon_render::{Camera, ECSRenderer, init_render_window, DisplayHandle};
use raidillon_render::{init_render_window, DisplayHandle};
use raidillon_ui::Gui;
use raidillon_input::{Input, FPSCameraController};
use winit::keyboard::KeyCode;
use winit::window::CursorGrabMode;
use winit::event::MouseButton;
mod engine;
use crate::engine::Engine;
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
enum Action {
MoveForward,
MoveBackward,
MoveLeft,
MoveRight,
}
fn main() -> Result<()> {
let event_loop = winit::event_loop::EventLoop::builder()
.build()
.expect("create event-loop");
let (window, _display): (winit::window::Window, DisplayHandle) = init_render_window(&event_loop, "raidillon", (1280, 720))?;
let (window, display): (winit::window::Window, DisplayHandle) = init_render_window(&event_loop, "raidillon", (1280, 720))?;
// Create ECS renderer which internally owns both the world and the renderer
let mut ecsr = ECSRenderer::from_display_handle(&_display)?;
let mut engine = Engine::new(&display)?;
// Dear ImGui integration
let mut gui = Gui::new(&_display, &window)?;
let mut input = Input::<Action>::new();
input.map_key(KeyCode::KeyW, Action::MoveForward);
input.map_key(KeyCode::KeyS, Action::MoveBackward);
input.map_key(KeyCode::KeyA, Action::MoveLeft);
input.map_key(KeyCode::KeyD, Action::MoveRight);
let mut camera_controller = FPSCameraController::new(Vec3::new(0.0, 0.0, 2.0));
let mut right_mouse_held = false;
let mut time = Time::new();
let object_ent = ecsr.load_mesh_from_gltf("resources/models/tree.gltf", Transform {
translation: Vec3::new(0.0, -2.5, -5.0),
rotation: Quat::IDENTITY,
scale: Vec3::new(0.01, 0.01, 0.01),
})?;
let ground_ent = ecsr.load_mesh_from_gltf("resources/models/plane.gltf", Transform {
translation: Vec3::new(0.0, -1.5, 0.0),
rotation: Quat::IDENTITY,
scale: Vec3::new(1.0, 1.0, 1.0),
})?;
let camera_ent = {
let (w, h): (u32, u32) = window.inner_size().into();
ecsr.world.spawn((Camera {
eye: Vec3::new(0.0, 0.0, 2.0),
center: Vec3::ZERO,
up: Vec3::Y,
fovy: 60_f32.to_radians(),
aspect: w as f32 / h as f32,
znear: 0.1,
zfar: 100.0,
},))
};
let mut gui = Gui::new(&display, &window)?;
event_loop
.run(move |event, el| {
use winit::event::{Event, WindowEvent};
use winit::event::{Event};
gui.handle_event(&window, &event);
input.handle_event(&event);
engine.handle_event(&event);
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => el.exit(),
WindowEvent::Resized(sz) => {
ecsr.world.query_one_mut::<&mut Camera>(camera_ent).map(|mut cam| {
cam.aspect = sz.width as f32 / sz.height as f32;
});
Event::WindowEvent { event, .. } => {
if let winit::event::WindowEvent::CloseRequested = event {
el.exit();
}
WindowEvent::MouseInput { state, button, .. } => {
if button == MouseButton::Right {
match state {
winit::event::ElementState::Pressed => {
if window
.set_cursor_grab(CursorGrabMode::Confined)
.or_else(|_| window.set_cursor_grab(CursorGrabMode::Locked))
.is_ok()
{
window.set_cursor_visible(false);
right_mouse_held = true;
}
}
winit::event::ElementState::Released => {
let _ = window.set_cursor_grab(CursorGrabMode::None);
window.set_cursor_visible(true);
right_mouse_held = false;
}
}
}
}
WindowEvent::RedrawRequested => {
// First render the 3D world
let mut target = ecsr.renderer.display().draw();
ecsr.render_into(&mut target);
// Then overlay ImGui on top
gui.render_with(&mut target, &window, |ui| {
if let Ok(mut tr) = ecsr.world.query_one_mut::<&mut Transform>(object_ent) {
ui.text("Hold right click to control the camera");
ui.text("WASD to move");
// Translation controls
let mut translation = [tr.translation.x, tr.translation.y, tr.translation.z];
if ui.input_float3("Translation", &mut translation).build() {
tr.translation = Vec3::from(translation);
}
// Scale controls
let mut scale = [tr.scale.x, tr.scale.y, tr.scale.z];
if ui.input_float3("Scale", &mut scale).build() {
tr.scale = Vec3::from(scale);
}
// Rotation controls
let (yaw, pitch, roll) = tr.rotation.to_euler(EulerRot::YXZ);
let mut rotation_deg = [yaw.to_degrees(), pitch.to_degrees(), roll.to_degrees()];
if ui.input_float3("Rotation (deg)", &mut rotation_deg).build() {
let yaw = rotation_deg[0].to_radians();
let pitch = rotation_deg[1].to_radians();
let roll = rotation_deg[2].to_radians();
tr.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
}
}
});
target.finish().expect("Failed to swap buffers");
}
_ => {}
},
}
Event::WindowEvent { .. } => {}
Event::AboutToWait => {
time.tick();
engine.update();
{
let dt = time.delta_seconds();
camera_controller.update(
&input,
dt,
right_mouse_held,
(Action::MoveForward, Action::MoveBackward, Action::MoveLeft, Action::MoveRight),
);
if let Ok(mut cam) = ecsr.world.query_one_mut::<&mut Camera>(camera_ent) {
cam.eye = camera_controller.position;
cam.center = camera_controller.position + camera_controller.front();
}
}
input.end_frame();
// Render
let mut target = display.as_inner().draw();
engine.render_into(&mut target);
gui.render_with(&mut target, &window, |_| {});
target.finish().unwrap();
gui.prepare_frame(&window);
window.request_redraw();