summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engine-ecs/src/lib.rs6
-rw-r--r--engine/src/lib.rs45
-rw-r--r--engine/src/shader/default.rs8
-rw-r--r--engine/src/windowing.rs60
-rw-r--r--engine/src/windowing/window.rs36
-rw-r--r--src/main.rs99
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 {