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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use crate::{
    material::graph::MaterialGraph,
    material_graph,
    math::*,
    mesh::{
        vertex_factory::{StaticVertexFactory, VertexType},
        MeshDrawMode, MeshError,
    },
    vertex_type,
};
use serde::{Deserialize, Serialize};

pub fn default_screenspace_color_material_graph() -> MaterialGraph {
    material_graph! {
        inputs {
            [fragment] uniform color: vec4;
        }

        outputs {
            [fragment] inout BaseColor: vec4;
        }

        [color -> BaseColor]
    }
}

pub fn default_screenspace_texture_material_graph() -> MaterialGraph {
    material_graph! {
        inputs {
            [vertex] inout TextureCoord: vec2 = {vec2(0.0, 0.0)};

            [fragment] uniform mainImage: sampler2D;
        }

        outputs {
            [fragment] inout BaseColor: vec4;
        }

        [(texture2d, sampler: mainImage, coord: [TextureCoord => vTexCoord]) -> BaseColor]
    }
}

pub fn screenspace_domain_graph() -> MaterialGraph {
    material_graph! {
        inputs {
            [fragment] inout BaseColor: vec4 = {vec4(1.0, 1.0, 1.0, 1.0)};
            [fragment] inout VisibilityMask: bool = {true};

            [vertex] in position: vec2 = {vec2(0.0, 0.0)};
        }

        outputs {
            [vertex] inout TextureCoord: vec2;

            [vertex] builtin gl_Position: vec4;
            [fragment] out finalColor: vec4;
        }

        [discarded = (discard_test, condition: (negate, v: VisibilityMask))]
        [position -> TextureCoord]
        [(make_vec4,
            x: (sub_float, a: (mul_float, a: (maskX_vec2, v: position), b: {2.0}), b: {1.0}),
            y: (sub_float, a: (mul_float, a: (maskY_vec2, v: position), b: {2.0}), b: {1.0}),
            z: {0.0},
            w: {1.0}
        ) -> gl_Position]
        [(if_vec4,
            condition: discarded,
            truthy: {vec4(0.0, 0.0, 0.0, 0.0)},
            falsy: BaseColor
        ) -> finalColor]
    }
}

fn default_position() -> vek::Vec2<f32> {
    vec2(0.0, 0.0)
}

pub trait ScreenSpaceDomain: VertexType {}

vertex_type! {
    #[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]
    @tags(ScreenSpaceDomain)
    pub struct ScreenSpaceVertex {
        #[serde(default = "default_position")]
        pub position: vec2 = position(0, bounds),
    }
}

#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]
pub struct ScreenSpaceQuadFactory;

impl ScreenSpaceQuadFactory {
    pub fn factory(self) -> Result<StaticVertexFactory, MeshError> {
        let mut result = StaticVertexFactory::new(
            ScreenSpaceVertex::vertex_layout()?,
            4,
            2,
            MeshDrawMode::Triangles,
        );
        result.vertices_vec2f(
            "position",
            &[
                vec2(0.0, 0.0),
                vec2(1.0, 0.0),
                vec2(1.0, 1.0),
                vec2(0.0, 1.0),
            ],
            None,
        )?;
        result.triangles(&[(0, 1, 2), (2, 3, 0)], None)?;
        Ok(result)
    }
}

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

    #[test]
    fn test_screenspace_materials() {
        MaterialLibrary::assert_material_compilation(
            &ScreenSpaceVertex::vertex_layout().unwrap(),
            RenderTargetDescriptor::Main,
            &screenspace_domain_graph(),
            &default_screenspace_color_material_graph(),
        );

        MaterialLibrary::assert_material_compilation(
            &ScreenSpaceVertex::vertex_layout().unwrap(),
            RenderTargetDescriptor::Main,
            &screenspace_domain_graph(),
            &default_screenspace_texture_material_graph(),
        );
    }
}