o3 refactor
This commit is contained in:
parent
341d531db3
commit
049f522bb1
19 changed files with 508 additions and 214 deletions
|
|
@ -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"] }
|
||||
|
|
|
|||
90
raidillon_game/src/engine.rs
Normal file
90
raidillon_game/src/engine.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue