diff options
| -rw-r--r-- | engine-ecs/src/lib.rs | 6 | ||||
| -rw-r--r-- | engine/src/lib.rs | 45 | ||||
| -rw-r--r-- | engine/src/shader/default.rs | 8 | ||||
| -rw-r--r-- | engine/src/windowing.rs | 60 | ||||
| -rw-r--r-- | engine/src/windowing/window.rs | 36 | ||||
| -rw-r--r-- | src/main.rs | 99 |
6 files changed, 134 insertions, 120 deletions
diff --git a/engine-ecs/src/lib.rs b/engine-ecs/src/lib.rs index e9a28ab..878a28c 100644 --- a/engine-ecs/src/lib.rs +++ b/engine-ecs/src/lib.rs @@ -114,6 +114,12 @@ impl World self.error_handler = err_handler; } + + pub fn stop_after_tick(&self) + { + self.stop.store(true, Ordering::Relaxed); + } + /// Creates a entity with the given components. A new unique [`Uid`] will be generated /// for this entity. pub fn create_entity<Comps>(&mut self, components: Comps) -> Uid diff --git a/engine/src/lib.rs b/engine/src/lib.rs index b1c41d6..01c0701 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -3,15 +3,12 @@ use crate::asset::{Assets, Extension as AssetExtension}; use crate::delta_time::{update as update_delta_time, DeltaTime, LastUpdate}; -use crate::ecs::component::Sequence as ComponentSequence; +use crate::ecs::error::HandlerFn as ErrorHandlerFn; use crate::ecs::extension::Extension; use crate::ecs::phase::PRE_UPDATE as PRE_UPDATE_PHASE; -use crate::ecs::sole::Sole; use crate::ecs::system::initializable::Initializable; -use crate::ecs::system::observer::Observer; -use crate::ecs::system::{Into, System}; -use crate::ecs::uid::Uid; -use crate::ecs::{SoleAlreadyExistsError, World}; +use crate::ecs::system::Into; +use crate::ecs::World; use crate::shader::Extension as ShaderExtension; mod util; @@ -87,42 +84,16 @@ impl Engine Self { world } } - pub fn spawn<Comps>(&mut self, components: Comps) -> Uid - where - Comps: ComponentSequence, + pub fn with_error_handler(mut self, error_handler: ErrorHandlerFn) -> Self { - self.world.create_entity(components) + self.world.set_err_handler(error_handler); + self } - pub fn register_system<'this, SystemImpl>( - &'this mut self, - phase_euid: Uid, - system: impl System<'this, SystemImpl>, - ) - { - self.world.register_system(phase_euid, system); - } - - pub fn register_observer<'this, SystemImpl>( - &'this mut self, - observer: impl Observer<'this, SystemImpl>, - ) - { - self.world.register_observer(observer); - } - - /// Adds a globally shared singleton value. - /// - /// # Errors - /// Returns `Err` if this [`Sole`] has already been added. - pub fn add_sole(&mut self, sole: impl Sole) -> Result<(), SoleAlreadyExistsError> - { - self.world.add_sole(sole) - } - - pub fn add_extension(&mut self, extension: impl Extension) + pub fn with_extension(mut self, extension: impl Extension) -> Self { self.world.add_extension(extension); + self } /// Runs the event loop. diff --git a/engine/src/shader/default.rs b/engine/src/shader/default.rs index eafe024..27a38b6 100644 --- a/engine/src/shader/default.rs +++ b/engine/src/shader/default.rs @@ -16,7 +16,11 @@ use crate::material::{Flags as MaterialFlags, Material}; use crate::matrix::Matrix; use crate::model::{MaterialSearchResult, Model}; use crate::projection::{ClipVolume as ProjectionClipVolume, Projection}; -use crate::rendering::{PendingShaderBindings, SurfaceSpec, TargetWindow as RenderingTargetWindow}; +use crate::rendering::{ + PendingShaderBindings, + SurfaceSpec, + TargetWindow as RenderingTargetWindow, +}; use crate::shader::cursor::{BindingValue as ShaderBindingValue, Cursor as ShaderCursor}; use crate::shader::{ Context as ShaderContext, @@ -47,7 +51,7 @@ pub fn enqueue_set_shader_bindings( ) { let Some((camera, camera_world_pos, _)) = camera_query.iter().next() else { - tracing::warn!("No current camera"); + tracing::trace!("No current camera"); return; }; diff --git a/engine/src/windowing.rs b/engine/src/windowing.rs index 8dba8f9..ea5b5f7 100644 --- a/engine/src/windowing.rs +++ b/engine/src/windowing.rs @@ -3,7 +3,7 @@ use std::env::consts::EXE_SUFFIX; use std::hint::cold_path; use std::panic::catch_unwind; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Weak, Mutex}; +use std::sync::{Arc, Mutex, Weak}; use std::thread::Builder as ThreadBuilder; use crossbeam_queue::ArrayQueue; @@ -185,7 +185,7 @@ fn update_stuff( mouse.position = PhysicalPosition { x: absolute_mouse_pos.0, - y: absolute_mouse_pos.1 + y: absolute_mouse_pos.1, }; keyboard.set_text_keys(iter_array_queue(&context.shared_state.text_keys)); @@ -312,7 +312,6 @@ fn update_stuff( let err = err.take().expect("Not possible"); return Err(err.into()); - } Ok(()) @@ -416,7 +415,12 @@ impl Context fn try_send_message_to_app(&self, message: MessageToApp) { - if self.shared_state.message_to_app_queue.push(message).is_err() { + if self + .shared_state + .message_to_app_queue + .push(message) + .is_err() + { tracing::error!( "Failed to send message. Queue for messages to windowing app is full" ); @@ -451,7 +455,7 @@ impl Context }; let event_loop = match create_event_loop() { - Ok(event_loop) => event_loop, + Ok(event_loop) => event_loop, Err(err) => { return Err((app, AppThreadError::CreateEventLoop(err))); } @@ -459,17 +463,26 @@ impl Context event_loop.set_control_flow(EventLoopControlFlow::Poll); - event_loop.run_app(&mut app).map_err(|err| (app, AppThreadError::StartEventLoop(err)))?; + event_loop + .run_app(&mut app) + .map_err(|err| (app, AppThreadError::StartEventLoop(err)))?; Ok(()) }) { - Ok(Ok(())) => {}, + Ok(Ok(())) => {} Ok(Err((app, err))) => { - *app.shared_state.thread_err.try_lock().expect("Not possible") = Some(err); - app.shared_state.has_thread_err.store(true, Ordering::Relaxed); + *app.shared_state + .thread_err + .try_lock() + .expect("Not possible") = Some(err); + app.shared_state + .has_thread_err + .store(true, Ordering::Relaxed); } Err(_) => { - shared_state_c.thread_panicked.store(true, Ordering::Relaxed); + shared_state_c + .thread_panicked + .store(true, Ordering::Relaxed); } }; }) @@ -570,7 +583,7 @@ impl Default for SharedState is_dropped: AtomicBool::new(false), thread_panicked: AtomicBool::new(false), thread_err: Mutex::new(None), - has_thread_err: AtomicBool::new(false) + has_thread_err: AtomicBool::new(false), } } } @@ -596,9 +609,9 @@ impl App ); let winit_window = Arc::new( - match event_loop - .create_window(window_creation_attrs.clone().into_window_attrs()) - { + match event_loop.create_window( + window_creation_attrs.clone().into_window_attrs(), + ) { Ok(window) => window, Err(err) => { tracing::error!("Failed to create window: {err}"); @@ -607,9 +620,16 @@ impl App }, ); + window_creation_attrs.apply_extra_attrs_to_window(&winit_window); + self.windows.insert( WindowId::from_inner(winit_window.id()), - (Arc::downgrade(&winit_window), WindowSettings::default()), + ( + Arc::downgrade(&winit_window), + WindowSettings { + cursor_grab_mode: window_creation_attrs.cursor_grab_mode, + }, + ), ); self.send_message(MessageFromApp::WindowCreated( @@ -772,10 +792,12 @@ impl ApplicationHandler for App let window_size = window.inner_size(); - if let Err(err) = window.set_cursor_position(Position::Physical(PhysicalPosition { - x: window_size.width as i32 / 2, - y: window_size.height as i32 / 2, - })) { + if let Err(err) = + window.set_cursor_position(Position::Physical(PhysicalPosition { + x: window_size.width as i32 / 2, + y: window_size.height as i32 / 2, + })) + { cold_path(); tracing::error!( window_id=?window_id, diff --git a/engine/src/windowing/window.rs b/engine/src/windowing/window.rs index 93cb233..bbf7eb6 100644 --- a/engine/src/windowing/window.rs +++ b/engine/src/windowing/window.rs @@ -33,6 +33,10 @@ pub struct CreationAttributes pub position: Option<Position>, pub inner_size: Option<Size>, pub x_visual_id: Option<XVisualID>, + + // These do not have equivalents in winit::window::WindowAttributes + pub cursor_visible: bool, + pub cursor_grab_mode: CursorGrabMode, } macro_rules! gen_creation_attrs_with_fn { @@ -60,6 +64,9 @@ gen_creation_attrs_with_fn!(position, Option<Position>); gen_creation_attrs_with_fn!(inner_size, Option<Size>); gen_creation_attrs_with_fn!(x_visual_id, Option<XVisualID>); +gen_creation_attrs_with_fn!(cursor_visible, bool); +gen_creation_attrs_with_fn!(cursor_grab_mode, CursorGrabMode); + impl CreationAttributes { pub(crate) fn into_window_attrs(self) -> winit::window::WindowAttributes @@ -69,8 +76,10 @@ impl CreationAttributes .with_transparent(self.transparent) .with_maximized(self.maximized) .with_fullscreen(match self.fullscreen { - Some(Fullscreen::Borderless) => Some(winit::window::Fullscreen::Borderless(None)), - None => None + Some(Fullscreen::Borderless) => { + Some(winit::window::Fullscreen::Borderless(None)) + } + None => None, }) .with_visible(self.visible) .with_resizable(self.resizable); @@ -80,11 +89,18 @@ impl CreationAttributes #[cfg(target_os = "linux")] if let Some(visual_id) = self.x_visual_id { - return <winit::window::WindowAttributes as winit::platform::x11::WindowAttributesExtX11>::with_x11_visual(window_attrs, visual_id) + use winit::platform::x11::WindowAttributesExtX11; + + return window_attrs.with_x11_visual(visual_id); } window_attrs } + + pub(crate) fn apply_extra_attrs_to_window(&self, window: &winit::window::Window) + { + window.set_cursor_visible(self.cursor_visible); + } } impl Default for CreationAttributes @@ -100,7 +116,9 @@ impl Default for CreationAttributes resizable: true, position: None, inner_size: None, - x_visual_id: None + x_visual_id: None, + cursor_visible: true, + cursor_grab_mode: CursorGrabMode::None, } } } @@ -146,8 +164,8 @@ impl Window { Self { title: creation_attrs.title.clone().into_owned(), - cursor_visible: true, - cursor_grab_mode: CursorGrabMode::None, + cursor_visible: creation_attrs.cursor_visible, + cursor_grab_mode: creation_attrs.cursor_grab_mode, wid: Id::from_inner(winit_window.id()), inner_size: winit_window.inner_size().into(), scale_factor: winit_window.scale_factor(), @@ -162,9 +180,9 @@ impl Window let curr_inner_size = winit_window.inner_size().clone().into(); - let inner_size_request_result = match winit_window - .request_inner_size(winit::dpi::Size::Physical(self.inner_size.clone().into())) - { + let inner_size_request_result = match winit_window.request_inner_size( + winit::dpi::Size::Physical(self.inner_size.clone().into()), + ) { // The comparison of curr_inner_size is in case the user's windowing system // lies about using the requested inner size None if curr_inner_size == self.inner_size => Ok(()), diff --git a/src/main.rs b/src/main.rs index ebb6563..e5076d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,11 +11,8 @@ use engine::camera::{Active as ActiveCamera, Camera}; use engine::color::Color; use engine::data_types::dimens::Dimens3; use engine::ecs::actions::Actions; -use engine::ecs::event::component::{Added, EventMatchExt}; -use engine::ecs::pair::Pair; use engine::ecs::phase::START as START_PHASE; use engine::ecs::sole::Single; -use engine::ecs::system::observer::Observe; use engine::input::Extension as InputExtension; use engine::lighting::{AttenuationParams, GlobalLight, PointLight}; use engine::material::{Flags as MaterialFlags, Material}; @@ -24,13 +21,16 @@ use engine::mesh::cube::{ CreationSpec as CubeMeshCreationSpec, }; use engine::model::{Materials as ModelMaterials, Model, Spec as ModelSpec}; -use engine::rendering::{Extension as RenderingExtension, GraphicsProperties, TargetWindow as RenderingTargetWindow}; +use engine::rendering::{ + Extension as RenderingExtension, + GraphicsProperties, + TargetWindow as RenderingTargetWindow, +}; use engine::transform::WorldPosition; use engine::vector::Vec3; use engine::windowing::window::{ CreationAttributes as WindowCreationAttributes, CursorGrabMode as WindowCursorGrabMode, - Window, }; use engine::Engine; use tracing::level_filters::LevelFilter; @@ -61,66 +61,59 @@ fn main() -> Result<(), Box<dyn Error>> ) .init(); - let mut engine = Engine::new(); - - engine.spawn(( - Camera::default(), - WorldPosition { - position: Vec3 { x: 0.0, y: 0.0, z: 3.0 }, - }, - ActiveCamera, - FlyCamera::default(), - )); - - engine.add_sole(GlobalLight::default())?; - - engine.register_system(*START_PHASE, init); - - engine.register_observer(configure_window_on_added); - - engine.add_extension(engine::windowing::Extension::default()); - - engine.add_extension( - RenderingExtension::builder() - .graphics_props( - GraphicsProperties::builder() - .debug(cfg!(debug_assertions)) - .build(), - ) - .build(), - ); - - engine.add_extension(FlyCameraExtension(FlyCameraOptions { - mouse_sensitivity: 0.2, - })); - - engine.add_extension(InputExtension::default()); - - engine.spawn(( - WindowCreationAttributes::default().with_title("Game"), - RenderingTargetWindow - )); - - engine.start(); + Engine::new() + .with_extension(engine::windowing::Extension::default()) + .with_extension( + RenderingExtension::builder() + .graphics_props( + GraphicsProperties::builder() + .debug(cfg!(debug_assertions)) + .build(), + ) + .build(), + ) + .with_extension(InputExtension::default()) + .with_extension(FlyCameraExtension(FlyCameraOptions { + mouse_sensitivity: 0.2, + })) + .with_extension(Application) + .start(); Ok(()) } -fn configure_window_on_added(observe: Observe<Pair<Added, Window>>) -{ - for evt_match in &observe { - let mut window = evt_match.get_ent_target_comp_mut(); +struct Application; - window.cursor_visible = false; - window.cursor_grab_mode = WindowCursorGrabMode::Locked; +impl engine::ecs::extension::Extension for Application +{ + fn collect(self, mut collector: engine::ecs::extension::Collector<'_>) + { + let _ = collector.add_sole(GlobalLight::default()); - window.set_changed(); + collector.add_system(*START_PHASE, init); } } fn init(mut assets: Single<Assets>, mut actions: Actions) { actions.spawn(( + WindowCreationAttributes::default() + .with_title("Game") + .with_cursor_visible(false) + .with_cursor_grab_mode(WindowCursorGrabMode::Locked), + RenderingTargetWindow, + )); + + actions.spawn(( + Camera::default(), + WorldPosition { + position: Vec3 { x: 0.0, y: 0.0, z: 3.0 }, + }, + ActiveCamera, + FlyCamera::default(), + )); + + actions.spawn(( PointLight::builder() .diffuse(YELLOW) .attenuation_params(AttenuationParams { |
