From 1df3b61d66ba7d5d45d041106aaf4c7b9940361f Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 6 Sep 2024 20:24:18 +0200 Subject: [PATCH 1/3] extract `scene` into separate crate --- src/experimental.rs | 1 - src/experimental/coroutines.rs | 94 ---- src/experimental/scene.rs | 711 +----------------------------- src/experimental/state_machine.rs | 205 --------- src/lib.rs | 6 +- src/telemetry.rs | 9 +- src/time.rs | 10 +- tests/coroutine_pause.rs | 75 +--- 8 files changed, 28 insertions(+), 1083 deletions(-) delete mode 100644 src/experimental/state_machine.rs diff --git a/src/experimental.rs b/src/experimental.rs index 22b2770c..a544cdb6 100644 --- a/src/experimental.rs +++ b/src/experimental.rs @@ -7,4 +7,3 @@ pub mod camera; pub mod collections; pub mod coroutines; pub mod scene; -pub mod state_machine; diff --git a/src/experimental/coroutines.rs b/src/experimental/coroutines.rs index c638f3a2..7fd1e9c6 100644 --- a/src/experimental/coroutines.rs +++ b/src/experimental/coroutines.rs @@ -261,97 +261,3 @@ pub fn wait_seconds(time: f32) -> TimerDelayFuture { remaining_time: time, } } - -/// Special built-in coroutines for modifying values over time. -pub mod tweens { - use crate::experimental::scene::{Handle, Lens, Node}; - use std::future::Future; - use std::pin::Pin; - use std::{ - ops::{Add, Mul, Sub}, - task::{Context, Poll}, - }; - - pub struct LinearTweenFuture - where - T: Copy + Add + Sub + Mul, - { - from: T, - to: T, - lens: Lens, - start_time: f64, - time: f32, - } - impl Unpin for LinearTweenFuture where - T: Copy + Add + Sub + Mul - { - } - - impl Future for LinearTweenFuture - where - T: Copy + Add + Sub + Mul, - { - type Output = (); - - fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll { - let t = (miniquad::date::now() - self.start_time) / self.time as f64; - let this = self.get_mut(); - let var = this.lens.get(); - - // node with value was deleted - if var.is_none() { - return Poll::Ready(()); - } - let var = var.unwrap(); - - if t <= 1. { - *var = this.from + (this.to - this.from) * t as f32; - - Poll::Pending - } else { - *var = this.to; - - Poll::Ready(()) - } - } - } - - pub fn linear( - handle: Handle, - lens: F, - from: T, - to: T, - time: f32, - ) -> LinearTweenFuture - where - T: Copy + Add + Sub + Mul, - T1: Node, - F: for<'r> FnMut(&'r mut T1) -> &'r mut T, - { - LinearTweenFuture { - to, - from, - lens: handle.lens(lens), - time, - start_time: miniquad::date::now(), - } - } - - pub async fn follow_path(handle: Handle, mut lens: F, path: Vec, time: f32) - where - T: Copy + Add + Sub + Mul, - T1: Node, - F: for<'r> FnMut(&'r mut T1) -> &'r mut T, - { - for point in path.windows(2) { - linear( - handle, - &mut lens, - point[0], - point[1], - time / path.len() as f32, - ) - .await - } - } -} diff --git a/src/experimental/scene.rs b/src/experimental/scene.rs index bf3e34a2..a2463d59 100644 --- a/src/experimental/scene.rs +++ b/src/experimental/scene.rs @@ -1,705 +1,14 @@ -use std::{any::Any, marker::PhantomData, ops::Drop}; +use crate::get_context; -use crate::camera::Camera2D; - -pub use macroquad_macro::CapabilityTrait; - -mod arena; - -#[rustfmt::skip] -pub trait Node { - fn ready(_node: RefMut) where Self: Sized {} - fn update(_node: RefMut) where Self: Sized {} - fn fixed_update(_node: RefMut) where Self: Sized {} - fn draw(_node: RefMut) where Self: Sized {} -} - -trait NodeAny: Any + Node { - fn as_any(&self) -> &dyn Any; - fn as_any_mut(&mut self) -> &mut dyn Any; -} - -impl NodeAny for T { - fn as_any(&self) -> &dyn Any { - self - } - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - -#[derive(Clone, Copy, Debug, PartialEq)] -struct Id { - id: usize, - generation: u64, -} - -pub struct Handle { - id: Option, - _marker: PhantomData, -} - -unsafe impl Send for Handle {} - -#[derive(Clone, Copy, Debug)] -pub struct HandleUntyped(Id); - -impl std::fmt::Debug for Handle { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:?}", self.id)?; - - Ok(()) - } -} - -impl Clone for Handle { - fn clone(&self) -> Handle { - Handle { - id: self.id, - _marker: PhantomData, - } - } -} - -impl Copy for Handle {} - -impl Handle { - pub fn null() -> Handle { - Handle { - id: None, - _marker: PhantomData, - } - } - - pub fn untyped(&self) -> HandleUntyped { - HandleUntyped(self.id.unwrap()) - } - - pub fn as_trait(&self) {} -} - -pub(crate) struct Lens { - handle: HandleUntyped, - offset: isize, - _marker: PhantomData, -} - -impl Lens { - pub fn get(&mut self) -> Option<&mut T> { - let node = get_untyped_node(self.handle)?; - - Some(unsafe { &mut *((node.data as *mut u8).offset(self.offset) as *mut T) }) - } -} - -impl Handle { - pub(crate) fn lens(&self, f: F) -> Lens - where - F: for<'r> FnOnce(&'r mut T) -> &'r mut T1, - { - assert!(self.id.is_some()); - - let offset = unsafe { - let mut base = std::mem::MaybeUninit::::uninit(); - let field = f(std::mem::transmute(base.as_mut_ptr())) as *mut _ as *mut u8; - - (field as *mut u8).offset_from(base.as_mut_ptr() as *mut u8) - }; - - Lens { - handle: HandleUntyped(self.id.unwrap()), - offset, - _marker: PhantomData, - } - } -} - -pub struct NodeWith { - pub node: HandleUntyped, - pub capability: T, -} - -pub struct RefMut { - data: *mut T, - handle: Handle, - capabilities: *mut Vec>, - used: *mut bool, -} - -impl RefMut { - pub fn handle(&self) -> Handle { - Handle { - id: self.handle.id, - _marker: PhantomData, - } - } - - pub fn persist(&self) { - unsafe { get_scene() }.nodes[self.handle.id.unwrap().id] - .as_mut() - .unwrap() - .permanent = true; - } - - pub fn provides(&mut self, x: S) { - unsafe { (*self.capabilities).push(Box::new(x)) }; - } - - pub fn delete(self) { - assert!(self.handle.id.is_some()); - - unsafe { - *self.used = false; - } - unsafe { get_scene() }.delete(self.handle.id.unwrap()); - std::mem::forget(self); - } -} - -impl std::ops::Deref for RefMut { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.data } - } -} - -impl std::ops::DerefMut for RefMut { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.data } - } -} - -impl Drop for RefMut { - fn drop(&mut self) { - assert_eq!(unsafe { *self.used }, true); - unsafe { - *self.used = false; - } - } -} - -pub struct RefMutAny<'a> { - data: *mut (), - used: *mut bool, - vtable: *mut (), - capabilities: *mut Vec>, - handle: HandleUntyped, - - _marker: PhantomData<&'a ()>, -} - -impl<'a> RefMutAny<'a> { - pub fn handle(&self) -> Handle { - Handle { - id: Some(self.handle.0), - _marker: PhantomData, - } - } - - pub fn delete(self) { - unsafe { - *self.used = false; - } - unsafe { get_scene() }.delete(self.handle.0); - std::mem::forget(self); - } - - pub fn to_typed(self) -> RefMut { - let res = RefMut { - data: self.data as *mut T, - handle: Handle { - id: Some(self.handle.0), - _marker: PhantomData::, - }, - capabilities: self.capabilities, - used: self.used, - }; - - // "used" is now moved to RefMut and will be invalidated by RefMut's drop - // no need for RefMutAny's drop than - std::mem::forget(self); - - res - } -} - -impl<'a> std::ops::Deref for RefMutAny<'a> { - type Target = dyn Any; - - fn deref(&self) -> &Self::Target { - let trait_obj: &dyn NodeAny = unsafe { std::mem::transmute((self.data, self.vtable)) }; - - trait_obj.as_any() - } -} - -impl<'a> std::ops::DerefMut for RefMutAny<'a> { - fn deref_mut(&mut self) -> &mut dyn Any { - let trait_obj: &mut dyn NodeAny = unsafe { std::mem::transmute((self.data, self.vtable)) }; - - trait_obj.as_any_mut() - } -} - -impl<'a> Drop for RefMutAny<'a> { - fn drop(&mut self) { - assert_eq!(unsafe { *self.used }, true); - - unsafe { - *self.used = false; - } - } -} - -struct Cell { - id: Id, - data: *mut (), - vtable: *mut (), - capabilities: Vec>, - ready: *const fn(RefMut<()>), - update: *const fn(RefMut<()>), - fixed_update: *const fn(RefMut<()>), - draw: *const fn(RefMut<()>), - virtual_drop: *const fn(*mut ()), - data_len: usize, - permanent: bool, - initialized: bool, - used: *mut bool, -} - -unsafe impl Sync for Scene {} - -fn virtual_drop(data: *mut ()) { - unsafe { - std::ptr::drop_in_place(data as *mut T); - } -} - -impl Cell { - fn new(id: Id, data: *mut (), vtable: *mut (), used: *mut bool) -> Self { - Cell { - id, - data, - vtable, - capabilities: vec![], - used, - permanent: false, - ready: unsafe { - std::mem::transmute(&(Node::ready as fn(RefMut)) as *const fn(RefMut)) - }, - update: unsafe { - std::mem::transmute(&(Node::update as fn(RefMut)) as *const fn(RefMut)) - }, - fixed_update: unsafe { - std::mem::transmute(&(Node::fixed_update as fn(RefMut)) as *const fn(RefMut)) - }, - draw: unsafe { - std::mem::transmute(&(Node::draw as fn(RefMut)) as *const fn(RefMut)) - }, - virtual_drop: unsafe { - std::mem::transmute(&(virtual_drop:: as fn(*mut ())) as *const fn(*mut ())) - }, - data_len: std::mem::size_of::(), - initialized: false, - } - } - - fn update(&mut self, data: T) { - assert!(std::mem::size_of::() <= self.data_len); - - let trait_obj = &data as &dyn NodeAny; - let (_, vtable) = unsafe { std::mem::transmute::<_, (*mut (), *mut ())>(trait_obj) }; - - self.vtable = vtable; - self.ready = - unsafe { std::mem::transmute(&(Node::ready as fn(RefMut)) as *const fn(RefMut)) }; - self.update = unsafe { - std::mem::transmute(&(Node::update as fn(RefMut)) as *const fn(RefMut)) - }; - self.fixed_update = unsafe { - std::mem::transmute(&(Node::fixed_update as fn(RefMut)) as *const fn(RefMut)) - }; - self.draw = - unsafe { std::mem::transmute(&(Node::draw as fn(RefMut)) as *const fn(RefMut)) }; - self.virtual_drop = unsafe { - std::mem::transmute(&(virtual_drop:: as fn(*mut ())) as *const fn(*mut ())) - }; - - unsafe { - std::ptr::copy_nonoverlapping::(&data as *const _ as *mut _, self.data as *mut _, 1); - } - self.id.generation += 1; - self.initialized = false; - self.permanent = false; - - self.capabilities.clear(); - - std::mem::forget(data); - } -} - -struct Scene { - dense: Vec, - dense_ongoing: Vec>, - nodes: Vec>, - arena: arena::Arena, - camera: [Option; 4], - camera_pos: crate::Vec2, - - acc: f64, - current_time: f64, - in_fixed_update: bool, - - any_map: std::collections::HashMap>, - free_nodes: Vec, -} - -impl Scene { - pub fn new() -> Self { - Scene { - dense: vec![], - dense_ongoing: vec![], - nodes: Vec::new(), - arena: arena::Arena::new(), - free_nodes: Vec::new(), - camera: [Some(Camera2D::default()), None, None, None], - camera_pos: crate::vec2(0., 0.), - acc: 0.0, - current_time: crate::time::get_time(), - in_fixed_update: false, - any_map: std::collections::HashMap::new(), - } - } - - pub fn clear(&mut self) { - self.any_map.clear(); - - for cell in &mut self.nodes { - if let Some(Cell { - permanent: false, .. - }) = cell - { - if let Some(cell) = cell.take() { - assert!(unsafe { *cell.used == false }); - - unsafe { - (*cell.virtual_drop)(cell.data); - } - let ix = self.dense.iter().position(|i| *i == cell.id).unwrap(); - self.dense.remove(ix); - - self.free_nodes.push(cell); - } - } - } - } - - pub fn get_any(&mut self, handle: HandleUntyped) -> Option { - let handle = handle.0; - let cell = self.nodes.get_mut(handle.id)?; - - if cell.is_none() { - return None; - } - let cell = cell.as_mut().unwrap(); - - if cell.id.generation != handle.generation { - return None; - } - - if unsafe { *cell.used } { - return None; - } - - unsafe { *cell.used = true }; - - Some(RefMutAny { - data: cell.data, - vtable: cell.vtable, - capabilities: &mut cell.capabilities as _, - handle: HandleUntyped(cell.id), - used: cell.used, - - _marker: PhantomData, - }) - } - - pub fn get(&mut self, handle: Handle) -> Option> { - if handle.id.is_none() { - return None; - } - let ref_mut_any = self.get_any(HandleUntyped(handle.id.unwrap()))?; - Some(ref_mut_any.to_typed()) - } - - fn iter(&self) -> MagicVecIterator { - MagicVecIterator { - n: 0, - len: self.dense.len(), - } - } - - fn add_node(&mut self, data: T) -> Handle { - let id; - - if let Some(i) = self - .free_nodes - .iter() - .position(|free_node| free_node.data_len >= std::mem::size_of::()) - { - let mut free_node = self.free_nodes.remove(i); - - free_node.update::(data); - - id = free_node.id; - - self.nodes[id.id] = Some(free_node); - } else { - let trait_obj = &data as &dyn NodeAny; - let (_, vtable) = unsafe { std::mem::transmute::<_, (*mut (), *mut ())>(trait_obj) }; - - let ptr = self.arena.alloc(std::mem::size_of::()) as *mut _ as *mut T; - unsafe { - std::ptr::write(ptr, data); - } - let ptr = ptr as *mut (); - let used = self.arena.alloc(1) as *mut _ as *mut bool; - unsafe { - std::ptr::write(used, false); - } - let used = used as *mut _ as *mut bool; - - id = Id { - id: self.nodes.len(), - generation: 0, - }; - self.nodes.push(Some(Cell::new::(id, ptr, vtable, used))); - } - - self.dense.push(id); - - Handle { - id: Some(id), - _marker: PhantomData, - } - } - - pub fn delete(&mut self, id: Id) { - if let Some(node) = self.nodes[id.id].take() { - assert_eq!(node.id.generation, id.generation); - - self.dense_ongoing.push(Err(id)); - - unsafe { - (*node.virtual_drop)(node.data); - } - self.free_nodes.push(node); - } - } - - pub fn update(&mut self) { - for node in &mut self.iter() { - let cell = self.nodes[node.handle.0.id].as_mut().unwrap(); - if cell.initialized == false { - cell.initialized = true; - - let node: RefMut<()> = node.to_typed::<()>(); - unsafe { (*cell.ready)(node) }; - } - } - - let new_time = crate::time::get_time(); - - let mut frame_time = new_time - self.current_time; - - // https://medium.com/@tglaiel/how-to-make-your-game-run-at-60fps-24c61210fe75x - if (frame_time - 1.0 / 120.0).abs() < 0.0002 { - frame_time = 1.0 / 120.0; - } else if (frame_time - 1.0 / 60.0).abs() < 0.0002 { - frame_time = 1.0 / 60.0; - } else if (frame_time - 1.0 / 30.0).abs() < 0.0002 { - frame_time = 1.0 / 30.0; - } - - self.current_time = new_time; - self.acc += frame_time; - - for node in &mut self.iter() { - let cell = self.nodes[node.handle.0.id].as_mut().unwrap(); - let node: RefMut<()> = node.to_typed::<()>(); - unsafe { (*cell.update)(node) }; - } - - while self.acc > CONST_FPS { - self.acc -= CONST_FPS; - for node in &mut self.iter() { - let cell = self.nodes[node.handle.0.id].as_mut().unwrap(); - let node: RefMut<()> = node.to_typed::<()>(); - - self.in_fixed_update = true; - unsafe { (*cell.fixed_update)(node) }; - self.in_fixed_update = false; - } - } - - for camera in self.camera.iter() { - if let Some(camera) = camera { - self.camera_pos = camera.target; - crate::prelude::push_camera_state(); - crate::prelude::set_camera(&*camera); - - for node in &mut self.iter() { - let cell = self.nodes[node.handle.0.id].as_mut().unwrap(); - let node: RefMut<()> = node.to_typed::<()>(); - unsafe { (*cell.draw)(node) }; - } - - crate::prelude::pop_camera_state(); - } - } - - for id in self.dense_ongoing.drain(0..) { - match id { - Ok(id) => { - self.dense.push(id); - } - Err(id) => { - let ix = self.dense.iter().position(|i| *i == id).unwrap(); - self.dense.remove(ix); - } - } - } - } -} - -pub struct MagicVecIterator { - n: usize, - len: usize, -} - -impl Iterator for MagicVecIterator { - type Item = RefMutAny<'static>; - - fn next(&mut self) -> Option> { - let scene = unsafe { get_scene() }; - let nodes = &mut scene.nodes; - let dense = &scene.dense; - if self.n >= self.len { - return None; - } - let ix = dense[self.n]; - let cell = &mut nodes[ix.id]; - self.n += 1; - - if cell.is_none() { - return self.next(); - } - let cell = cell.as_mut().unwrap(); - - if unsafe { *cell.used } { - return self.next(); - } - - unsafe { *cell.used = true }; - - Some(RefMutAny { - data: cell.data, - vtable: cell.vtable, - capabilities: &mut cell.capabilities as _, - handle: HandleUntyped(cell.id), - used: cell.used, - _marker: PhantomData, - }) - } -} - -static mut SCENE: Option = None; - -unsafe fn get_scene() -> &'static mut Scene { - SCENE.get_or_insert(Scene::new()) -} - -pub(crate) fn allocated_memory() -> usize { - unsafe { get_scene().arena.offset() } -} - -pub fn clear() { - crate::experimental::coroutines::stop_all_coroutines(); - - unsafe { get_scene() }.clear() -} - -/// Get node and panic if the node is borrowed or deleted -pub fn get_node(handle: Handle) -> RefMut { - unsafe { get_scene() } - .get(handle) - .expect(&format!("No such node: {:?}", handle.id)) -} - -pub fn try_get_node(handle: Handle) -> Option> { - unsafe { get_scene() }.get(handle) -} - -pub fn get_untyped_node(handle: HandleUntyped) -> Option> { - unsafe { get_scene() }.get_any(handle) -} - -pub fn camera_pos() -> crate::Vec2 { - unsafe { get_scene() }.camera_pos -} - -pub fn set_camera(n: usize, camera: Option) { - assert!(n <= 4); - unsafe { get_scene() }.camera[n] = camera; -} - -pub fn add_node(node: T) -> Handle { - unsafe { get_scene() }.add_node(node) -} - -pub(crate) fn update() { - unsafe { get_scene() }.update() -} - -pub fn all_nodes() -> MagicVecIterator { - unsafe { get_scene() }.iter() -} - -pub fn find_node_by_type() -> Option> { - unsafe { get_scene() } - .iter() - .find(|node| node.is::()) - .map(|node| node.to_typed()) -} - -pub fn find_nodes_with() -> impl Iterator> { - unsafe { - get_scene().iter().filter_map(|node| { - (*node.capabilities) - .iter() - .find(|capability| capability.is::()) - .map(|capability| NodeWith { - node: node.handle, - capability: *capability.downcast_ref::().unwrap(), - }) - }) - } -} - -pub fn find_nodes_by_type() -> impl Iterator> { - unsafe { get_scene() } - .iter() - .filter(|node| node.is::()) - .map(|node| node.to_typed()) -} - -const CONST_FPS: f64 = 1.0 / 60.; - -pub(crate) fn in_fixed_update() -> bool { - unsafe { get_scene() }.in_fixed_update +// somewhat hacky workaround to keep everything else working +pub struct SceneHandler { + pub update: fn(), + pub in_fixed_update: fn() -> bool, + pub fixed_frame_time: fn() -> f32, + pub allocated_memory: fn() -> usize, } -pub(crate) fn fixed_frame_time() -> f32 { - CONST_FPS as _ +pub fn register_handler(handler: SceneHandler) { + let context = get_context(); + context.scene_handler = Some(handler); } diff --git a/src/experimental/state_machine.rs b/src/experimental/state_machine.rs deleted file mode 100644 index fe1f8e40..00000000 --- a/src/experimental/state_machine.rs +++ /dev/null @@ -1,205 +0,0 @@ -use crate::experimental::coroutines::Coroutine; - -use crate::experimental::scene; - -type UpdateFn = Box, f32)>; -type CoroutineFn = Box) -> Coroutine>; -type OnEndFn = Box)>; - -pub struct State { - update: Option>, - coroutine: Option>, - on_end: Option>, -} - -impl State { - pub fn new() -> Self { - State { - update: None, - coroutine: None, - on_end: None, - } - } - - pub fn update(self, update: impl FnMut(&mut scene::RefMut, f32) + 'static) -> Self { - State { - update: Some(Box::new(update)), - ..self - } - } - - pub fn coroutine( - self, - coroutine: impl FnMut(&mut scene::RefMut) -> Coroutine + 'static, - ) -> Self { - State { - coroutine: Some(Box::new(coroutine)), - ..self - } - } - - pub fn on_end(self, on_end: impl FnMut(&mut scene::RefMut) + 'static) -> Self { - State { - on_end: Some(Box::new(on_end)), - ..self - } - } -} - -pub enum StateMachine { - Ready(StateMachineOwned), - InUse { - next_state: Option, - current_state: usize, - }, -} - -impl StateMachine { - pub fn new() -> StateMachine { - StateMachine::Ready(StateMachineOwned::new()) - } - - pub fn add_state(&mut self, id: usize, state: State) { - match self { - StateMachine::Ready(state_machine) => state_machine.insert(id, state), - _ => panic!(), - } - } - - pub fn take(&mut self) -> StateMachineOwned { - let current_state = self.state(); - match std::mem::replace( - self, - StateMachine::InUse { - next_state: None, - current_state, - }, - ) { - StateMachine::InUse { .. } => panic!(), - StateMachine::Ready(state_machine) => state_machine, - } - } - - fn put_back(&mut self, mut state_machine: StateMachineOwned) { - match self { - StateMachine::Ready(_) => panic!(), - StateMachine::InUse { next_state, .. } => { - if let Some(next_state) = next_state { - state_machine.set_state(*next_state); - } - } - } - *self = StateMachine::Ready(state_machine); - } - - pub fn set_state(&mut self, state: usize) { - match self { - StateMachine::Ready(state_machine) => { - state_machine.set_state(state); - } - StateMachine::InUse { - ref mut next_state, .. - } => { - *next_state = Some(state); - } - } - } - - pub fn state(&self) -> usize { - match self { - StateMachine::Ready(state_machine) => state_machine.state(), - StateMachine::InUse { - ref current_state, .. - } => *current_state, - } - } - - /// A hack to update a state machine being part of an updating struct - pub fn update_detached<'a, F>(mut t: scene::RefMut, mut f: F) - where - F: FnMut(&mut scene::RefMut) -> &mut StateMachine, - { - let mut state_machine = f(&mut t).take(); - state_machine.update(&mut t, crate::time::get_frame_time()); - - // coroutine may want to access this node by its handle - // but while we have borrowed t to RefMut - it will fail this attempt - // so here we drop t, poll the coroutine and than getting t back by its handle - let handle = t.handle(); - drop(t); - if let Some(ref mut coroutine) = state_machine.active_coroutine { - coroutine.poll(crate::time::get_frame_time() as _); - } - let mut t = crate::experimental::scene::get_node(handle); - - f(&mut t).put_back(state_machine); - } - - pub fn update<'a>(&mut self, t: &'a mut scene::RefMut) { - match self { - StateMachine::Ready(state_machine) => { - state_machine.update(t, crate::time::get_frame_time()) - } - _ => panic!(), - } - } -} - -pub struct StateMachineOwned { - states: Vec>, - active_coroutine: Option, - next_state: Option, - current_state: usize, -} - -impl StateMachineOwned { - const MAX_STATE: usize = 32; - - pub fn new() -> Self { - let mut states = vec![]; - for _ in 0..Self::MAX_STATE { - states.push(State::new()); - } - StateMachineOwned { - states, - active_coroutine: None, - next_state: None, - current_state: 0, - } - } - - pub fn insert(&mut self, id: usize, state: State) { - assert!(id < Self::MAX_STATE); - - self.states[id] = state; - } - - pub fn set_state(&mut self, state: usize) { - self.next_state = Some(state); - } - - pub fn state(&self) -> usize { - self.current_state - } - - fn update(&mut self, player: &mut scene::RefMut, dt: f32) { - if let Some(next_state) = self.next_state { - if next_state != self.current_state { - if let Some(on_end) = &mut self.states[self.current_state].on_end { - on_end(player); - } - if let Some(coroutine) = &mut self.states[next_state].coroutine { - let mut coroutine = coroutine(player); - coroutine.set_manual_poll(); - self.active_coroutine = Some(coroutine); - } - } - self.current_state = next_state; - self.next_state = None; - } - - if let Some(update) = self.states[self.current_state].update.as_mut() { - (update)(player, dt); - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 146b3afb..d68cb3fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,6 +228,7 @@ struct Context { textures: crate::texture::TexturesContext, update_on: conf::UpdateTrigger, + scene_handler: Option, } #[derive(Clone)] @@ -357,6 +358,7 @@ impl Context { default_filter_mode: crate::quad_gl::FilterMode::Linear, textures: crate::texture::TexturesContext::new(), update_on: Default::default(), + scene_handler: None, } } @@ -387,7 +389,9 @@ impl Context { } fn end_frame(&mut self) { - crate::experimental::scene::update(); + if let Some(handler) = &self.scene_handler { + (handler.update)(); + } self.perform_render_passes(); diff --git a/src/telemetry.rs b/src/telemetry.rs index c90eb933..123e2151 100644 --- a/src/telemetry.rs +++ b/src/telemetry.rs @@ -280,9 +280,12 @@ pub struct GpuQuery { } pub fn scene_allocated_memory() -> usize { - use crate::experimental::scene; - - scene::allocated_memory() + let context = get_context(); + if let Some(handler) = &context.scene_handler { + (handler.allocated_memory)() + } else { + 0 + } } /// ```skip diff --git a/src/time.rs b/src/time.rs index cb688f3d..9c8cabd2 100644 --- a/src/time.rs +++ b/src/time.rs @@ -13,11 +13,13 @@ pub fn get_fps() -> i32 { pub fn get_frame_time() -> f32 { let context = get_context(); - if crate::experimental::scene::in_fixed_update() { - crate::experimental::scene::fixed_frame_time() - } else { - context.frame_time as f32 + if let Some(handler) = &context.scene_handler { + if (handler.in_fixed_update)() { + return (handler.fixed_frame_time)(); + } } + + context.frame_time as f32 } /// Returns elapsed wall-clock time in seconds since start diff --git a/tests/coroutine_pause.rs b/tests/coroutine_pause.rs index 23aefb3d..8c6b0c2e 100644 --- a/tests/coroutine_pause.rs +++ b/tests/coroutine_pause.rs @@ -1,10 +1,4 @@ -use macroquad::{ - experimental::{ - coroutines::{start_coroutine, wait_seconds}, - scene, - }, - window::next_frame, -}; +use macroquad::{experimental::coroutines::start_coroutine, window::next_frame}; #[macroquad::test] async fn coroutine_execution_order() { @@ -18,70 +12,3 @@ async fn coroutine_execution_order() { println!("d"); next_frame().await; } - -#[macroquad::test] -async fn coroutine_manual_poll() { - struct Player { - state: i32, - } - impl scene::Node for Player {} - - let player = scene::add_node(Player { state: 0 }); - - let mut coroutine = start_coroutine(async move { - loop { - scene::get_node(player).state += 1; - next_frame().await; - } - }); - - // make sure that coroutine is not yet polled - assert_eq!(scene::get_node(player).state, 0); - - coroutine.set_manual_poll(); - - // still not polled - assert_eq!(scene::get_node(player).state, 0); - - coroutine.poll(0.1); - assert_eq!(scene::get_node(player).state, 1); - - next_frame().await; - next_frame().await; - - // make sure that after main loop's next_frame coroutine was not polled - assert_eq!(scene::get_node(player).state, 1); - - // and that we still can poll - coroutine.poll(0.1); - assert_eq!(scene::get_node(player).state, 2); -} - -#[macroquad::test] -async fn coroutine_manual_poll_delay() { - struct Player { - state: i32, - } - impl scene::Node for Player {} - - let player = scene::add_node(Player { state: 0 }); - - let mut coroutine = start_coroutine(async move { - wait_seconds(1.).await; - scene::get_node(player).state = 1; - }); - - coroutine.set_manual_poll(); - - assert_eq!(scene::get_node(player).state, 0); - - // not 1 second yet, coroutine will have "now": 0.0, "delta": 0.9, (0.0 + 0.9) < 1.0 - coroutine.poll(0.9); - - assert_eq!(scene::get_node(player).state, 0); - - // coroutine will have "now": 0.1, delta: 0.11, (0.9 + 0.11) > 1.0, wait_for_seconds pass - coroutine.poll(0.11); - - assert_eq!(scene::get_node(player).state, 1); -} From 4ccdc8dd9827b2c460f63583e30e93e33c7b0616 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 6 Sep 2024 20:33:30 +0200 Subject: [PATCH 2/3] move hidden `CapabilityTrait` derive macro as well --- macroquad_macro/src/lib.rs | 103 ------------------------------------- 1 file changed, 103 deletions(-) diff --git a/macroquad_macro/src/lib.rs b/macroquad_macro/src/lib.rs index 76b2249b..05e82688 100644 --- a/macroquad_macro/src/lib.rs +++ b/macroquad_macro/src/lib.rs @@ -229,106 +229,3 @@ pub fn test(_attr: TokenStream, item: TokenStream) -> TokenStream { prelude } - -/// Very experimental thing for macroquad::experimantal::scene -/// Maybe will go away in future versions -#[doc(hidden)] -#[proc_macro_derive(CapabilityTrait)] -pub fn capability_trait_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let mut source = input.into_iter().peekable(); - - while let Some(TokenTree::Punct(_)) = source.peek() { - let _ = source.next(); - let _ = next_group(&mut source); - } - assert_eq!("pub", &format!("{}", source.next().unwrap())); - assert_eq!("struct", &format!("{}", source.next().unwrap())); - let struct_name = format!("{}", source.next().unwrap()); - - let mut group = next_group(&mut source) - .unwrap() - .stream() - .into_iter() - .peekable(); - - let mut trait_decl = format!("pub trait {}Trait {{", struct_name); - let mut trait_impl = format!("impl {}Trait for NodeWith<{}> {{", struct_name, struct_name); - - fn next_str(group: &mut Peekable>) -> Option { - group.next().map(|tok| format!("{}", tok)) - } - - loop { - // skip doc comments - while let Some(TokenTree::Punct(_)) = group.peek() { - let _ = group.next(); - let _ = next_group(&mut group); - } - - let _pub = next_str(&mut group); - if _pub.is_none() { - break; - } - assert_eq!("pub", _pub.unwrap()); - let fn_name = next_str(&mut group).unwrap(); - let mut fn_res = "()".to_string(); - assert_eq!(":", &next_str(&mut group).unwrap()); - assert_eq!("fn", &next_str(&mut group).unwrap()); - let fn_args_decl = next_str(&mut group).unwrap(); - let mut fn_args_impl = String::new(); - - let args = fn_args_decl.split(":").collect::>(); - for arg in &args[1..args.len() - 1] { - fn_args_impl.push_str(&format!(", {}", arg.split(", ").last().unwrap())); - } - let p = next_str(&mut group); - match p.as_deref() { - Some("-") => { - assert_eq!(">", next_str(&mut group).unwrap()); - fn_res = next_str(&mut group).unwrap(); - let _ = next_str(&mut group); - } - Some(",") => {} - None => break, - _ => panic!(), - }; - - trait_decl.push_str(&format!( - "fn {} {} -> {};", - fn_name, - fn_args_decl - .replace("node : HandleUntyped", "&self") - .replace("node: HandleUntyped", "&self"), - fn_res - )); - - let args = fn_args_impl - .replace("node : HandleUntyped", "") - .replace("node: HandleUntyped", "") - .replace("(", "") - .replace(")", ""); - - trait_impl.push_str(&format!( - "fn {} {} -> {} {{", - fn_name, - fn_args_decl - .replace("node : HandleUntyped", "&self") - .replace("node: HandleUntyped", "&self"), - fn_res - )); - trait_impl.push_str(&format!( - "(self.capability.{})(self.node {})", - fn_name, args - )); - trait_impl.push_str("}"); - } - trait_decl.push_str("}"); - trait_impl.push_str("}"); - - let res = format!( - "{} -{}", - trait_decl, trait_impl - ); - res.parse().unwrap() -} From c08597b39d19b35e3affae2d0167225362796eb2 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 6 Sep 2024 22:13:19 +0200 Subject: [PATCH 3/3] remove the unneeded `arena` module --- src/experimental/scene/arena.rs | 91 --------------------------------- 1 file changed, 91 deletions(-) delete mode 100644 src/experimental/scene/arena.rs diff --git a/src/experimental/scene/arena.rs b/src/experimental/scene/arena.rs deleted file mode 100644 index b2c042ac..00000000 --- a/src/experimental/scene/arena.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! Gleaned from https://github.com/ratel-rust/toolshed/blob/master/src/arena.rs -//! and than modified a lot. -//! -//! Module containing the `Arena` and `Uninitialized` structs. For convenience the -//! `Arena` is exported at the root of the crate. - -use std::cell::Cell; -use std::mem::size_of; - -const ARENA_BLOCK: usize = 64 * 1024; - -/// An arena implementation that uses preallocated 64KiB pages for all allocations. -/// If a new allocation were to be pushed over the the boundaries of the page, a -/// new page is internally allocated first, thus this version of the arena can never -/// run out of memory unless the process runs out of heap altogether. -/// -/// Allocating a type larger than the page size will result in a new heap allocation -/// just for that type separate from the page mechanism. -pub struct Arena { - store: Cell>>, - ptr: Cell<*mut u8>, - offset: Cell, -} - -impl Arena { - /// Create a new arena with a single preallocated 64KiB page. - pub fn new() -> Self { - let mut store = vec![Vec::with_capacity(ARENA_BLOCK)]; - let ptr = store[0].as_mut_ptr(); - - Arena { - store: Cell::new(store), - ptr: Cell::new(ptr), - offset: Cell::new(0), - } - } - - pub fn alloc(&self, size: usize) -> *mut u8 { - // This should be optimized away for size known at compile time. - if size > ARENA_BLOCK { - return self.alloc_bytes(size); - } - - let size = match size % size_of::() { - 0 => size, - n => size + (size_of::() - n), - }; - - let offset = self.offset.get(); - let cap = offset + size; - - if cap > ARENA_BLOCK { - self.grow(); - - self.offset.set(size); - self.ptr.get() - } else { - self.offset.set(cap); - unsafe { self.ptr.get().add(offset) } - } - } - - #[inline] - fn alloc_byte_vec(&self, mut val: Vec) -> *mut u8 { - let ptr = val.as_mut_ptr(); - - let mut temp = self.store.replace(Vec::new()); - temp.push(val); - self.store.replace(temp); - - ptr - } - - pub fn grow(&self) { - let ptr = self.alloc_byte_vec(Vec::with_capacity(ARENA_BLOCK)); - self.ptr.set(ptr); - } - - fn alloc_bytes(&self, size: usize) -> *mut u8 { - self.alloc_byte_vec(Vec::with_capacity(size)) - } - - #[doc(hidden)] - #[inline] - pub unsafe fn offset(&self) -> usize { - self.offset.get() - } -} - -/// Akin to `CopyCell`: `Sync` is unsafe but `Send` is totally fine! -unsafe impl Send for Arena {}