use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use crate::exec::resume;
use crate::get_context;
struct CoroutineInternal {
future: Pin<Box<dyn Future<Output = ()>>>,
manual_poll: bool,
manual_time: Option<f64>,
}
pub(crate) struct CoroutinesContext {
coroutines: Vec<Option<CoroutineInternal>>,
active_coroutine_now: Option<f64>,
active_coroutine_delta: Option<f64>,
}
impl CoroutinesContext {
pub fn new() -> CoroutinesContext {
CoroutinesContext {
coroutines: Vec::with_capacity(1000),
active_coroutine_now: None,
active_coroutine_delta: None,
}
}
pub fn update(&mut self) {
for future in &mut self.coroutines {
if let Some(f) = future {
if f.manual_poll == false && resume(&mut f.future) {
*future = None;
}
}
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Coroutine {
id: usize,
}
impl Coroutine {
pub fn is_done(&self) -> bool {
let context = &get_context().coroutines_context;
context.coroutines[self.id].is_none()
}
pub fn set_manual_poll(&mut self) {
let context = &mut get_context().coroutines_context;
if let Some(coroutine) = &mut context.coroutines[self.id] {
coroutine.manual_time = Some(0.);
coroutine.manual_poll = true;
}
}
pub fn poll(&mut self, delta_time: f64) {
let context = &mut get_context().coroutines_context;
let coroutine = &mut context.coroutines[self.id];
if let Some(f) = coroutine {
context.active_coroutine_now = f.manual_time;
context.active_coroutine_delta = Some(delta_time);
*f.manual_time.as_mut().unwrap() += delta_time;
if resume(&mut f.future) {
*coroutine = None;
}
context.active_coroutine_now = None;
context.active_coroutine_delta = None;
}
}
}
pub fn start_coroutine(future: impl Future<Output = ()> + 'static + Send) -> Coroutine {
let context = &mut get_context().coroutines_context;
let boxed_future: Pin<Box<dyn Future<Output = ()>>> = Box::pin(future);
context.coroutines.push(Some(CoroutineInternal {
future: boxed_future,
manual_poll: false,
manual_time: None,
}));
Coroutine {
id: context.coroutines.len() - 1,
}
}
pub fn stop_all_coroutines() {
let context = &mut get_context().coroutines_context;
for future in &mut context.coroutines {
*future = None;
}
}
pub fn stop_coroutine(coroutine: Coroutine) {
let context = &mut get_context().coroutines_context;
context.coroutines[coroutine.id] = None;
}
pub struct TimerDelayFuture {
pub(crate) remaining_time: f32,
}
impl Future for TimerDelayFuture {
type Output = Option<()>;
fn poll(mut self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> {
let delta = get_context()
.coroutines_context
.active_coroutine_delta
.unwrap_or(crate::time::get_frame_time() as _);
self.remaining_time -= delta as f32;
if self.remaining_time <= 0.0 {
Poll::Ready(Some(()))
} else {
Poll::Pending
}
}
}
pub fn wait_seconds(time: f32) -> TimerDelayFuture {
TimerDelayFuture {
remaining_time: 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<T>
where
T: Copy + Add<Output = T> + Sub<Output = T> + Mul<f32, Output = T>,
{
from: T,
to: T,
lens: Lens<T>,
start_time: f64,
time: f32,
}
impl<T> Unpin for LinearTweenFuture<T> where
T: Copy + Add<Output = T> + Sub<Output = T> + Mul<f32, Output = T>
{
}
impl<T> Future for LinearTweenFuture<T>
where
T: Copy + Add<Output = T> + Sub<Output = T> + Mul<f32, Output = T>,
{
type Output = ();
fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> {
let t = (miniquad::date::now() - self.start_time) / self.time as f64;
let this = self.get_mut();
let var = this.lens.get();
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<T, T1, F>(
handle: Handle<T1>,
lens: F,
from: T,
to: T,
time: f32,
) -> LinearTweenFuture<T>
where
T: Copy + Add<Output = T> + Sub<Output = T> + Mul<f32, Output = T>,
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<T, T1, F>(handle: Handle<T1>, mut lens: F, path: Vec<T>, time: f32)
where
T: Copy + Add<Output = T> + Sub<Output = T> + Mul<f32, Output = T>,
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
}
}
}