pittore 0.2.4

Simple toolkit for 2D visualization based on wgpu.
Documentation
use glam::{vec2, Mat2, Vec2, Vec2Swizzles, Vec4, Vec4Swizzles};

use crate::render::Color;

use super::Transform2d;

pub trait IntoRawInstance {
    fn into_raw(self, texture_size: Vec2) -> super::Instance;
}

#[derive(Debug, Clone)]
pub struct Instance2d {
    pub transform: Transform2d,
    pub color: Color,
    pub sprite_rect: Option<SpriteRect>,
    pub sprite_scaling: SpriteScaling,
}

impl Default for Instance2d {
    fn default() -> Self {
        Instance2d {
            transform: Transform2d::IDENTITY,
            color: Color::WHITE,
            sprite_rect: None,
            sprite_scaling: SpriteScaling::Sprite,
        }
    }
}

impl IntoRawInstance for Instance2d {
    fn into_raw(mut self, texture_size: Vec2) -> super::Instance {
        let sprite_rect = match self.sprite_rect {
            Some(rect) => rect.into_coords(texture_size),
            None => Vec4::new(0.0, 0.0, 1.0, 1.0),
        };

        if matches!(self.sprite_scaling, SpriteScaling::Sprite) {
            let scale = match self.sprite_rect {
                Some(rect) => rect.0.zw(),
                None => texture_size,
            };
            self.transform.scale *= scale;
        }

        let affine = self.transform.compute_affine();

        super::Instance {
            matrix2: affine.matrix2.to_cols_array(),
            translation: affine.translation,
            sprite_rect,
            color: self.color.0,
            _padding: Default::default(),
        }
    }
}

#[derive(Debug, Clone)]
pub struct Line2d {
    pub start: Vec2,
    pub end: Vec2,
    pub width: f32,
    pub color: Color,
}

impl Default for Line2d {
    fn default() -> Self {
        Line2d {
            start: Vec2::ZERO,
            end: Vec2::ZERO,
            width: 1.0,
            color: Color::WHITE,
        }
    }
}

impl Line2d {
    pub fn new(start: Vec2, end: Vec2, width: f32, color: Color) -> Self {
        Line2d {
            start,
            end,
            width,
            color,
        }
    }
}

impl IntoRawInstance for Line2d {
    #[allow(unused)]
    fn into_raw(mut self, texture_size: Vec2) -> super::Instance {
        let pos = (self.start + self.end) * 0.5;
        let diff = self.end - self.start;
        let d = diff.length();
        let dir = diff.normalize_or(Vec2::X);
        let rotation = Mat2::from_cols(vec2(dir.x, dir.y), vec2(-dir.y, dir.x));

        Instance2d {
            transform: Transform2d::from_translation(pos)
                .with_rotation(rotation)
                .with_scale(vec2(d, self.width)),
            color: self.color,
            ..Default::default()
        }
        .into_raw(texture_size)
    }
}

#[derive(Debug, Default, Clone, Copy)]
pub enum SpriteScaling {
    #[default]
    /// Scale an instance by sprite's size if texture is set.
    Sprite,
    /// Use the default scale of mesh.
    Mesh,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SpriteRect(pub Vec4);

impl SpriteRect {
    pub const fn new(x: u32, y: u32, w: u32, h: u32) -> Self {
        SpriteRect(Vec4::new(x as f32, y as f32, w as f32, h as f32))
    }

    pub fn into_coords(self, size: Vec2) -> Vec4 {
        self.0 / size.xyxy()
    }
}