retrofire_core/render/
shader.rs

1//! Fragment and vertex shaders.
2//!
3//! Shaders are functions that are used to customize vertex and fragment
4//! handling during rendering.
5//!
6//! A *vertex shader* is responsible for transforming and projecting each
7//! vertex in the rendered geometry, usually using a modelview matrix to move
8//! the vertex to the view (camera) space and a projection matrix to transform
9//! it to the clip space. Vertex shaders can also perform any other per-vertex
10//! calculations and pass on the results as attributes of the output vertex.
11//!
12//! A *fragment shader* is used to compute the color of each individual pixel,
13//! or fragment, drawn to the render target. The fragment shader receives as
14//! input any vertex attributes interpolated across the primitive being
15//! rasterized, such as color, texture coordinate, or normal vector.
16
17use crate::geom::Vertex;
18use crate::math::color::Color4;
19
20use super::raster::Frag;
21
22/// Trait for vertex shaders, used to transform vertices and perform other
23/// per-vertex computations.
24///
25/// # Type parameters
26/// * `In`: Type of the input vertex.
27/// * `Uni`: Type of custom "uniform" (non-vertex-specific) data, such as
28///     transform matrices, passed to the shader.
29pub trait VertexShader<In, Uni> {
30    /// The type of the output vertex.
31    type Output;
32    /// Transforms `vertex` and does performs other per-vertex computations
33    /// needed, outputting a new vertex of type `Self::Output`. Custom data
34    /// that is not vertex-specific can be passed in the `uniform` parameter.
35    ///
36    /// # Panics
37    /// `shade_vertex` should never panic.
38    fn shade_vertex(&self, vertex: In, uniform: Uni) -> Self::Output;
39}
40
41/// Trait for fragment shaders, used to compute the color of each individual
42/// pixel, or fragment, rendered.
43///
44/// # Type parameters
45/// * `Var`: The varying of the input fragment.
46pub trait FragmentShader<Var> {
47    /// Computes the color of `frag`. Returns either `Some(color)`, or `None`
48    /// if the fragment should be discarded.
49    ///
50    /// # Panics
51    /// `shade_fragment` should never panic.
52    fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4>;
53}
54
55impl<F, In, Out, Uni> VertexShader<In, Uni> for F
56where
57    F: Fn(In, Uni) -> Out,
58{
59    type Output = Out;
60
61    fn shade_vertex(&self, vertex: In, uniform: Uni) -> Out {
62        self(vertex, uniform)
63    }
64}
65
66impl<F, Var, Out> FragmentShader<Var> for F
67where
68    F: Fn(Frag<Var>) -> Out,
69    Out: Into<Option<Color4>>,
70{
71    fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4> {
72        self(frag).into()
73    }
74}
75
76/// A type that composes a vertex and a fragment shader.
77#[derive(Copy, Clone)]
78pub struct Shader<Vs, Fs> {
79    pub vertex_shader: Vs,
80    pub fragment_shader: Fs,
81}
82
83impl<Vs, Fs> Shader<Vs, Fs> {
84    /// Returns a new `Shader` with `vs` as the vertex shader
85    /// and `fs` as the fragment shader.
86    pub const fn new<In, Uni, Pos, Attr>(vs: Vs, fs: Fs) -> Self
87    where
88        Vs: VertexShader<In, Uni, Output = Vertex<Pos, Attr>>,
89        Fs: FragmentShader<Attr>,
90    {
91        Self {
92            vertex_shader: vs,
93            fragment_shader: fs,
94        }
95    }
96}
97
98impl<In, Vs, Fs, Uni> VertexShader<In, Uni> for Shader<Vs, Fs>
99where
100    Vs: VertexShader<In, Uni>,
101{
102    type Output = Vs::Output;
103
104    fn shade_vertex(&self, vertex: In, uniform: Uni) -> Self::Output {
105        self.vertex_shader.shade_vertex(vertex, uniform)
106    }
107}
108
109impl<Vs, Fs, Var> FragmentShader<Var> for Shader<Vs, Fs>
110where
111    Fs: FragmentShader<Var>,
112{
113    fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4> {
114        self.fragment_shader.shade_fragment(frag)
115    }
116}