1use alloc::vec::Vec;
9use core::fmt::Debug;
10
11use crate::geom::Vertex;
12use crate::math::{
13 Mat4x4, Vary,
14 mat::{RealToProj, RealToReal},
15 vec::ProjVec3,
16};
17
18use self::{
19 clip::{ClipVert, view_frustum},
20 ctx::DepthSort,
21 raster::Scanline,
22};
23
24pub use self::{
25 batch::Batch,
26 cam::Camera,
27 clip::Clip,
28 ctx::Context,
29 shader::{FragmentShader, VertexShader},
30 stats::Stats,
31 target::{Colorbuf, Framebuf, Target},
32 tex::{TexCoord, Texture, uv},
33 text::Text,
34};
35
36pub mod batch;
37pub mod cam;
38pub mod clip;
39pub mod ctx;
40pub mod prim;
41pub mod raster;
42pub mod scene;
43pub mod shader;
44pub mod stats;
45pub mod target;
46pub mod tex;
47pub mod text;
48
49pub trait Render<V: Vary> {
51 type Clip;
53
54 type Clips: Clip<Item = Self::Clip> + ?Sized;
56
57 type Screen;
59
60 fn inline(ixd: Self, vs: &[ClipVert<V>]) -> Self::Clip;
62
63 fn depth(_clip: &Self::Clip) -> f32 {
65 f32::INFINITY
66 }
67
68 fn is_backface(_: &Self::Screen) -> bool {
70 false
71 }
72
73 fn to_screen(clip: Self::Clip, tf: &Mat4x4<NdcToScreen>) -> Self::Screen;
75
76 fn rasterize<F: FnMut(Scanline<V>)>(scr: Self::Screen, scanline_fn: F);
78}
79
80#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
82pub struct Model;
83
84#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
86pub struct World;
87
88#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
90pub struct View;
91
92#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
94pub struct Ndc;
95
96#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
98pub struct Screen;
99
100pub type ModelToWorld = RealToReal<3, Model, World>;
102
103pub type WorldToView = RealToReal<3, World, View>;
105
106pub type ModelToView = RealToReal<3, Model, View>;
108
109pub type ModelToProj = RealToProj<Model>;
111
112pub type ViewToProj = RealToProj<View>;
114
115pub type NdcToScreen = RealToReal<3, Ndc, Screen>;
117
118pub trait Shader<Vtx, Var, Uni>:
120 VertexShader<Vtx, Uni, Output = Vertex<ProjVec3, Var>> + FragmentShader<Var>
121{
122}
123impl<S, Vtx, Var, Uni> Shader<Vtx, Var, Uni> for S where
124 S: VertexShader<Vtx, Uni, Output = Vertex<ProjVec3, Var>>
125 + FragmentShader<Var>
126{
127}
128
129pub fn render<Prim, Vtx: Clone, Var, Uni: Copy, Shd>(
131 prims: impl AsRef<[Prim]>,
132 verts: impl AsRef<[Vtx]>,
133 shader: &Shd,
134 uniform: Uni,
135 to_screen: Mat4x4<NdcToScreen>,
136 target: &mut impl Target,
137 ctx: &Context,
138) where
139 Prim: Render<Var> + Clone,
140 [<Prim>::Clip]: Clip<Item = Prim::Clip>,
141 Var: Vary,
142 Shd: Shader<Vtx, Var, Uni>,
143{
144 let verts = verts.as_ref();
146 let prims = prims.as_ref();
147
148 let mut stats = Stats::start();
149 stats.calls = 1.0;
150 stats.prims.i = prims.len();
151 stats.verts.i = verts.len();
152
153 let verts: Vec<_> = verts
155 .iter()
157 .cloned()
159 .map(|v| shader.shade_vertex(v, uniform))
160 .map(ClipVert::new)
161 .collect();
162
163 let prims: Vec<_> = prims
165 .iter()
166 .map(|tri| Prim::inline(tri.clone(), &verts))
167 .collect();
169
170 let mut clipped = Vec::with_capacity(prims.len() / 2);
173 view_frustum::clip(&prims[..], &mut clipped);
174
175 if let Some(d) = ctx.depth_sort {
177 depth_sort::<Prim, _>(&mut clipped, d);
178 }
179
180 for prim in clipped {
182 let prim = Prim::to_screen(prim, &to_screen);
184 if ctx.face_cull(Prim::is_backface(&prim)) {
187 continue;
188 }
189
190 stats.prims.o += 1;
192 stats.verts.o += 3; Prim::rasterize(prim, |scanline| {
196 stats.frags += target.rasterize(scanline, shader, ctx);
198 });
199 }
200 *ctx.stats.borrow_mut() += stats.finish();
201}
202
203fn depth_sort<P: Render<V>, V: Vary>(prims: &mut [P::Clip], d: DepthSort) {
204 prims.sort_unstable_by(|t, u| {
205 let z = P::depth(t);
206 let w = P::depth(u);
207 if d == DepthSort::FrontToBack {
208 z.total_cmp(&w)
209 } else {
210 w.total_cmp(&z)
211 }
212 });
213}