retrofire_core/render/
batch.rs

1//! Builder for setting up geometry for rendering.
2
3use alloc::vec::Vec;
4use core::borrow::Borrow;
5
6use crate::geom::{mesh, Mesh, Tri};
7use crate::math::{mat::Mat4x4, vary::Vary};
8
9use super::{ctx::Context, target::Target, NdcToScreen, Shader};
10
11/// A builder for rendering a chunk of geometry as a batch.
12///
13/// Several values must be assigned before the [`render`][Batch::render]
14/// method can be called:
15/// * [faces][Batch::faces]: A list of triangles, each a triplet of indices
16///   into the list of vertices (TODO: handling oob)
17/// * [vertices][Batch::vertices]: A list of vertices
18/// * [shader][Batch::shader]: The combined vertex and fragment shader used
19/// * [target][Batch::target]: The render target to render into
20/// * [context][Batch::context]: The rendering context and settings used. (TODO: optional?)
21///
22/// Additionally, setting the following values is optional:
23/// * [uniform][Batch::uniform]: The uniform value passed to the vertex shader
24/// * [viewport][Batch::viewport]: The matrix used for the NDC-to-screen transform.
25// TODO Not correct right now due to method call ordering constraints
26// A batch can be freely reused, for example to render several chunks of geometry
27// using the same configuration, or several [instances] of the same geometry.
28// [instances]: https://en.wikipedia.org/wiki/Geometry_instancing
29#[derive(Clone, Debug, Default)]
30pub struct Batch<Vtx, Uni, Shd, Tgt, Ctx> {
31    faces: Vec<Tri<usize>>,
32    verts: Vec<Vtx>,
33    uniform: Uni,
34    shader: Shd,
35    viewport: Mat4x4<NdcToScreen>,
36    target: Tgt,
37    ctx: Ctx,
38}
39
40macro_rules! update {
41    ($($upd:ident)+ ; $self:ident $($rest:ident)+) => {{
42        let Self { $($upd: _, )+ $($rest, )+ } = $self;
43        Batch { $($upd, )+ $($rest, )+ }
44    }};
45}
46
47impl Batch<(), (), (), (), Context> {
48    pub fn new() -> Self {
49        Self::default()
50    }
51}
52
53impl<Vtx, Uni, Shd, Tgt, Ctx> Batch<Vtx, Uni, Shd, Tgt, Ctx> {
54    /// Sets the faces to be rendered.
55    ///
56    /// The faces are copied into the batch.
57    pub fn faces(self, faces: impl AsRef<[Tri<usize>]>) -> Self {
58        Self {
59            faces: faces.as_ref().to_vec(),
60            ..self
61        }
62    }
63
64    /// Sets the vertices to be rendered.
65    ///
66    /// The vertices are cloned into the batch.
67    // TODO: Allow taking by reference to make cloning Batch cheap
68    pub fn vertices<V: Clone>(
69        self,
70        verts: impl AsRef<[V]>,
71    ) -> Batch<V, Uni, Shd, Tgt, Ctx> {
72        let verts = verts.as_ref().to_vec();
73        update!(verts; self faces uniform shader viewport target ctx)
74    }
75
76    /// Clones faces and vertices from a mesh to this batch.
77    pub fn mesh<A: Clone>(
78        self,
79        mesh: &Mesh<A>,
80    ) -> Batch<mesh::Vertex<A>, Uni, Shd, Tgt, Ctx> {
81        let faces = mesh.faces.clone();
82        let verts = mesh.verts.clone();
83        update!(verts faces; self uniform shader viewport target ctx)
84    }
85
86    /// Sets the uniform data to be passed to the vertex shaders.
87    pub fn uniform<U: Copy>(self, uniform: U) -> Batch<Vtx, U, Shd, Tgt, Ctx> {
88        update!(uniform; self verts faces shader viewport target ctx)
89    }
90
91    /// Sets the combined vertex and fragment shader.
92    pub fn shader<V: Vary, S: Shader<Vtx, V, Uni>>(
93        self,
94        shader: S,
95    ) -> Batch<Vtx, Uni, S, Tgt, Ctx> {
96        update!(shader; self verts faces uniform viewport target ctx)
97    }
98
99    /// Sets the viewport matrix.
100    pub fn viewport(self, viewport: Mat4x4<NdcToScreen>) -> Self {
101        update!(viewport; self verts faces uniform shader target ctx)
102    }
103
104    /// Sets the render target.
105    pub fn target<T>(self, target: T) -> Batch<Vtx, Uni, Shd, T, Ctx> {
106        update!(target; self verts faces uniform shader viewport ctx)
107    }
108
109    /// Sets the rendering context.
110    pub fn context(self, ctx: &Context) -> Batch<Vtx, Uni, Shd, Tgt, &Context> {
111        update!(ctx; self verts faces uniform shader viewport target)
112    }
113}
114
115impl<Vtx: Clone, Uni: Copy, Shd, Tgt: Target, Ctx>
116    Batch<Vtx, Uni, Shd, &mut Tgt, Ctx>
117where
118    Ctx: Borrow<Context>,
119{
120    /// Renders this batch of geometry.
121    pub fn render<V: Vary>(&mut self)
122    where
123        Shd: Shader<Vtx, V, Uni>,
124    {
125        #[rustfmt::skip]
126        let Self {
127            faces, verts, shader, uniform, viewport, target, ctx,
128        } = self;
129        super::render(
130            faces,
131            verts,
132            shader,
133            *uniform,
134            *viewport,
135            *target,
136            (*ctx).borrow(),
137        );
138    }
139}