Switch ecs to edict #1
|
@ -264,6 +264,12 @@ version = "1.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
|
||||
|
||||
[[package]]
|
||||
name = "atomicell"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "157342dd84c64f16899b4b16c1fb2cce54b887990362aac3c590b3d13810890f"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
|
@ -534,6 +540,42 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
|
@ -1036,8 +1078,10 @@ dependencies = [
|
|||
"anyhow",
|
||||
"async-std",
|
||||
"async-trait",
|
||||
"atomicell",
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"edict",
|
||||
"gilrs-core",
|
||||
"glam",
|
||||
"hecs",
|
||||
|
@ -1492,6 +1536,17 @@ dependencies = [
|
|||
"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]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.3.1"
|
||||
|
@ -1780,6 +1835,12 @@ dependencies = [
|
|||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-fn"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af7b2c33e09916c65a15c92c1e583946052527e06102689ed11c6125f64fa8ba"
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.8.4"
|
||||
|
|
|
@ -27,3 +27,5 @@ petgraph = "0.6.3"
|
|||
gilrs-core = "0.5.6"
|
||||
syn = "2.0.26"
|
||||
quote = "1.0.29"
|
||||
edict = "0.5.0"
|
||||
atomicell = "0.1.9"
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use edict::Component;
|
||||
use winit::dpi::PhysicalSize;
|
||||
|
||||
use crate::{math::{Angle, OPENGL_TO_WGPU_MATRIX, Transform}, render::camera::CameraProjectionMode};
|
||||
|
||||
#[derive(Clone, Component)]
|
||||
pub struct CameraComponent {
|
||||
pub transform: Transform,
|
||||
pub fov: Angle,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use edict::Component;
|
||||
|
||||
use crate::render::{vertex::Vertex, mesh::Mesh, material::Material};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Component)]
|
||||
pub struct MeshComponent {
|
||||
pub mesh: Mesh,
|
||||
pub material: Material,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use edict::Component;
|
||||
|
||||
use crate::math::Transform;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Component)]
|
||||
pub struct TransformComponent {
|
||||
pub transform: Transform,
|
||||
}
|
||||
|
|
|
@ -6,11 +6,8 @@ use tracing::warn;
|
|||
use crate::game::Controls;
|
||||
|
||||
pub mod components;
|
||||
pub mod world;
|
||||
pub mod resources;
|
||||
|
||||
use world::World;
|
||||
|
||||
/// A trait that represents a simple system
|
||||
pub trait SimpleSystem {
|
||||
fn setup(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
|
||||
|
@ -22,7 +19,7 @@ pub trait SimpleSystem {
|
|||
}
|
||||
|
||||
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<()> {
|
||||
self(controls.world)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +1,6 @@
|
|||
use std::{collections::VecDeque, ops::{Deref, DerefMut}};
|
||||
|
||||
use super::Resource;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
pub trait Event: Clone + Send + Sync + 'static {}
|
||||
impl<T: Clone + Send + Sync + 'static> Event for T {}
|
||||
|
||||
#[derive(Clone)]
|
||||
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,
|
||||
}
|
||||
pub type Events<T> = VecDeque<T>;
|
|
@ -8,22 +8,16 @@ pub use window_state::*;
|
|||
pub mod 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_mut(&mut self) -> &mut dyn Any;
|
||||
}
|
||||
|
||||
impl Resource for WindowEvent<'static> {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sync + Send + 'static> Resource for VecDeque<T> {
|
||||
/// Implements this trait for anything that fits the type bounds
|
||||
impl<T: Send + Sync + 'static> CastableAny for T {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::any::Any;
|
||||
|
||||
use super::Resource;
|
||||
use super::CastableAny;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct WindowState {
|
||||
|
@ -13,13 +13,3 @@ impl WindowState {
|
|||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl Resource for WindowState {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
185
src/ecs/world.rs
185
src/ecs/world.rs
|
@ -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())
|
||||
})
|
||||
}
|
||||
}
|
50
src/game.rs
50
src/game.rs
|
@ -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};
|
||||
|
||||
|
@ -13,10 +13,10 @@ use tracing_subscriber::{
|
|||
|
||||
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 world: &'a mut World,
|
||||
pub world: &'a mut edict::World,
|
||||
}
|
||||
|
||||
struct TickCounter {
|
||||
|
@ -78,7 +78,7 @@ struct GameLoop {
|
|||
window: Arc<Window>,
|
||||
renderer: Box<dyn Renderer>,
|
||||
|
||||
world: Arc<Mutex<World>>,
|
||||
world: Arc<Mutex<edict::World>>,
|
||||
/// higher priority systems
|
||||
engine_sys_dispatcher: SystemDispatcher,
|
||||
user_sys_dispatcher: SystemDispatcher,
|
||||
|
@ -86,7 +86,13 @@ struct 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 {
|
||||
window: Arc::clone(&window),
|
||||
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>) {
|
||||
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) {
|
||||
|
@ -142,7 +148,7 @@ impl GameLoop {
|
|||
InputEvent::CursorEntered { .. } => {
|
||||
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;
|
||||
|
||||
None
|
||||
|
@ -151,7 +157,7 @@ impl GameLoop {
|
|||
InputEvent::CursorLeft { .. } => {
|
||||
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;
|
||||
|
||||
None
|
||||
|
@ -186,14 +192,13 @@ impl GameLoop {
|
|||
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
|
||||
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,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if trigger {
|
||||
let mut event_queue = world.query_or_insert_res::<Events<InputEvent>>
|
||||
(|| Box::new(RefCell::new(Events::<InputEvent>::new())));
|
||||
let event_queue = world.with_resource(|| Events::<InputEvent>::new());
|
||||
|
||||
let input_event = InputEvent::MouseMotion { device_id, delta, };
|
||||
event_queue.push_back(input_event);
|
||||
|
@ -212,8 +217,10 @@ impl GameLoop {
|
|||
// 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.
|
||||
{
|
||||
let mut world = self.world.lock().await;
|
||||
world.trigger_event(input_event.clone());
|
||||
let world = self.world.lock().await;
|
||||
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 {
|
||||
|
@ -238,7 +245,7 @@ impl GameLoop {
|
|||
WindowEvent::Focused(is_focused) => {
|
||||
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;
|
||||
},
|
||||
|
||||
|
@ -257,12 +264,13 @@ impl GameLoop {
|
|||
} */
|
||||
|
||||
let mut world = self.world.lock().await;
|
||||
self.renderer.as_mut().prepare(&mut world).await;
|
||||
world.clear_updated_resources();
|
||||
world.update_events();
|
||||
self.renderer.as_mut().prepare(&mut world);
|
||||
if let Some(mut event_queue) = world.get_resource_mut::<EventQueue>() {
|
||||
event_queue.update_events();
|
||||
}
|
||||
drop(world);
|
||||
|
||||
match self.renderer.as_mut().render().await {
|
||||
match self.renderer.as_mut().render() {
|
||||
Ok(_) => {}
|
||||
// Reconfigure the surface if lost
|
||||
Err(wgpu::SurfaceError::Lost) => self.on_resize(self.renderer.as_ref().surface_size()).await,
|
||||
|
@ -282,7 +290,7 @@ impl GameLoop {
|
|||
}
|
||||
|
||||
pub struct Game {
|
||||
world: Option<Arc<Mutex<World>>>,
|
||||
world: Option<Arc<Mutex<edict::World>>>,
|
||||
system_dispatcher: Option<SystemDispatcher>
|
||||
}
|
||||
|
||||
|
@ -312,13 +320,13 @@ impl Game {
|
|||
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
|
||||
}
|
||||
|
||||
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
|
||||
|
|
76
src/input.rs
76
src/input.rs
|
@ -5,7 +5,7 @@ use glam::Vec2;
|
|||
use tracing::{warn, debug};
|
||||
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;
|
||||
|
||||
|
@ -100,16 +100,6 @@ pub struct Touches {
|
|||
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 {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
|
@ -152,16 +142,6 @@ pub struct InputButtons<T: Clone + Hash + Eq + PartialEq + 'static> {
|
|||
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> {
|
||||
pub fn new() -> 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 {
|
||||
InputEvent::KeyboardInput { input, .. } => {
|
||||
if let Some(code) = input.virtual_keycode {
|
||||
let mut e = world.query_or_insert_res::<InputButtons<KeyCode>>
|
||||
(|| Box::new(RefCell::new(InputButtons::<KeyCode>::new())));
|
||||
drop(event_queue);
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
@ -293,22 +280,22 @@ impl InputEventUpdater {
|
|||
delta: Vec2::new(delta.0 as f32, delta.1 as f32)
|
||||
};
|
||||
|
||||
world.trigger_event(delta);
|
||||
event_queue.trigger_event(delta);
|
||||
},
|
||||
InputEvent::CursorMoved { position, .. } => {
|
||||
let exact = MouseExact {
|
||||
pos: Vec2::new(position.x as f32, position.y as f32)
|
||||
};
|
||||
|
||||
world.trigger_event(exact);
|
||||
event_queue.trigger_event(exact);
|
||||
},
|
||||
InputEvent::CursorEntered { .. } => {
|
||||
let event = CursorEnteredWindow {};
|
||||
world.trigger_event(event);
|
||||
event_queue.trigger_event(event);
|
||||
},
|
||||
InputEvent::CursorLeft { .. } => {
|
||||
let event = CursorLeftWindow {};
|
||||
world.trigger_event(event);
|
||||
event_queue.trigger_event(event);
|
||||
},
|
||||
InputEvent::MouseWheel { delta, .. } => {
|
||||
let event = match delta {
|
||||
|
@ -320,7 +307,7 @@ impl InputEventUpdater {
|
|||
},
|
||||
};
|
||||
|
||||
world.trigger_event(event);
|
||||
event_queue.trigger_event(event);
|
||||
}, //MouseButton
|
||||
InputEvent::MouseInput { button, state, .. } => {
|
||||
let button_event = match button {
|
||||
|
@ -330,13 +317,15 @@ impl InputEventUpdater {
|
|||
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>>
|
||||
(|| Box::new(RefCell::new(InputButtons::<MouseButton>::new())));
|
||||
let mut e = world.with_resource(|| InputButtons::<MouseButton>::new());
|
||||
e.add_input_from_winit(button_event, state.clone());
|
||||
},
|
||||
InputEvent::Touch(t) => {
|
||||
drop(event_queue);
|
||||
|
||||
let touch = Touch {
|
||||
phase: TouchPhase::from(t.phase),
|
||||
location: Vec2::new(t.location.x as f32, t.location.y as f32),
|
||||
|
@ -347,9 +336,7 @@ impl InputEventUpdater {
|
|||
finger_id: t.id,
|
||||
};
|
||||
|
||||
let mut touches = world.query_or_insert_res::<Touches>
|
||||
(|| Box::new(RefCell::new(Touches::new())));
|
||||
|
||||
let mut touches = world.with_resource(|| Touches::new());
|
||||
touches.touches.push(touch);
|
||||
},
|
||||
_ => {},
|
||||
|
@ -363,32 +350,19 @@ impl SimpleSystem for InputEventUpdater {
|
|||
fn execute_mut(&mut self, controls: &mut crate::game::Controls) -> anyhow::Result<()> {
|
||||
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() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let queue = queue.unwrap();
|
||||
|
||||
// borrow checker isn't happy when I query multiple things :(
|
||||
let mut events = queue.clone();
|
||||
drop(queue);
|
||||
let mut events = queue.unwrap();
|
||||
|
||||
while let Some(event) = events.pop_front() {
|
||||
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(())
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
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.
|
||||
///
|
||||
|
@ -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
|
||||
}
|
||||
}
|
26
src/main.rs
26
src/main.rs
|
@ -6,16 +6,15 @@ mod ecs;
|
|||
mod math;
|
||||
mod input;
|
||||
|
||||
use std::cell::Ref;
|
||||
|
||||
use atomicell::Ref;
|
||||
use ecs::components::mesh::MeshComponent;
|
||||
|
||||
use ecs::components::transform::TransformComponent;
|
||||
use edict::QueryIter;
|
||||
use game::Game;
|
||||
use input_event::InputEvent;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::ecs::world::World;
|
||||
use crate::input::{InputEventUpdater, KeyCode, MouseMotion, MouseExact, CursorEnteredWindow, MouseScroll, CursorLeftWindow, MouseButton, InputButtons};
|
||||
use crate::render::material::Material;
|
||||
use crate::render::texture::Texture;
|
||||
|
@ -68,7 +67,7 @@ impl Point3d {
|
|||
|
||||
#[async_std::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)));
|
||||
|
||||
|
@ -91,10 +90,8 @@ async fn main() {
|
|||
camera.transform.rotate_z(Angle::Degrees(-90.0));
|
||||
world.spawn((camera,));
|
||||
|
||||
let jiggle_system = |world: &mut World| -> anyhow::Result<()> {
|
||||
//let input: &InputEventUpdater = world.query_res().unwrap();
|
||||
|
||||
let keys = world.query_res();
|
||||
let jiggle_system = |world: &mut edict::World| -> anyhow::Result<()> {
|
||||
let keys = world.get_resource();
|
||||
if keys.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -124,7 +121,16 @@ async fn main() {
|
|||
|
||||
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;
|
||||
|
||||
/* debug!("Translation: {}", t.translation);
|
||||
|
@ -133,7 +139,7 @@ async fn main() {
|
|||
t.translation.x *= -1.0 */
|
||||
t.translation.x += dir_x;
|
||||
t.translation.y += dir_y;
|
||||
}
|
||||
} */
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
|
|
@ -10,6 +10,7 @@ pub fn radians_to_degrees(radians: f32) -> f32 {
|
|||
radians * 180.0 / PI
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Angle {
|
||||
Degrees(f32),
|
||||
Radians(f32),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use hecs::Entity;
|
||||
use edict::EntityId;
|
||||
|
||||
use crate::math::Transform;
|
||||
|
||||
|
@ -7,14 +7,14 @@ use super::{mesh::Mesh, material::Material};
|
|||
pub struct RenderJob {
|
||||
mesh: Mesh,
|
||||
material: Material,
|
||||
entity: Entity,
|
||||
entity: EntityId,
|
||||
|
||||
transform: Transform,
|
||||
last_transform: Option<Transform>, // TODO: render interpolation
|
||||
}
|
||||
|
||||
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 {
|
||||
mesh,
|
||||
material,
|
||||
|
@ -32,7 +32,7 @@ impl RenderJob {
|
|||
&self.material
|
||||
}
|
||||
|
||||
pub fn entity(&self)-> Entity {
|
||||
pub fn entity(&self)-> EntityId {
|
||||
self.entity
|
||||
}
|
||||
|
||||
|
|
|
@ -6,17 +6,16 @@ use std::borrow::Cow;
|
|||
use async_std::sync::Mutex;
|
||||
use async_trait::async_trait;
|
||||
|
||||
use atomicell::{AtomicCell, RefMut};
|
||||
use edict::{EntityId, Entities};
|
||||
use tracing::{debug, warn};
|
||||
use wgpu::{BindGroup, BindGroupLayout};
|
||||
use wgpu::util::DeviceExt;
|
||||
use winit::window::Window;
|
||||
|
||||
use hecs::Entity;
|
||||
|
||||
use crate::ecs::components::camera::CameraComponent;
|
||||
use crate::ecs::components::mesh::MeshComponent;
|
||||
use crate::ecs::components::transform::TransformComponent;
|
||||
use crate::ecs::world::World;
|
||||
use crate::math::{Transform, Angle};
|
||||
use crate::resources;
|
||||
|
||||
|
@ -25,11 +24,10 @@ use super::desc_buf_lay::DescVertexBufferLayout;
|
|||
use super::texture::RenderTexture;
|
||||
use super::{render_pipeline::FullRenderPipeline, vertex::{VERTICES}, render_buffer::BufferStorage, render_job::RenderJob, mesh::Mesh};
|
||||
|
||||
#[async_trait]
|
||||
pub trait Renderer {
|
||||
async fn prepare(&mut self, main_world: &mut World);
|
||||
async fn render(&mut self) -> Result<(), wgpu::SurfaceError>;
|
||||
async fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>);
|
||||
fn prepare(&mut self, main_world: &mut edict::World);
|
||||
fn render(&mut self) -> Result<(), wgpu::SurfaceError>;
|
||||
fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>);
|
||||
|
||||
fn surface_size(&self) -> winit::dpi::PhysicalSize<u32>;
|
||||
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_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_bind_group: wgpu::BindGroup,
|
||||
|
@ -346,10 +344,10 @@ impl BasicRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Renderer for BasicRenderer {
|
||||
async fn prepare(&mut self, main_world: &mut World) {
|
||||
for (entity, (model, transform)) in main_world.query::<(&MeshComponent, &TransformComponent)>().iter() {
|
||||
fn prepare(&mut self, main_world: &mut edict::World) {
|
||||
|
||||
for (entity, model, transform) in main_world.query::<(Entities, &MeshComponent, &TransformComponent)>().iter() {
|
||||
// Create the render job and push it to the queue
|
||||
let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity, transform.transform, None);
|
||||
self.render_jobs.push_back(job);
|
||||
|
@ -360,8 +358,7 @@ impl Renderer for BasicRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
// Find the active camera
|
||||
if let Some((_e, (camera,))) = main_world.query_mut::<(&mut CameraComponent,)>().into_iter().next() {
|
||||
if let Some(camera) = main_world.query_mut::<(&mut CameraComponent,)>().into_iter().next() {
|
||||
let view_proj = self.inuse_camera.update_view_projection(camera);
|
||||
self.queue.write_buffer(&self.camera_buffer, 0, bytemuck::cast_slice(&[view_proj.clone()]));
|
||||
} 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 view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
|
@ -434,7 +431,7 @@ impl Renderer for BasicRenderer {
|
|||
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 {
|
||||
self.size = new_size;
|
||||
self.config.width = new_size.width;
|
||||
|
|
Loading…
Reference in New Issue