device 0.0.4

A generative engine
use super::*;

#[derive(Clone, Copy)]
pub(crate) struct Tiling {
  pub(crate) resolution: u32,
  pub(crate) size: u32,
}

impl Tiling {
  pub(crate) fn destination_read(self, filters: u32) -> bool {
    if self.size == 1 {
      filters.is_multiple_of(2)
    } else {
      true
    }
  }

  pub(crate) fn offset(self, filter: u32) -> Vec2f {
    if self.size == 1 {
      return Vec2f::new(0.0, 0.0);
    }

    let col = filter % self.size;
    let row = filter / self.size;

    Vec2f::new(
      (self.resolution * col) as f32,
      (self.resolution * row) as f32,
    )
  }

  pub(crate) fn set_viewport(self, render_pass: &mut RenderPass, filter: u32) {
    if self.size == 1 {
      return;
    }

    let col = filter % self.size;
    let row = filter / self.size;

    render_pass.set_viewport(
      (col * self.resolution) as f32,
      (row * self.resolution) as f32,
      self.resolution as f32,
      self.resolution as f32,
      0.0,
      0.0,
    );
  }

  pub(crate) fn source_offset(self, filter: u32) -> Vec2f {
    if self.size == 1 {
      return Vec2f::new(0.0, 0.0);
    }

    let Some(filter) = filter.checked_sub(1) else {
      return Vec2f::new(0.0, 0.0);
    };

    let row = filter / self.size;
    let col = filter % self.size;

    Vec2f::new(col as f32 / self.size as f32, row as f32 / self.size as f32)
  }

  pub(crate) fn source_read(self, filters: u32) -> bool {
    if self.size == 1 {
      !filters.is_multiple_of(2)
    } else {
      true
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn tiling() {
    #[track_caller]
    fn case(filter: u32, offset: Vec2f, source_offset: Vec2f) {
      let tiling = Tiling {
        resolution: 100,
        size: 2,
      };

      assert_eq!(tiling.source_offset(filter), source_offset,);
      assert_eq!(tiling.offset(filter), offset,);
    }

    case(0, vector!(0.0, 0.0), vector!(0.0, 0.0));
    case(1, vector!(100.0, 0.0), vector!(0.0, 0.0));
    case(2, vector!(0.0, 100.0), vector!(0.5, 0.0));
    case(3, vector!(100.0, 100.0), vector!(0.0, 0.5));
    case(4, vector!(0.0, 200.0), vector!(0.5, 0.5));
  }
}