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::{
18 geom::Vertex,
19 math::{Color4, vec::ProjVec3},
20};
21
22use super::raster::Frag;
23
24/// Trait for vertex shaders, used to transform vertices and perform other
25/// per-vertex computations.
26///
27/// # Type parameters
28/// * `In`: Type of the input vertex.
29/// * `Uni`: Type of custom "uniform" (non-vertex-specific) data, such as
30/// transform matrices, passed to the shader.
31pub trait VertexShader<In, Uni> {
32 /// The type of the output vertex.
33 type Output;
34 /// Transforms `vertex` and does performs other per-vertex computations
35 /// needed, outputting a new vertex of type `Self::Output`. Custom data
36 /// that is not vertex-specific can be passed in the `uniform` parameter.
37 ///
38 /// # Panics
39 /// `shade_vertex` should never panic.
40 fn shade_vertex(&self, vertex: In, uniform: Uni) -> Self::Output;
41}
42
43/// Trait for fragment shaders, used to compute the color of each individual
44/// pixel, or fragment, rendered.
45///
46/// # Type parameters
47/// * `Var`: The varying of the input fragment.
48pub trait FragmentShader<Var> {
49 /// Computes the color of `frag`. Returns either `Some(color)`, or `None`
50 /// if the fragment should be discarded.
51 ///
52 /// # Panics
53 /// `shade_fragment` should never panic.
54 fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4>;
55}
56
57impl<F, In, Out, Uni> VertexShader<In, Uni> for F
58where
59 F: Fn(In, Uni) -> Out,
60{
61 type Output = Out;
62
63 fn shade_vertex(&self, vertex: In, uniform: Uni) -> Out {
64 self(vertex, uniform)
65 }
66}
67
68impl<F, Var, Out> FragmentShader<Var> for F
69where
70 F: Fn(Frag<Var>) -> Out,
71 Out: Into<Option<Color4>>,
72{
73 fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4> {
74 self(frag).into()
75 }
76}
77
78pub fn new<Vs, Fs, Vtx, Var, Uni>(vs: Vs, fs: Fs) -> Shader<Vs, Fs>
79where
80 Vs: VertexShader<Vtx, Uni, Output = Vertex<ProjVec3, Var>>,
81 Fs: FragmentShader<Var>,
82{
83 Shader::new(vs, fs)
84}
85
86/// A type that composes a vertex and a fragment shader.
87#[derive(Copy, Clone)]
88pub struct Shader<Vs, Fs> {
89 pub vertex_shader: Vs,
90 pub fragment_shader: Fs,
91}
92
93impl<Vs, Fs> Shader<Vs, Fs> {
94 /// Returns a new `Shader` with `vs` as the vertex shader
95 /// and `fs` as the fragment shader.
96 pub const fn new<In, Uni, Pos, Attr>(vs: Vs, fs: Fs) -> Self
97 where
98 Vs: VertexShader<In, Uni, Output = Vertex<Pos, Attr>>,
99 Fs: FragmentShader<Attr>,
100 {
101 Self {
102 vertex_shader: vs,
103 fragment_shader: fs,
104 }
105 }
106}
107
108impl<In, Vs, Fs, Uni> VertexShader<In, Uni> for Shader<Vs, Fs>
109where
110 Vs: VertexShader<In, Uni>,
111{
112 type Output = Vs::Output;
113
114 fn shade_vertex(&self, vertex: In, uniform: Uni) -> Self::Output {
115 self.vertex_shader.shade_vertex(vertex, uniform)
116 }
117}
118
119impl<Vs, Fs, Var> FragmentShader<Var> for Shader<Vs, Fs>
120where
121 Fs: FragmentShader<Var>,
122{
123 fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4> {
124 self.fragment_shader.shade_fragment(frag)
125 }
126}