device 0.0.4

A generative engine
use super::*;

#[derive(Clone)]
pub(crate) struct State {
  pub(crate) alpha: f32,
  pub(crate) beat: u64,
  pub(crate) callback: Option<Box<dyn Callback>>,
  pub(crate) complexity: f32,
  pub(crate) db: f32,
  pub(crate) encoder: f32,
  pub(crate) filter: Filter,
  pub(crate) filters: Vec<Filter>,
  pub(crate) fit: bool,
  pub(crate) interpolate: bool,
  pub(crate) rng: SmallRng,
  pub(crate) spread: bool,
  pub(crate) status: bool,
  pub(crate) text: Option<Text>,
  pub(crate) tile: bool,
  pub(crate) transient: Transformation2,
  pub(crate) velocity: Vec4f,
  pub(crate) wrap: bool,
}

impl Default for State {
  fn default() -> Self {
    Self {
      alpha: 0.5,
      beat: 0,
      callback: None,
      db: 0.0,
      filter: Filter::default(),
      filters: Vec::new(),
      fit: false,
      interpolate: false,
      encoder: 0.0,
      rng: SmallRng::from_rng(&mut rand::rng()),
      spread: false,
      status: false,
      text: None,
      tile: false,
      transient: Transformation2::default(),
      velocity: Vec4f::zeros(),
      complexity: 0.0,
      wrap: true,
    }
  }
}

impl State {
  pub(crate) fn all(&mut self) -> &mut Self {
    self.filter.field = Field::All;
    self
  }

  pub(crate) fn alpha(&mut self, alpha: f32) -> &mut Self {
    self.filter.alpha = alpha;
    self
  }

  #[allow(unused)]
  pub(crate) fn base(&mut self, base: f32) -> &mut Self {
    self.filter.base = base;
    self
  }

  pub(crate) fn bottom(&mut self) -> &mut Self {
    self.filter.field = Field::Bottom;
    self
  }

  pub(crate) fn callback(
    &mut self,
    callback: impl FnMut(&mut State, Duration) + Clone + 'static,
  ) -> &mut Self {
    self.callback = Some(Box::new(callback));
    self
  }

  pub(crate) fn circle(&mut self) -> &mut Self {
    self.filter.field = Field::Circle { size: None };
    self
  }

  #[cfg(false)]
  pub(crate) fn clear(&mut self) -> &mut Self {
    self.filters.clear();
    self
  }

  #[cfg(test)]
  pub(crate) fn coordinates(&mut self, coordinates: bool) -> &mut Self {
    self.filter.coordinates = coordinates;
    self
  }

  #[cfg(test)]
  pub(crate) fn cross(&mut self) -> &mut Self {
    self.filter.field = Field::Cross;
    self
  }

  pub(crate) fn db(&mut self, db: f32) -> &mut Self {
    self.db = db;
    self
  }

  pub(crate) fn field(&mut self, field: Field) -> &mut Self {
    self.filter.field = field;
    self
  }

  pub(crate) fn frequencies(&mut self) -> &mut Self {
    self.filter.field = Field::Frequencies;
    self
  }

  pub(crate) fn identity(&mut self) -> &mut Self {
    self.filter.color = Mat4f::identity();
    self
  }

  pub(crate) fn interpolate(&mut self, interpolate: bool) -> &mut Self {
    self.interpolate = interpolate;
    self
  }

  pub(crate) fn invert(&mut self) -> &mut Self {
    self.filter.color = color::invert();
    self
  }

  pub(crate) fn invert_r(&mut self) -> &mut Self {
    self.filter.color = Axis::Red.invert();
    self
  }

  #[cfg(test)]
  pub(crate) fn left(&mut self) -> &mut Self {
    self.filter.field = Field::Left;
    self
  }

  #[cfg(test)]
  pub(crate) fn mirror_x(&mut self, mirror: Mirror) -> &mut Self {
    self.filter.mirror.x = mirror;
    self
  }

  #[cfg(test)]
  pub(crate) fn mirror_y(&mut self, mirror: Mirror) -> &mut Self {
    self.filter.mirror.y = mirror;
    self
  }

  pub(crate) fn none(&mut self) -> &mut Self {
    self.filter.field = Field::None;
    self
  }

  pub(crate) fn pop(&mut self) -> &mut Self {
    self.filters.pop();
    self
  }

  pub(crate) fn position(&mut self, position: Mat3f) -> &mut Self {
    self.filter.position = position;
    self
  }

  pub(crate) fn preset_limit(&self) -> usize {
    #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
    let preset_limit = ((self.complexity + 1.0) * Preset::LIMIT as f32) as usize;
    preset_limit
  }

  pub(crate) fn push(&mut self) -> &mut Self {
    self.filters.push(self.filter.clone());
    self
  }

  pub(crate) fn repeat(&mut self, repeat: bool) -> &mut Self {
    self.filter.repeat = repeat;
    self
  }

  #[cfg(test)]
  pub(crate) fn rms(&mut self, rms: Mat1x2f) -> &mut Self {
    self.filter.rms = rms;
    self
  }

  pub(crate) fn rotate_color(&mut self, axis: Axis, angle: f32) -> &mut Self {
    self.filter.color = axis.rotate(angle);
    self
  }

  pub(crate) fn rotate_position(&mut self, angle: f32) -> &mut Self {
    self.filter.position = Mat3f::new_rotation(-angle);
    self
  }

  #[cfg(test)]
  pub(crate) fn rotation(&mut self, rotation: f32) -> &mut Self {
    self.filter.position_response.rotation = rotation;
    self
  }

  pub(crate) fn samples(&mut self) -> &mut Self {
    self.filter.field = Field::Samples;
    self
  }

  pub(crate) fn scale(&mut self, n: f32) -> &mut Self {
    self.filter.position *= Mat3f::new_scaling(n);
    self
  }

  pub(crate) fn scaling(&mut self, z: f32) -> &mut Self {
    self.transient.scaling = Vec2f::new(z, z);
    self
  }

  pub(crate) fn spread(&mut self, spread: bool) -> &mut Self {
    self.spread = spread;
    self
  }

  #[cfg(test)]
  pub(crate) fn square(&mut self) -> &mut Self {
    self.filter.field = Field::Square;
    self
  }

  pub(crate) fn text(&mut self, text: Option<Text>) -> &mut Self {
    self.text = text;
    self
  }

  pub(crate) fn tick(&mut self, dt: Duration) {
    {
      let dt = dt.as_secs_f32();
      let ds = self.velocity.z * dt;
      self.transient.translation -= self.velocity.xy() * dt;
      self.transient.scaling -= Vec2f::new(ds, ds);
      self.transient.rotation -= self.velocity.w * dt;
    }

    let mut callback = self.callback.take();
    if let Some(callback) = &mut callback {
      callback(self, dt);
    }
    self.callback = callback;
    for filter in &mut self.filters {
      filter.tick(dt);
    }
  }

  #[cfg(test)]
  pub(crate) fn tile(&mut self, tile: bool) -> &mut Self {
    self.tile = tile;
    self
  }

  pub(crate) fn times(&mut self, n: usize) -> &mut Self {
    for _ in 0..n {
      self.push();
    }
    self
  }

  pub(crate) fn top(&mut self) -> &mut Self {
    self.filter.field = Field::Top;
    self
  }

  pub(crate) fn transform(&mut self, rotation: f32, scaling: f32) -> &mut Self {
    self.position(Mat3f::new_rotation(-rotation).prepend_scaling(scaling))
  }

  pub(crate) fn transient(&self) -> Option<Filter> {
    if self.transient == Transformation2::default() {
      None
    } else {
      Some(Filter {
        position: self.transient.response(1.0),
        wrap: self.wrap,
        ..default()
      })
    }
  }

  #[cfg(test)]
  pub(crate) fn triangle(&mut self) -> &mut Self {
    self.filter.field = Field::Triangle;
    self
  }

  pub(crate) fn truncate(&mut self, len: usize) -> &mut Self {
    self.filters.truncate(len);
    self
  }

  pub(crate) fn vz(&mut self, vz: f32) -> &mut Self {
    self.velocity.z = vz;
    self
  }

  pub(crate) fn wrap(&mut self, wrap: bool) -> &mut Self {
    self.filter.wrap = wrap;
    self
  }

  pub(crate) fn x(&mut self) -> &mut Self {
    self.filter.field = Field::X;
    self
  }
}