murrelet_draw 0.1.2

drawing functions for murrelet, a livecode framework
Documentation
use glam::*;
use itertools::Itertools;
use lerpable::Lerpable;
use murrelet_common::*;
use murrelet_livecode::unitcells::{UnitCellContext, UnitCellCreator, UnitCellExprWorldContext};
use murrelet_livecode_derive::*;

use crate::transform2d::{Transform2d, Transform2dStep};

const REFERENCE_SIZE: f32 = 100.0;

#[derive(Clone, Debug, Livecode, Lerpable)]
pub enum Sequencer {
    Square(SimpleSquareSequence),
    Rect(SimpleRectSequence),
    Hex(SimpleHexSequence),
}
impl UnitCellCreator for Sequencer {
    fn to_unit_cell_ctxs(&self) -> Vec<UnitCellContext> {
        match &self {
            Sequencer::Square(g) => g.to_unit_cell_ctxs(),
            Sequencer::Rect(g) => g.to_unit_cell_ctxs(),
            Sequencer::Hex(g) => g.to_unit_cell_ctxs(),
        }
    }
}

#[derive(Clone, Debug, Default, Livecode, Lerpable)]
pub struct SimpleHexSequence {
    rows: usize,
    cols: usize,
    size: f32,
}
impl UnitCellCreator for SimpleHexSequence {
    fn to_unit_cell_ctxs(&self) -> Vec<UnitCellContext> {
        make_grid(self.cols, self.rows, vec2(self.size, self.size), true)
    }
}

#[derive(Clone, Debug, Default, Livecode, Lerpable)]
pub struct SimpleSquareSequence {
    rows: usize,
    cols: usize,
    size: f32,
}
impl UnitCellCreator for SimpleSquareSequence {
    fn to_unit_cell_ctxs(&self) -> Vec<UnitCellContext> {
        make_grid(self.cols, self.rows, vec2(self.size, self.size), false)
    }
}

#[derive(Clone, Debug, Default, Livecode, Lerpable)]
pub struct SimpleRectSequence {
    rows: usize,
    cols: usize,
    #[lerpable(func = "lerpify_vec2")]
    size: Vec2,
}

impl SimpleRectSequence {
    pub fn new(rows: usize, cols: usize, size: Vec2) -> Self {
        Self { rows, cols, size }
    }
}

impl UnitCellCreator for SimpleRectSequence {
    fn to_unit_cell_ctxs(&self) -> Vec<UnitCellContext> {
        make_grid(self.cols, self.rows, self.size, false)
    }
}

fn make_grid(
    x: usize,
    y: usize,
    cell_size: Vec2,
    offset_alternating: bool,
) -> Vec<UnitCellContext> {
    let x_usize = x;
    let y_usize = y;

    (0..x_usize)
        .flat_map(|x| {
            let x_idx = IdxInRange::new(x, x_usize);
            (0..y_usize).map(move |y| {
                let y_idx = IdxInRange::new(y, y_usize);
                let idx = IdxInRange2d::new_from_idx(x_idx, y_idx);
                let ctx = UnitCellExprWorldContext::from_idx2d(idx, 1.0);

                let mut center = if offset_alternating {
                    let mut center = idx.to_alternating_i().center_of_cell();
                    center += vec2(-0.5, 0.0);
                    if idx.i.i() % 2 == 1 {
                        center += vec2(0.5, 0.5);
                    }

                    let offset_angle = AnglePi::new(1.0 / 6.0);
                    let diag_scale =
                        offset_angle.to_norm_dir() * cell_size.x / (REFERENCE_SIZE * 0.5);

                    center *= diag_scale;
                    center
                } else {
                    let mut center = idx.center_of_cell();
                    center *= vec2(cell_size.x, cell_size.y) / REFERENCE_SIZE;
                    center
                };

                center *= REFERENCE_SIZE;

                let transform = Transform2d::new(vec![
                    Transform2dStep::scale(cell_size.x / 100.0, cell_size.x / 100.0),
                    Transform2dStep::translate_vec(center),
                ])
                .to_simple();
                UnitCellContext::new(ctx, transform)
            })
        })
        .collect_vec()
}