1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! Drawing rectangles; by far the most commonly used `Draw*` struct.

use crate::*;

/// [`QuadIns`] is the basis for most draw structs.This renders a rectangle.
/// There are some default shaders available at [`QuadIns::SHADER`].
///
/// Example usage with your own struct:
///
/// ```
/// struct MyStruct {
///   pub base: QuadIns,
///   pub field1: f32,
///   pub field2: f32,
/// }
/// ```
///
/// And render using:
///
/// ```
/// let s = MyStruct {
///   base: QuadIns::from_rect(rect),
///   field1: 0.0,
///   field2: 0.0,
/// };
/// cx.add_instances(&SHADER, &[s]);
/// ```
#[derive(Clone, Copy, Default)]
#[repr(C)]
pub struct QuadIns {
    /// The top-left corner position of the quad, in absolute coordinates.
    pub rect_pos: Vec2,
    /// The size of the quad.
    pub rect_size: Vec2,
    /// Z-index.
    pub draw_depth: f32,
}

impl QuadIns {
    #[must_use]
    pub fn from_rect(rect: Rect) -> Self {
        debug_assert!(!rect.size.x.is_nan());
        debug_assert!(!rect.size.y.is_nan());
        Self { rect_pos: rect.pos, rect_size: rect.size, ..Default::default() }
    }

    #[must_use]
    pub fn with_draw_depth(mut self, draw_depth: f32) -> Self {
        self.draw_depth = draw_depth;
        self
    }

    #[must_use]
    pub fn rect(&self) -> Rect {
        Rect { pos: self.rect_pos, size: self.rect_size }
    }

    //ANCHOR: build_geom
    pub fn build_geom() -> Geometry {
        // First, represent each corner of the quad as a vertex,
        // with each side having a length of 1.
        let vertex_attributes = vec![
            // top left vertex
            vec2(0., 0.),
            // top right vertex
            vec2(1., 0.),
            // bottom right vertex
            vec2(1., 1.),
            // bottom left vertex
            vec2(0., 1.),
        ];
        // Group the vertices into two triangles, right triangles
        // on opposing corner coming together to share a hypotenuse.
        let indices = vec![
            // top-right triangle
            [0, 1, 2],
            // bottom-left triangle
            [2, 3, 0],
        ];
        Geometry::new(vertex_attributes, indices)
    }
    //ANCHOR_END: build_geom

    /// Common [`Shader`] code for using [`QuadIns`].
    pub const SHADER: CodeFragment = code_fragment!(
        r#"
        instance rect_pos: vec2;
        instance rect_size: vec2;
        instance draw_depth: float;
        geometry geom: vec2;
        varying pos: vec2;

        fn scroll() -> vec2 {
            return draw_scroll;
        }

        fn vertex() -> vec4 {
            let scr = scroll();

            let clipped: vec2 = clamp(
                geom * rect_size + rect_pos - scr,
                draw_clip.xy,
                draw_clip.zw
            );
            pos = (clipped + scr - rect_pos) / rect_size;
            // only pass the clipped position forward
            return camera_projection * (camera_view * vec4(
                clipped.x,
                clipped.y,
                draw_depth + draw_zbias,
                1.
            ));
        }
    "#
    );
}