use std::slice::{Iter, IterMut};
use std::time::Instant;
use crate::particle_sys::ParticleSys;
use crate::util::check_period;
#[derive(Debug, Clone)]
pub struct SyncGrp<P: ParticleSys> {
period: f32,
parts: Vec<P>,
start_time: Instant,
active: bool,
looping: bool,
initialized: bool,
}
impl<P: ParticleSys + std::clone::Clone> SyncGrp<P> {
pub fn new(period: f32, sliceparts: &[P]) -> Self {
SyncGrp {
period,
parts: sliceparts.into(),
start_time: Instant::now(),
active: false,
looping: false,
initialized: false,
}
}
pub fn with_systems(mut self, sliceparts: &[P]) -> Self {
self.parts = sliceparts.into();
self
}
}
impl<P> ParticleSys for SyncGrp<P>
where
P: ParticleSys + std::clone::Clone,
{
type T = P;
fn is_active(&self) -> bool {
self.active
}
fn is_looping(&self) -> bool {
self.active && self.looping
}
fn is_initialized(&mut self) -> bool {
self.initialized
}
fn reset_time(&mut self) {
self.start_time = Instant::now();
}
fn elapsed_time(&mut self) -> Option<f32> {
Some(self.start_time.elapsed().as_secs_f32())
}
fn setup(&mut self, should_loop: bool, p: Option<f32>) -> Result<(), String> {
self.period = match p {
Some(p) => {
check_period(p)?;
p
}
None => self.period,
};
for ps in self.parts.iter_mut() {
ps.setup(should_loop, Some(self.period))?;
}
self.looping = should_loop;
self.active = true;
self.initialized = true;
self.reset_time();
Ok(())
}
fn tear_down(&mut self) {
for ps in self.parts.iter_mut() {
ps.tear_down();
}
self.active = false;
self.initialized = false;
}
fn next_frame(&mut self, time: Option<f32>) -> Result<bool, String> {
let current_time = match time {
None => Some(self.start_time.elapsed().as_secs_f32()),
v => v,
};
for ps in self.parts.iter_mut() {
ps.next_frame(current_time)?;
}
Ok(self.start_time.elapsed().as_secs_f32() <= self.period)
}
fn iter(&self) -> Option<Iter<'_, Self::T>> {
Some(self.parts.iter())
}
fn iter_mut(&mut self) -> Option<IterMut<'_, Self::T>> {
Some(self.parts.iter_mut())
}
fn with_period(mut self, p: f32) -> Result<Self, String> {
check_period(p)?;
self.period = p;
Ok(self)
}
}
impl<P: ParticleSys + std::clone::Clone> Default for SyncGrp<P> {
fn default() -> Self {
SyncGrp::new(1.0, &[])
}
}
#[derive(Debug, Clone)]
pub struct SeqGrp<P: ParticleSys> {
period: f32,
parts: Vec<P>,
start_time: Instant,
active: bool,
looping: bool,
initialized: bool,
part_period: f32,
current_part: usize,
time_offset: f32,
}
impl<P> SeqGrp<P>
where
P: ParticleSys + std::clone::Clone,
{
pub fn new(period: f32, sliceparts: &[P]) -> Self {
let part_period = period / sliceparts.len() as f32;
SeqGrp {
period,
parts: sliceparts.into(),
start_time: Instant::now(),
active: false,
looping: false,
initialized: false,
part_period,
current_part: 0,
time_offset: 0.,
}
}
pub fn with_systems(mut self, sliceparts: &[P]) -> Self {
self.parts = sliceparts.into();
self.part_period = self.period / self.parts.len() as f32;
self
}
}
impl<P> ParticleSys for SeqGrp<P>
where
P: ParticleSys + std::clone::Clone,
{
type T = P;
fn is_active(&self) -> bool {
self.active
}
fn is_looping(&self) -> bool {
self.active && self.looping
}
fn is_initialized(&mut self) -> bool {
self.initialized
}
fn reset_time(&mut self) {
self.start_time = Instant::now();
}
fn elapsed_time(&mut self) -> Option<f32> {
Some(self.start_time.elapsed().as_secs_f32())
}
fn setup(&mut self, should_loop: bool, p: Option<f32>) -> Result<(), String> {
self.period = match p {
Some(p) => {
check_period(p)?;
self.part_period = p / self.parts.len() as f32;
p
}
None => self.period,
};
self.parts
.get_mut(0)
.ok_or("indexing out of bounds for SeqGrp part in setup: 0")?
.setup(should_loop, Some(self.part_period))?;
self.current_part = 0;
self.time_offset = 0.;
self.looping = should_loop;
self.active = true;
self.initialized = true;
self.reset_time();
Ok(())
}
fn tear_down(&mut self) {
for ps in self.parts.iter_mut() {
ps.tear_down();
}
self.current_part = 0;
self.time_offset = 0.;
self.active = false;
self.initialized = false;
}
fn next_frame(&mut self, time: Option<f32>) -> Result<bool, String> {
let current_time = match time {
None => Some(self.start_time.elapsed().as_secs_f32()),
Some(v) => Some(v - self.time_offset),
};
let p = self.parts.get_mut(self.current_part).ok_or(format!(
"indexing out of bounds for SeqGrp part in next_frame: {}",
self.current_part
))?;
if !p.next_frame(current_time)? {
self.current_part += 1;
self.time_offset += self.part_period;
if self.current_part == self.parts.len() {
match self.looping {
true => {
self.current_part = 0;
self.time_offset = 0.;
self.reset_time();
}
false => {
return Ok(false);
}
}
}
let p = self.parts.get_mut(self.current_part).ok_or(format!(
"indexing out of bounds for SeqGrp part in next_frame-setup: {}",
self.current_part
))?;
p.tear_down();
p.setup(self.looping, Some(self.part_period))?;
}
Ok(true)
}
fn iter(&self) -> Option<Iter<'_, Self::T>> {
Some(self.parts.iter())
}
fn iter_mut(&mut self) -> Option<IterMut<'_, Self::T>> {
Some(self.parts.iter_mut())
}
fn with_period(mut self, p: f32) -> Result<Self, String> {
check_period(p)?;
self.period = p;
self.part_period = p / self.parts.len() as f32;
Ok(self)
}
}