verdant 0.7.0

A windowing and rendering library, made to be accessible. Clean API, SDF-based rendering, multi-window support, built on wgpu and winit.
Documentation
use crate::{KIND_CANVAS, KIND_ELLIPSE, KIND_LINE, KIND_RECT, KIND_TEXTURED, Vertex, transform::Transform2d, types::Color, vec::Vec2};

// TODO: an index buffer is a good idea, probably

#[allow(clippy::too_many_arguments)]
pub(crate) fn rect_vertices(
    x: f32, y: f32,
    w: f32, h: f32,
    fill_color: Color,
    outline_color: Color,
    outline_width: f32,
    corner_radius: f32,
    total_scale: Vec2,
) -> [Vertex; 6] {
    let (hw, hh) = (w / 2., h / 2.);
    let (center_x, center_y) = (x + hw, y + hh);

    // half the outline width + an extra 1.5 for anti-aliasing
    let padding = (outline_width / 2.) + 1.5;
    let pad_x = hw + (padding / total_scale.x);
    let pad_y = hh + (padding / total_scale.y);

    let v = |x, y| Vertex {
        position: Vec2::new(x + center_x, y + center_y),
        uv:       Vec2::new(x, y) * total_scale,
        radii:    Vec2::new(hw, hh) * total_scale,

        fill_color,
        outline_color,
        outline_width,
        corner_radius,

        kind: KIND_RECT,
    };
    [
        v(-pad_x, -pad_y), v( pad_x, -pad_y), v( pad_x,  pad_y), // triangle 1
        v(-pad_x, -pad_y), v( pad_x,  pad_y), v(-pad_x,  pad_y), // triangle 2
    ]
}

#[allow(clippy::too_many_arguments)]
pub(crate) fn ellipse_vertices(
    x: f32, y: f32,
    rx: f32, ry: f32,
    fill_color: Color,
    outline_color: Color,
    outline_width: f32,
    total_scale: Vec2,
) -> [Vertex; 6] {
    // half the outline width + an extra 1.5 for anti-aliasing
    let padding = (outline_width / 2.0) + 1.5;
    let pad_x = rx + (padding / total_scale.x);
    let pad_y = ry + (padding / total_scale.y);

    let (x1, y1, x2, y2) = (x - pad_x, y - pad_y, x + pad_x, y + pad_y);

    let v = |x, y, ux, uy| Vertex {
        position: Vec2::new(x, y),
        uv:       Vec2::new(ux, uy) * total_scale,
        radii:    Vec2::new(rx, ry) * total_scale,

        fill_color,
        outline_color,
        outline_width,

        corner_radius: 0.,

        kind: KIND_ELLIPSE,
    };
    [
        v(x1, y1, -pad_x, -pad_y), v(x2, y1,  pad_x, -pad_y), v(x2, y2,  pad_x,  pad_y),
        v(x1, y1, -pad_x, -pad_y), v(x2, y2,  pad_x,  pad_y), v(x1, y2, -pad_x,  pad_y),
    ]
}

pub(crate) fn line_vertices(
    a: Vec2,
    b: Vec2,
    color: Color,
    width: f32,
    transform: Transform2d,
) -> [Vertex; 6] {
    let displacement = b - a;
    let length = displacement.length();
    const EPSILON: f32 = 1e-6;

    let dir = if length < EPSILON {
        Vec2::new(1.0, 0.0)
    } else {
        displacement / length
    };
    let perp = Vec2::new(-dir.y, dir.x);

    let scale_x = transform.transform_vector(dir).length().max(1e-5);
    let scale_y = transform.transform_vector(perp).length().max(1e-5);
    let scale = Vec2::new(scale_x, scale_y);

    if length < EPSILON {
        let radius = width / 2.;
        return ellipse_vertices(
            a.x,
            a.y,
            radius,
            radius,
            color,
            Color::TRANSPARENT,
            0.,
            scale,
        )
    }

    let hw = width / 2.;
    let hl = length / 2.;

    let padding = 1.5;
    let pad_hw = hw + (padding / scale.x);
    let pad_hl = hl + hw + (padding / scale.y);

    let offset_x = dir * pad_hl;
    let offset_y = perp * pad_hw;
    let center = (a + b) / 2.;

    let corners = [
        center - offset_x - offset_y,
        center - offset_x + offset_y,
        center + offset_x + offset_y,
        center + offset_x - offset_y,
    ];

    let uvs = [
        Vec2::new(-pad_hl, -pad_hw),
        Vec2::new(-pad_hl,  pad_hw),
        Vec2::new( pad_hl,  pad_hw),
        Vec2::new( pad_hl, -pad_hw),
    ];

    let v = |i: usize| Vertex {
        position: corners[i],
        uv:       uvs[i] * scale,
        radii:    Vec2::new(hl, 0.) * scale,

        fill_color: color,
        outline_color: color,
        outline_width: width,

        corner_radius: 0.,

        kind: KIND_LINE,
    };

    [v(0), v(3), v(2), v(0), v(2), v(1)]
}

pub(crate) fn textured_vertices(
    x: f32, y: f32,
    w: f32, h: f32,
    uv_min: Vec2, uv_max: Vec2,
    fill_color: Color,
) -> [Vertex; 6] {
    let xs = [x, x + w];
    let ys = [y, y + h];
    let us = [uv_min.x, uv_max.x];
    let vs = [uv_min.y, uv_max.y];

    let v = |x, y| Vertex {
        position: Vec2::new(xs[x], ys[y]),
        uv:       Vec2::new(us[x], vs[y]),
        radii:    Vec2::ZERO,

        fill_color,
        outline_color: Color::TRANSPARENT,
        outline_width: 0.,

        corner_radius: 0.,

        kind: KIND_TEXTURED,
    };

    [
        v(0, 0), v(1, 0), v(1, 1),
        v(0, 0), v(1, 1), v(0, 1),
    ]
}

pub(crate) fn canvas_vertices(
    x: f32, y: f32,
    w: f32, h: f32,
    uv_min: Vec2, uv_max: Vec2,
    fill_color: Color
) -> [Vertex; 6] {
    let mut vertices = textured_vertices(x, y, w, h, uv_min, uv_max, fill_color);
    for v in &mut vertices {
        v.kind = KIND_CANVAS;
    }
    vertices
}