retrofire_core/render/shader.rs
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
//! Fragment and vertex shaders.
//!
//! Shaders are functions that are used to customize vertex and fragment
//! handling during rendering.
//!
//! A *vertex shader* is responsible for transforming and projecting each
//! vertex in the rendered geometry, usually using a modelview matrix to move
//! the vertex to the view (camera) space and a projection matrix to transform
//! it to the clip space. Vertex shaders can also perform any other per-vertex
//! calculations and pass on the results as attributes of the output vertex.
//!
//! A *fragment shader* is used to compute the color of each individual pixel,
//! or fragment, drawn to the render target. The fragment shader receives as
//! input any vertex attributes interpolated across the primitive being
//! rasterized, such as color, texture coordinate, or normal vector.
use crate::geom::Vertex;
use crate::math::color::Color4;
use super::raster::Frag;
/// Trait for vertex shaders, used to transform vertices and perform other
/// per-vertex computations.
///
/// # Type parameters
/// * `In`: Type of the input vertex.
/// * `Uni`: Type of custom "uniform" (non-vertex-specific) data, such as
/// transform matrices, passed to the shader.
pub trait VertexShader<In, Uni> {
/// The type of the output vertex.
type Output;
/// Transforms `vertex` and does performs other per-vertex computations
/// needed, outputting a new vertex of type `Self::Output`. Custom data
/// that is not vertex-specific can be passed in the `uniform` parameter.
///
/// # Panics
/// `shade_vertex` should never panic.
fn shade_vertex(&self, vertex: In, uniform: Uni) -> Self::Output;
}
/// Trait for fragment shaders, used to compute the color of each individual
/// pixel, or fragment, rendered.
///
/// # Type parameters
/// * `Var`: The varying of the input fragment.
pub trait FragmentShader<Var> {
/// Computes the color of `frag`. Returns either `Some(color)`, or `None`
/// if the fragment should be discarded.
///
/// # Panics
/// `shade_fragment` should never panic.
fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4>;
}
impl<F, In, Out, Uni> VertexShader<In, Uni> for F
where
F: Fn(In, Uni) -> Out,
{
type Output = Out;
fn shade_vertex(&self, vertex: In, uniform: Uni) -> Out {
self(vertex, uniform)
}
}
impl<F, Var, Out> FragmentShader<Var> for F
where
F: Fn(Frag<Var>) -> Out,
Out: Into<Option<Color4>>,
{
fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4> {
self(frag).into()
}
}
/// A type that composes a vertex and a fragment shader.
#[derive(Copy, Clone)]
pub struct Shader<Vs, Fs> {
pub vertex_shader: Vs,
pub fragment_shader: Fs,
}
impl<Vs, Fs> Shader<Vs, Fs> {
/// Returns a new `Shader` with `vs` as the vertex shader
/// and `fs` as the fragment shader.
pub const fn new<In, Uni, Pos, Attr>(vs: Vs, fs: Fs) -> Self
where
Vs: VertexShader<In, Uni, Output = Vertex<Pos, Attr>>,
Fs: FragmentShader<Attr>,
{
Self {
vertex_shader: vs,
fragment_shader: fs,
}
}
}
impl<In, Vs, Fs, Uni> VertexShader<In, Uni> for Shader<Vs, Fs>
where
Vs: VertexShader<In, Uni>,
{
type Output = Vs::Output;
fn shade_vertex(&self, vertex: In, uniform: Uni) -> Self::Output {
self.vertex_shader.shade_vertex(vertex, uniform)
}
}
impl<Vs, Fs, Var> FragmentShader<Var> for Shader<Vs, Fs>
where
Fs: FragmentShader<Var>,
{
fn shade_fragment(&self, frag: Frag<Var>) -> Option<Color4> {
self.fragment_shader.shade_fragment(frag)
}
}