Switch ecs to edict #1

Merged
SeanOMik merged 1 commits from feature/ecs-edict into feature/ecs-events-resources 2023-09-01 03:43:03 +00:00
18 changed files with 232 additions and 375 deletions
Showing only changes of commit d8deb6458b - Show all commits

61
Cargo.lock generated
View File

@ -264,6 +264,12 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
[[package]]
name = "atomicell"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157342dd84c64f16899b4b16c1fb2cce54b887990362aac3c590b3d13810890f"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -534,6 +540,42 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "edict"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d85bf7cde5687ce04b093bfe183453fa12996b6bdfd2567a0262ebd621761d77"
dependencies = [
"atomicell",
"edict-proc",
"hashbrown 0.13.2",
"parking_lot",
"smallvec",
"tiny-fn",
]
[[package]]
name = "edict-proc"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c94d80dc0f05250a9082bb9455bbf3d6c6c51db388b060df914aebcfb4a9b9f1"
dependencies = [
"edict-proc-lib",
"syn 2.0.26",
]
[[package]]
name = "edict-proc-lib"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52d98f9931a4f71c7eb7d85cf4ef1271b27014625c85a65376a52c10ac4ffaea"
dependencies = [
"proc-easy",
"proc-macro2",
"quote",
"syn 2.0.26",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.1" version = "1.0.1"
@ -1036,8 +1078,10 @@ dependencies = [
"anyhow", "anyhow",
"async-std", "async-std",
"async-trait", "async-trait",
"atomicell",
"bytemuck", "bytemuck",
"cfg-if", "cfg-if",
"edict",
"gilrs-core", "gilrs-core",
"glam", "glam",
"hecs", "hecs",
@ -1492,6 +1536,17 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "proc-easy"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea59c637cd0e6b71ae18e589854e9de9b7cb17fefdbf2047e42bd38e24285b19"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.26",
]
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "1.3.1" version = "1.3.1"
@ -1780,6 +1835,12 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "tiny-fn"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af7b2c33e09916c65a15c92c1e583946052527e06102689ed11c6125f64fa8ba"
[[package]] [[package]]
name = "tiny-skia" name = "tiny-skia"
version = "0.8.4" version = "0.8.4"

View File

@ -27,3 +27,5 @@ petgraph = "0.6.3"
gilrs-core = "0.5.6" gilrs-core = "0.5.6"
syn = "2.0.26" syn = "2.0.26"
quote = "1.0.29" quote = "1.0.29"
edict = "0.5.0"
atomicell = "0.1.9"

View File

@ -1,7 +1,9 @@
use edict::Component;
use winit::dpi::PhysicalSize; use winit::dpi::PhysicalSize;
use crate::{math::{Angle, OPENGL_TO_WGPU_MATRIX, Transform}, render::camera::CameraProjectionMode}; use crate::{math::{Angle, OPENGL_TO_WGPU_MATRIX, Transform}, render::camera::CameraProjectionMode};
#[derive(Clone, Component)]
pub struct CameraComponent { pub struct CameraComponent {
pub transform: Transform, pub transform: Transform,
pub fov: Angle, pub fov: Angle,

View File

@ -1,6 +1,8 @@
use edict::Component;
use crate::render::{vertex::Vertex, mesh::Mesh, material::Material}; use crate::render::{vertex::Vertex, mesh::Mesh, material::Material};
#[derive(Clone)] #[derive(Clone, Component)]
pub struct MeshComponent { pub struct MeshComponent {
pub mesh: Mesh, pub mesh: Mesh,
pub material: Material, pub material: Material,

View File

@ -1,6 +1,8 @@
use edict::Component;
use crate::math::Transform; use crate::math::Transform;
#[derive(Clone)] #[derive(Clone, Component)]
pub struct TransformComponent { pub struct TransformComponent {
pub transform: Transform, pub transform: Transform,
} }

View File

@ -6,11 +6,8 @@ use tracing::warn;
use crate::game::Controls; use crate::game::Controls;
pub mod components; pub mod components;
pub mod world;
pub mod resources; pub mod resources;
use world::World;
/// A trait that represents a simple system /// A trait that represents a simple system
pub trait SimpleSystem { pub trait SimpleSystem {
fn setup(&mut self, controls: &mut Controls) -> anyhow::Result<()> { fn setup(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
@ -22,7 +19,7 @@ pub trait SimpleSystem {
} }
impl<S> SimpleSystem for S impl<S> SimpleSystem for S
where S: FnMut(&mut World) -> anyhow::Result<()> where S: FnMut(&mut edict::World) -> anyhow::Result<()>
{ {
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> { fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
self(controls.world) self(controls.world)

View File

@ -0,0 +1,63 @@
use std::{collections::{HashMap, VecDeque}, any::{TypeId, Any}, cell::{RefCell, Ref, RefMut}};
use super::{CastableAny, Events, Event};
pub struct EventQueue {
events: HashMap<TypeId, RefCell<Box<dyn CastableAny>>>,
event_write_queue: HashMap<TypeId, RefCell<Box<dyn CastableAny>>>
}
impl EventQueue {
pub fn new() -> Self {
Self {
event_write_queue: HashMap::new(),
events: HashMap::new(),
}
}
/// Trigger an event
pub fn trigger_event<E>(&mut self, event: E)
where
E: Event
{
// the compiler wants me to explicit right here for some reason
let default = || RefCell::new(Box::new(Events::<E>::new()) as Box<dyn CastableAny>);
// Get, or create, a list of events of this type
let type_id = event.type_id();
let mut events = self.event_write_queue.entry(type_id)
.or_insert_with(default)
.borrow_mut();
// downcast resource as an events storage
let e: &mut Events<E> = events.as_mut().as_any_mut().downcast_mut().unwrap();
e.push_back(event);
}
// Clear events, this should happen at the start of every tick since events are cloned
// before being given to the reader.
pub fn update_events(&mut self) {
self.events.clear();
// get all keys of events
let keys: Vec<TypeId> = self.event_write_queue.keys().map(|k| k.clone()).collect();
// remove all elements from self.event_write_queue and insert them to events
for k in keys.into_iter() {
let v = self.event_write_queue.remove(&k).unwrap();
self.events.insert(k, v);
}
}
pub fn read_events<E>(&self) -> Option<Events<E>>
where
E: Event
{
if let Some(event ) = self.events.get(&TypeId::of::<E>()) {
let eref = event.borrow();
Some(eref.as_ref().as_any().downcast_ref::<Events<E>>().unwrap().clone())
} else {
None
}
}
}

View File

@ -1,53 +1,6 @@
use std::{collections::VecDeque, ops::{Deref, DerefMut}}; use std::collections::VecDeque;
use super::Resource;
pub trait Event: Clone + Send + Sync + 'static {} pub trait Event: Clone + Send + Sync + 'static {}
impl<T: Clone + Send + Sync + 'static> Event for T {} impl<T: Clone + Send + Sync + 'static> Event for T {}
#[derive(Clone)] pub type Events<T> = VecDeque<T>;
pub struct Events<T: Event> {
inner: VecDeque<T>
}
impl<T: Event> Events<T> {
pub fn new() -> Self {
Self {
inner: VecDeque::new()
}
}
}
impl<T: Event> Deref for Events<T> {
type Target = VecDeque<T>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T: Event> DerefMut for Events<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T: Event> Resource for Events<T> {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
pub trait EventHolder {
fn get_data<T>() -> T;
}
pub struct EventStorage<T> {
data: T,
is_future: bool,
}

View File

@ -8,22 +8,16 @@ pub use window_state::*;
pub mod events; pub mod events;
pub use events::*; pub use events::*;
pub trait Resource: Send + Sync + 'static { pub mod event_queue;
pub use event_queue::*;
pub trait CastableAny: Send + Sync + 'static {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any;
} }
impl Resource for WindowEvent<'static> { /// Implements this trait for anything that fits the type bounds
fn as_any(&self) -> &dyn Any { impl<T: Send + Sync + 'static> CastableAny for T {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl<T: Sync + Send + 'static> Resource for VecDeque<T> {
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }

View File

@ -1,6 +1,6 @@
use std::any::Any; use std::any::Any;
use super::Resource; use super::CastableAny;
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct WindowState { pub struct WindowState {
@ -13,13 +13,3 @@ impl WindowState {
Self::default() Self::default()
} }
} }
impl Resource for WindowState {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}

View File

@ -1,185 +0,0 @@
use std::{any::{TypeId, Any}, collections::{HashMap, HashSet, VecDeque}, ops::{Deref, DerefMut}, cell::{RefCell, Ref, RefMut}};
use tracing::debug;
use super::resources::{Resource, Events};
pub struct World {
inner: hecs::World,
resources: HashMap<TypeId, Box<RefCell<dyn Resource>>>,
updated_resources: HashSet<TypeId>,
// a boolean that flip flops to clear events every other frame
events_flipflop: bool,
events: HashMap<TypeId, Box<RefCell<dyn Resource>>>,
event_write_queue: HashMap<TypeId, Box<RefCell<dyn Resource>>>,//VecDeque<(TypeId, Box<dyn Resource>)>,
}
impl Deref for World {
type Target = hecs::World;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for World {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
#[allow(dead_code)]
impl World {
pub fn new() -> Self {
Self::from_hecs(hecs::World::new())
}
pub fn from_hecs(hecs_world: hecs::World) -> Self {
Self {
inner: hecs_world,
resources: HashMap::new(),
updated_resources: HashSet::new(),
events_flipflop: false,
events: HashMap::new(),
event_write_queue: HashMap::new(),
}
}
/// Attempts to query a resource, or will create it when its not found.
///
/// The resource will be created by a function passed in `default`.
pub fn query_or_insert_res<R>(&mut self, default: impl Fn() -> Box<RefCell<dyn Resource + 'static>>) -> RefMut<R>
where
R: Resource,
{
let type_id = TypeId::of::<R>();
let r = self.resources.entry(type_id)
.or_insert_with(default)
.borrow_mut();
RefMut::map(r, |r| r.as_any_mut().downcast_mut::<R>().unwrap())
}
/// Insert a resource into the World. You can only have one resource of the same type.
/// If you attempt to add another resource of the same type, it will be replaced.
///
/// This will also mark the resource as updated in this frame.
pub fn insert_resource<R>(&mut self, res: R)
where
R: Resource
{
let type_id = res.type_id();
self.resources.insert(type_id, Box::new(RefCell::new(res)));
self.updated_resources.insert(type_id);
}
/// Checks if a resource was updated this frame.
pub fn was_res_updated<R>(&self) -> bool
where
R: Resource
{
self.updated_resources.contains(&TypeId::of::<R>())
}
pub(crate) fn clear_updated_resources(&mut self) {
self.updated_resources.clear();
}
/// Trigger an event
pub fn trigger_event<E>(&mut self, event: E)
where
E: Clone + Send + Sync + 'static
{
// the compiler wants me to explicit right here for some reason
let default = || Box::new(RefCell::new(Events::<E>::new())) as Box<RefCell<(dyn Resource + 'static)>>;
// Get, or create, a list of events of this type
let type_id = event.type_id();
let events = self.event_write_queue.entry(type_id)
.or_insert_with(default)
.borrow_mut();
// downcast resource as an events storage
let mut events: RefMut<Events<E>> = RefMut::map(events, |e| e.as_any_mut().downcast_mut().unwrap());
events.push_back(event);
}
/// Clear events, this should happen at the start of every tick since events are cloned
/// before being given to the reader.
pub fn update_events(&mut self) {
self.events.clear();
// get all keys of events
let keys: Vec<TypeId> = self.event_write_queue.keys().map(|k| k.clone()).collect();
// remove all elements from self.event_write_queue and insert them to events
for k in keys.into_iter() {
let v = self.event_write_queue.remove(&k).unwrap();
self.events.insert(k, v);
}
}
pub fn read_events<E>(&self) -> Option<Ref<Events<E>>>
where
E: Clone + Send + Sync + 'static
{
if let Some(event ) = self.events.get(&TypeId::of::<E>()) {
//.or_else(|| self.event_write_queue.get(&TypeId::of::<E>())) {
let eref = event.borrow();
Some(Ref::map(eref, |x| x.as_any().downcast_ref::<Events<E>>().unwrap()))
} else {
None
}
/* if let Some(event) = self.events.get(&TypeId::of::<E>()) {
let eref = event.borrow();
Some(Ref::map(eref, |x| x.as_any().downcast_ref::<Events<E>>().unwrap()))
} else if let Some(event) = self.events.get(&TypeId::of::<E>()) {
None
} */
/* self.events.get(&TypeId::of::<E>())
//.map(|r| r.borrow().as_any().downcast_ref::<Events<E>>())
.map(|r| r.borrow().as_any().do)
.flatten() */
}
/// Query a resource.
///
/// This is O(1), resources are stored in HashMaps.
pub fn query_res<R>(&self) -> Option<Ref<R>>
where
R: Resource
{
self.resources
.get(&TypeId::of::<R>())
.map(|r| {
let r = r.borrow();
Ref::map(r, |r| r.as_any().downcast_ref().unwrap())
})
}
/// Query a resource mutably.
///
/// This will mark the resource as changed, even if it actually wasn't modified when mutably borrowed.
/// This is O(1), resources are stored in HashMaps.
pub fn query_res_mut<R>(&mut self) -> Option<RefMut<R>>
where
R: Resource
{
self.resources
.get_mut(&TypeId::of::<R>())
.map(|r| {
// update resource
self.updated_resources.insert(TypeId::of::<R>());
let r = r.borrow_mut();
RefMut::map(r, |r| r.as_any_mut().downcast_mut::<R>().unwrap())
})
}
}

View File

@ -1,4 +1,4 @@
use std::{sync::Arc, cell::RefCell, borrow::Borrow, collections::VecDeque}; use std::sync::Arc;
use async_std::{task::block_on, sync::Mutex}; use async_std::{task::block_on, sync::Mutex};
@ -13,10 +13,10 @@ use tracing_subscriber::{
use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, DeviceEvent}, event_loop::{EventLoop, ControlFlow}}; use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, DeviceEvent}, event_loop::{EventLoop, ControlFlow}};
use crate::{render::{renderer::{Renderer, BasicRenderer}, render_job::RenderJob}, input_event::InputEvent, ecs::{components::{mesh::MeshComponent, transform::TransformComponent}, SimpleSystem, SystemDispatcher, world::World, resources::{WindowState, Events}}, input::InputEventUpdater}; use crate::{render::renderer::{Renderer, BasicRenderer}, input_event::InputEvent, ecs::{SimpleSystem, SystemDispatcher, resources::{WindowState, Events, EventQueue}}};
pub struct Controls<'a> { pub struct Controls<'a> {
pub world: &'a mut World, pub world: &'a mut edict::World,
} }
struct TickCounter { struct TickCounter {
@ -78,7 +78,7 @@ struct GameLoop {
window: Arc<Window>, window: Arc<Window>,
renderer: Box<dyn Renderer>, renderer: Box<dyn Renderer>,
world: Arc<Mutex<World>>, world: Arc<Mutex<edict::World>>,
/// higher priority systems /// higher priority systems
engine_sys_dispatcher: SystemDispatcher, engine_sys_dispatcher: SystemDispatcher,
user_sys_dispatcher: SystemDispatcher, user_sys_dispatcher: SystemDispatcher,
@ -86,7 +86,13 @@ struct GameLoop {
} }
impl GameLoop { impl GameLoop {
pub async fn new(window: Arc<Window>, world: Arc<Mutex<World>>, user_systems: SystemDispatcher) -> GameLoop { pub async fn new(window: Arc<Window>, world: Arc<Mutex<edict::World>>, user_systems: SystemDispatcher) -> GameLoop {
// Create the EventQueue resource in the world
{
let mut world = world.lock().await;
world.insert_resource(EventQueue::new());
}
Self { Self {
window: Arc::clone(&window), window: Arc::clone(&window),
renderer: Box::new(BasicRenderer::create_with_window(window).await), renderer: Box::new(BasicRenderer::create_with_window(window).await),
@ -99,7 +105,7 @@ impl GameLoop {
} }
pub async fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) { pub async fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
self.renderer.on_resize(new_size).await; self.renderer.on_resize(new_size);
} }
pub fn run_sync(&mut self, event: Event<()>, control_flow: &mut ControlFlow) { pub fn run_sync(&mut self, event: Event<()>, control_flow: &mut ControlFlow) {
@ -142,7 +148,7 @@ impl GameLoop {
InputEvent::CursorEntered { .. } => { InputEvent::CursorEntered { .. } => {
let mut world = self.world.lock().await; let mut world = self.world.lock().await;
let mut state = world.query_or_insert_res::<WindowState>(|| Box::new(RefCell::new(WindowState::new()))); let mut state = world.with_resource(|| WindowState::new());
state.is_cursor_inside_window = true; state.is_cursor_inside_window = true;
None None
@ -151,7 +157,7 @@ impl GameLoop {
InputEvent::CursorLeft { .. } => { InputEvent::CursorLeft { .. } => {
let mut world = self.world.lock().await; let mut world = self.world.lock().await;
let mut state = world.query_or_insert_res::<WindowState>(|| Box::new(RefCell::new(WindowState::new()))); let mut state = world.with_resource(|| WindowState::new());
state.is_cursor_inside_window = false; state.is_cursor_inside_window = false;
None None
@ -186,14 +192,13 @@ impl GameLoop {
let mut world = self.world.lock().await; let mut world = self.world.lock().await;
// make sure that the mouse is inside the window and the mouse has focus before reporting mouse motion // make sure that the mouse is inside the window and the mouse has focus before reporting mouse motion
let trigger = match world.query_res::<WindowState>() { let trigger = match world.get_resource::<WindowState>() {
Some(window_state) if window_state.is_focused && window_state.is_cursor_inside_window => true, Some(window_state) if window_state.is_focused && window_state.is_cursor_inside_window => true,
_ => false, _ => false,
}; };
if trigger { if trigger {
let mut event_queue = world.query_or_insert_res::<Events<InputEvent>> let event_queue = world.with_resource(|| Events::<InputEvent>::new());
(|| Box::new(RefCell::new(Events::<InputEvent>::new())));
let input_event = InputEvent::MouseMotion { device_id, delta, }; let input_event = InputEvent::MouseMotion { device_id, delta, };
event_queue.push_back(input_event); event_queue.push_back(input_event);
@ -212,8 +217,10 @@ impl GameLoop {
// Its possible to receive multiple input events before the update event for // Its possible to receive multiple input events before the update event for
// the InputSystem is called, so we must use a queue for the events. // the InputSystem is called, so we must use a queue for the events.
{ {
let mut world = self.world.lock().await; let world = self.world.lock().await;
world.trigger_event(input_event.clone()); if let Some(mut event_queue) = world.get_resource_mut::<EventQueue>() {
event_queue.trigger_event(input_event.clone());
};
} }
if let Some(new_control) = self.input_update(&input_event).await { if let Some(new_control) = self.input_update(&input_event).await {
@ -238,7 +245,7 @@ impl GameLoop {
WindowEvent::Focused(is_focused) => { WindowEvent::Focused(is_focused) => {
let mut world = self.world.lock().await; let mut world = self.world.lock().await;
let mut state = world.query_or_insert_res::<WindowState>(|| Box::new(RefCell::new(WindowState::new()))); let mut state = world.with_resource(|| WindowState::new());
state.is_focused = *is_focused; state.is_focused = *is_focused;
}, },
@ -257,12 +264,13 @@ impl GameLoop {
} */ } */
let mut world = self.world.lock().await; let mut world = self.world.lock().await;
self.renderer.as_mut().prepare(&mut world).await; self.renderer.as_mut().prepare(&mut world);
world.clear_updated_resources(); if let Some(mut event_queue) = world.get_resource_mut::<EventQueue>() {
world.update_events(); event_queue.update_events();
}
drop(world); drop(world);
match self.renderer.as_mut().render().await { match self.renderer.as_mut().render() {
Ok(_) => {} Ok(_) => {}
// Reconfigure the surface if lost // Reconfigure the surface if lost
Err(wgpu::SurfaceError::Lost) => self.on_resize(self.renderer.as_ref().surface_size()).await, Err(wgpu::SurfaceError::Lost) => self.on_resize(self.renderer.as_ref().surface_size()).await,
@ -282,7 +290,7 @@ impl GameLoop {
} }
pub struct Game { pub struct Game {
world: Option<Arc<Mutex<World>>>, world: Option<Arc<Mutex<edict::World>>>,
system_dispatcher: Option<SystemDispatcher> system_dispatcher: Option<SystemDispatcher>
} }
@ -312,13 +320,13 @@ impl Game {
Self::default() Self::default()
} }
pub fn with_world(&mut self, world: World) -> &mut Self { pub fn with_world(&mut self, world: edict::World) -> &mut Self {
self.world = Some(Arc::new(Mutex::new(world))); self.world = Some(Arc::new(Mutex::new(world)));
self self
} }
pub fn with_world_arc(&mut self, world: Arc<Mutex<World>>) -> &mut Self { pub fn with_world_arc(&mut self, world: Arc<Mutex<edict::World>>) -> &mut Self {
self.world = Some(world); self.world = Some(world);
self self

View File

@ -5,7 +5,7 @@ use glam::Vec2;
use tracing::{warn, debug}; use tracing::{warn, debug};
use winit::event::{VirtualKeyCode, ElementState, MouseScrollDelta}; use winit::event::{VirtualKeyCode, ElementState, MouseScrollDelta};
use crate::{ecs::{SimpleSystem, resources::{Resource, Events}, world::World}, input_event::InputEvent}; use crate::{ecs::{SimpleSystem, resources::{CastableAny, Events, EventQueue}}, input_event::InputEvent};
pub type KeyCode = winit::event::VirtualKeyCode; pub type KeyCode = winit::event::VirtualKeyCode;
@ -100,16 +100,6 @@ pub struct Touches {
pub touches: Vec<Touch>, pub touches: Vec<Touch>,
} }
impl Resource for Touches {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl Touches { impl Touches {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -152,16 +142,6 @@ pub struct InputButtons<T: Clone + Hash + Eq + PartialEq + 'static> {
button_events: HashMap<u64, ButtonEvent<T>>, button_events: HashMap<u64, ButtonEvent<T>>,
} }
impl<T: Sync + Send + Clone + Hash + Eq + PartialEq + 'static> Resource for InputButtons<T> {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl<T: Clone + Hash + Eq + PartialEq + 'static> InputButtons<T> { impl<T: Clone + Hash + Eq + PartialEq + 'static> InputButtons<T> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -279,12 +259,19 @@ impl InputEventUpdater {
} }
} }
pub fn update(&mut self, event: &InputEvent, world: &mut World) -> bool { pub fn update(&mut self, event: &InputEvent, world: &mut edict::World) -> bool {
let event_queue = world.get_resource_mut::<EventQueue>();
if event_queue.is_none() {
return false;
}
let mut event_queue = event_queue.unwrap();
match event { match event {
InputEvent::KeyboardInput { input, .. } => { InputEvent::KeyboardInput { input, .. } => {
if let Some(code) = input.virtual_keycode { if let Some(code) = input.virtual_keycode {
let mut e = world.query_or_insert_res::<InputButtons<KeyCode>> drop(event_queue);
(|| Box::new(RefCell::new(InputButtons::<KeyCode>::new()))); let mut e = world.with_resource(|| InputButtons::<KeyCode>::new());
//let mut e = with_resource_mut(world, || InputButtons::<KeyCode>::new());
e.add_input_from_winit(code, input.state); e.add_input_from_winit(code, input.state);
} }
}, },
@ -293,22 +280,22 @@ impl InputEventUpdater {
delta: Vec2::new(delta.0 as f32, delta.1 as f32) delta: Vec2::new(delta.0 as f32, delta.1 as f32)
}; };
world.trigger_event(delta); event_queue.trigger_event(delta);
}, },
InputEvent::CursorMoved { position, .. } => { InputEvent::CursorMoved { position, .. } => {
let exact = MouseExact { let exact = MouseExact {
pos: Vec2::new(position.x as f32, position.y as f32) pos: Vec2::new(position.x as f32, position.y as f32)
}; };
world.trigger_event(exact); event_queue.trigger_event(exact);
}, },
InputEvent::CursorEntered { .. } => { InputEvent::CursorEntered { .. } => {
let event = CursorEnteredWindow {}; let event = CursorEnteredWindow {};
world.trigger_event(event); event_queue.trigger_event(event);
}, },
InputEvent::CursorLeft { .. } => { InputEvent::CursorLeft { .. } => {
let event = CursorLeftWindow {}; let event = CursorLeftWindow {};
world.trigger_event(event); event_queue.trigger_event(event);
}, },
InputEvent::MouseWheel { delta, .. } => { InputEvent::MouseWheel { delta, .. } => {
let event = match delta { let event = match delta {
@ -320,7 +307,7 @@ impl InputEventUpdater {
}, },
}; };
world.trigger_event(event); event_queue.trigger_event(event);
}, //MouseButton }, //MouseButton
InputEvent::MouseInput { button, state, .. } => { InputEvent::MouseInput { button, state, .. } => {
let button_event = match button { let button_event = match button {
@ -330,13 +317,15 @@ impl InputEventUpdater {
winit::event::MouseButton::Other(v) => MouseButton::Other(*v), winit::event::MouseButton::Other(v) => MouseButton::Other(*v),
}; };
world.trigger_event(button_event.clone()); event_queue.trigger_event(button_event.clone());
drop(event_queue);
let mut e = world.query_or_insert_res::<InputButtons<MouseButton>> let mut e = world.with_resource(|| InputButtons::<MouseButton>::new());
(|| Box::new(RefCell::new(InputButtons::<MouseButton>::new())));
e.add_input_from_winit(button_event, state.clone()); e.add_input_from_winit(button_event, state.clone());
}, },
InputEvent::Touch(t) => { InputEvent::Touch(t) => {
drop(event_queue);
let touch = Touch { let touch = Touch {
phase: TouchPhase::from(t.phase), phase: TouchPhase::from(t.phase),
location: Vec2::new(t.location.x as f32, t.location.y as f32), location: Vec2::new(t.location.x as f32, t.location.y as f32),
@ -347,9 +336,7 @@ impl InputEventUpdater {
finger_id: t.id, finger_id: t.id,
}; };
let mut touches = world.query_or_insert_res::<Touches> let mut touches = world.with_resource(|| Touches::new());
(|| Box::new(RefCell::new(Touches::new())));
touches.touches.push(touch); touches.touches.push(touch);
}, },
_ => {}, _ => {},
@ -363,32 +350,19 @@ impl SimpleSystem for InputEventUpdater {
fn execute_mut(&mut self, controls: &mut crate::game::Controls) -> anyhow::Result<()> { fn execute_mut(&mut self, controls: &mut crate::game::Controls) -> anyhow::Result<()> {
let world = &mut controls.world; let world = &mut controls.world;
let queue = world.read_events::<InputEvent>(); let queue = world.get_resource_mut::<EventQueue>()
.map(|q| q.read_events::<InputEvent>()).flatten();
if queue.is_none() { if queue.is_none() {
return Ok(()); return Ok(());
} }
let queue = queue.unwrap(); let mut events = queue.unwrap();
// borrow checker isn't happy when I query multiple things :(
let mut events = queue.clone();
drop(queue);
while let Some(event) = events.pop_front() { while let Some(event) = events.pop_front() {
self.update(&event, world); self.update(&event, world);
} }
/* if let Some(queue) = world.read_events::<InputEvent>() {
// Clone the queue, then clear it
let mut events = queue.clone();
drop(queue);
while let Some(event) = events.pop_front() {
self.update(&event, world);
}
} */
Ok(()) Ok(())
} }
} }

View File

@ -1,6 +1,6 @@
use winit::{event::{DeviceId, KeyboardInput, ModifiersState, MouseScrollDelta, TouchPhase, MouseButton, AxisId, Touch, WindowEvent, ElementState}, dpi::PhysicalPosition}; use winit::{event::{DeviceId, KeyboardInput, ModifiersState, MouseScrollDelta, TouchPhase, MouseButton, AxisId, Touch, WindowEvent, ElementState}, dpi::PhysicalPosition};
use crate::ecs::resources::Resource; use crate::ecs::resources::CastableAny;
/// Wrapper around events from `winit::WindowEvent` that are specific to input related events. /// Wrapper around events from `winit::WindowEvent` that are specific to input related events.
/// ///
@ -221,13 +221,3 @@ impl<'a> TryFrom<&'a WindowEvent<'a>> for InputEvent {
} }
} }
} }
impl Resource for InputEvent {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}

View File

@ -6,16 +6,15 @@ mod ecs;
mod math; mod math;
mod input; mod input;
use std::cell::Ref; use atomicell::Ref;
use ecs::components::mesh::MeshComponent; use ecs::components::mesh::MeshComponent;
use ecs::components::transform::TransformComponent; use ecs::components::transform::TransformComponent;
use edict::QueryIter;
use game::Game; use game::Game;
use input_event::InputEvent; use input_event::InputEvent;
use tracing::debug; use tracing::debug;
use crate::ecs::world::World;
use crate::input::{InputEventUpdater, KeyCode, MouseMotion, MouseExact, CursorEnteredWindow, MouseScroll, CursorLeftWindow, MouseButton, InputButtons}; use crate::input::{InputEventUpdater, KeyCode, MouseMotion, MouseExact, CursorEnteredWindow, MouseScroll, CursorLeftWindow, MouseButton, InputButtons};
use crate::render::material::Material; use crate::render::material::Material;
use crate::render::texture::Texture; use crate::render::texture::Texture;
@ -68,7 +67,7 @@ impl Point3d {
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
let mut world = World::new(); let mut world = edict::World::new();
//world.spawn((Point2d::new(10, 10), Point3d::new(50, 50, 50))); //world.spawn((Point2d::new(10, 10), Point3d::new(50, 50, 50)));
@ -91,10 +90,8 @@ async fn main() {
camera.transform.rotate_z(Angle::Degrees(-90.0)); camera.transform.rotate_z(Angle::Degrees(-90.0));
world.spawn((camera,)); world.spawn((camera,));
let jiggle_system = |world: &mut World| -> anyhow::Result<()> { let jiggle_system = |world: &mut edict::World| -> anyhow::Result<()> {
//let input: &InputEventUpdater = world.query_res().unwrap(); let keys = world.get_resource();
let keys = world.query_res();
if keys.is_none() { if keys.is_none() {
return Ok(()); return Ok(());
} }
@ -124,7 +121,16 @@ async fn main() {
drop(keys); drop(keys);
for (_eid, (transform, )) in world.query_mut::<(&mut TransformComponent,)>() { for transform in world.query_mut::<(&mut TransformComponent,)>().iter_mut() {
let t = &mut transform.transform;
//debug!("Translation: {}", t.translation);
/* t.translation += glam::Vec3::new(0.0, 0.001, 0.0);
t.translation.x *= -1.0; */
t.translation.x += dir_x;
t.translation.y += dir_y;
}
/* for (transform,) in world.query_mut::<(TransformComponent, )>().iter() {
let t = &mut transform.transform; let t = &mut transform.transform;
/* debug!("Translation: {}", t.translation); /* debug!("Translation: {}", t.translation);
@ -133,7 +139,7 @@ async fn main() {
t.translation.x *= -1.0 */ t.translation.x *= -1.0 */
t.translation.x += dir_x; t.translation.x += dir_x;
t.translation.y += dir_y; t.translation.y += dir_y;
} } */
Ok(()) Ok(())
}; };

View File

@ -10,6 +10,7 @@ pub fn radians_to_degrees(radians: f32) -> f32 {
radians * 180.0 / PI radians * 180.0 / PI
} }
#[derive(Clone)]
pub enum Angle { pub enum Angle {
Degrees(f32), Degrees(f32),
Radians(f32), Radians(f32),

View File

@ -1,4 +1,4 @@
use hecs::Entity; use edict::EntityId;
use crate::math::Transform; use crate::math::Transform;
@ -7,14 +7,14 @@ use super::{mesh::Mesh, material::Material};
pub struct RenderJob { pub struct RenderJob {
mesh: Mesh, mesh: Mesh,
material: Material, material: Material,
entity: Entity, entity: EntityId,
transform: Transform, transform: Transform,
last_transform: Option<Transform>, // TODO: render interpolation last_transform: Option<Transform>, // TODO: render interpolation
} }
impl RenderJob { impl RenderJob {
pub fn new(mesh: Mesh, material: Material, entity: Entity, transform: Transform, last_transform: Option<Transform>) -> Self { pub fn new(mesh: Mesh, material: Material, entity: EntityId, transform: Transform, last_transform: Option<Transform>) -> Self {
Self { Self {
mesh, mesh,
material, material,
@ -32,7 +32,7 @@ impl RenderJob {
&self.material &self.material
} }
pub fn entity(&self)-> Entity { pub fn entity(&self)-> EntityId {
self.entity self.entity
} }

View File

@ -6,17 +6,16 @@ use std::borrow::Cow;
use async_std::sync::Mutex; use async_std::sync::Mutex;
use async_trait::async_trait; use async_trait::async_trait;
use atomicell::{AtomicCell, RefMut};
use edict::{EntityId, Entities};
use tracing::{debug, warn}; use tracing::{debug, warn};
use wgpu::{BindGroup, BindGroupLayout}; use wgpu::{BindGroup, BindGroupLayout};
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use winit::window::Window; use winit::window::Window;
use hecs::Entity;
use crate::ecs::components::camera::CameraComponent; use crate::ecs::components::camera::CameraComponent;
use crate::ecs::components::mesh::MeshComponent; use crate::ecs::components::mesh::MeshComponent;
use crate::ecs::components::transform::TransformComponent; use crate::ecs::components::transform::TransformComponent;
use crate::ecs::world::World;
use crate::math::{Transform, Angle}; use crate::math::{Transform, Angle};
use crate::resources; use crate::resources;
@ -25,11 +24,10 @@ use super::desc_buf_lay::DescVertexBufferLayout;
use super::texture::RenderTexture; use super::texture::RenderTexture;
use super::{render_pipeline::FullRenderPipeline, vertex::{VERTICES}, render_buffer::BufferStorage, render_job::RenderJob, mesh::Mesh}; use super::{render_pipeline::FullRenderPipeline, vertex::{VERTICES}, render_buffer::BufferStorage, render_job::RenderJob, mesh::Mesh};
#[async_trait]
pub trait Renderer { pub trait Renderer {
async fn prepare(&mut self, main_world: &mut World); fn prepare(&mut self, main_world: &mut edict::World);
async fn render(&mut self) -> Result<(), wgpu::SurfaceError>; fn render(&mut self) -> Result<(), wgpu::SurfaceError>;
async fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>); fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>);
fn surface_size(&self) -> winit::dpi::PhysicalSize<u32>; fn surface_size(&self) -> winit::dpi::PhysicalSize<u32>;
fn add_render_pipeline(&mut self, shader_id: u32, pipeline: Arc<FullRenderPipeline>); fn add_render_pipeline(&mut self, shader_id: u32, pipeline: Arc<FullRenderPipeline>);
@ -57,7 +55,7 @@ pub struct BasicRenderer {
pub render_pipelines: HashMap<u32, Arc<FullRenderPipeline>>, pub render_pipelines: HashMap<u32, Arc<FullRenderPipeline>>,
pub render_jobs: VecDeque<RenderJob>, pub render_jobs: VecDeque<RenderJob>,
buffer_storage: HashMap<Entity, RenderBufferStorage>, // TODO: clean up left over buffers from deleted entities/components buffer_storage: HashMap<EntityId, RenderBufferStorage>, // TODO: clean up left over buffers from deleted entities/components
transform_buffer: wgpu::Buffer, transform_buffer: wgpu::Buffer,
transform_bind_group: wgpu::BindGroup, transform_bind_group: wgpu::BindGroup,
@ -346,10 +344,10 @@ impl BasicRenderer {
} }
} }
#[async_trait]
impl Renderer for BasicRenderer { impl Renderer for BasicRenderer {
async fn prepare(&mut self, main_world: &mut World) { fn prepare(&mut self, main_world: &mut edict::World) {
for (entity, (model, transform)) in main_world.query::<(&MeshComponent, &TransformComponent)>().iter() {
for (entity, model, transform) in main_world.query::<(Entities, &MeshComponent, &TransformComponent)>().iter() {
// Create the render job and push it to the queue // Create the render job and push it to the queue
let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity, transform.transform, None); let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity, transform.transform, None);
self.render_jobs.push_back(job); self.render_jobs.push_back(job);
@ -360,8 +358,7 @@ impl Renderer for BasicRenderer {
} }
} }
// Find the active camera if let Some(camera) = main_world.query_mut::<(&mut CameraComponent,)>().into_iter().next() {
if let Some((_e, (camera,))) = main_world.query_mut::<(&mut CameraComponent,)>().into_iter().next() {
let view_proj = self.inuse_camera.update_view_projection(camera); let view_proj = self.inuse_camera.update_view_projection(camera);
self.queue.write_buffer(&self.camera_buffer, 0, bytemuck::cast_slice(&[view_proj.clone()])); self.queue.write_buffer(&self.camera_buffer, 0, bytemuck::cast_slice(&[view_proj.clone()]));
} else { } else {
@ -369,7 +366,7 @@ impl Renderer for BasicRenderer {
} }
} }
async fn render(&mut self) -> Result<(), wgpu::SurfaceError> { fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
let output = self.surface.get_current_texture()?; let output = self.surface.get_current_texture()?;
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default()); let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
@ -434,7 +431,7 @@ impl Renderer for BasicRenderer {
Ok(()) Ok(())
} }
async fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) { fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
if new_size.width > 0 && new_size.height > 0 { if new_size.width > 0 && new_size.height > 0 {
self.size = new_size; self.size = new_size;
self.config.width = new_size.width; self.config.width = new_size.width;