Skip to content

Commit 61cb3f8

Browse files
committed
Factor out some common stuff from render functions
1 parent e0d3559 commit 61cb3f8

File tree

2 files changed

+91
-89
lines changed

2 files changed

+91
-89
lines changed

core/src/render.rs

Lines changed: 90 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,17 @@ impl<S, Vtx, Var, Uni> Shader<Vtx, Var, Uni> for S where
8585
{
8686
}
8787

88-
pub fn render_lines<Vtx: Clone, Var: Lerp + Vary, Uni: Copy, Shd>(
89-
lines: impl AsRef<[[usize; 2]]>,
88+
fn start_stats(prims: usize, verts: usize) -> Stats {
89+
let mut s = Stats::start();
90+
s.calls = 1.0;
91+
s.prims.i = prims;
92+
s.verts.i = verts;
93+
s
94+
}
95+
96+
/// Renders the given triangles into `target`.
97+
pub fn render<Vtx: Clone, Var: Lerp + Vary, Uni: Copy, Shd>(
98+
tris: impl AsRef<[Tri<usize>]>,
9099
verts: impl AsRef<[Vtx]>,
91100
shader: &Shd,
92101
uniform: Uni,
@@ -96,67 +105,58 @@ pub fn render_lines<Vtx: Clone, Var: Lerp + Vary, Uni: Copy, Shd>(
96105
) where
97106
Shd: Shader<Vtx, Var, Uni>,
98107
{
108+
let tris = tris.as_ref();
99109
let verts = verts.as_ref();
100-
let lines = lines.as_ref();
101-
let mut stats = Stats::start();
102110

103-
stats.calls = 1.0;
104-
stats.prims.i += lines.len();
105-
stats.verts.i += verts.len();
111+
let mut stats = start_stats(tris.len(), verts.len());
106112

107113
// Vertex shader: transform vertices to clip space
108-
let verts: Vec<_> = verts
109-
.iter()
110-
// TODO Pass vertex as ref to shader
111-
.cloned()
112-
.map(|v| shader.shade_vertex(v, uniform))
113-
.map(ClipVert::new)
114-
.collect();
114+
let verts = transform(verts, shader, uniform);
115115

116116
// Map triangle vertex indices to actual vertices
117-
let lines: Vec<_> = lines
117+
// TODO This needlessly collects soon-to-be-culled triangles
118+
let tris: Vec<_> = tris
118119
.iter()
119-
.map(|vs| vs.map(|i| verts[i].clone()))
120+
.map(|Tri(vs)| Tri(vs.map(|i| verts[i].clone())))
120121
.collect();
121122

122123
// Clip against the view frustum
123124
let mut clipped = vec![];
124-
view_frustum::clip(&lines[..], &mut clipped);
125+
view_frustum::clip(&tris[..], &mut clipped);
125126

126-
for vs in clipped {
127+
// Optional depth sorting for use case such as transparency
128+
if let Some(d) = ctx.depth_sort {
129+
depth_sort(&mut clipped, d);
130+
}
131+
132+
for Tri(vs) in clipped {
127133
// Transform to screen space
128-
let vs = vs.map(|v| {
129-
let [x, y, _, w] = v.pos.0;
130-
// Perspective division (projection to the real plane)
131-
//
132-
// We use the screen-space z coordinate to store the reciprocal
133-
// of the original view-space depth. The interpolated reciprocal
134-
// is used in fragment processing for depth testing (larger values
135-
// are closer) and for perspective correction of the varyings.
136-
let pos = vec3(x, y, 1.0).z_div(w);
137-
Vertex {
138-
// Viewport transform
139-
pos: to_screen.apply(&pos).to_pt(),
140-
// Perspective correction
141-
attrib: v.attrib.z_div(w),
142-
}
143-
});
134+
let vs = project(vs, to_screen);
135+
136+
// Back/frontface culling
137+
//
138+
// TODO This could also be done earlier, before or as part of clipping
139+
match ctx.face_cull {
140+
Some(FaceCull::Back) if is_backface(&vs) => continue,
141+
Some(FaceCull::Front) if !is_backface(&vs) => continue,
142+
_ => {}
143+
}
144144

145145
// Log output stats after culling
146146
stats.prims.o += 1;
147147
stats.verts.o += 3;
148148

149149
// Fragment shader and rasterization
150-
line(vs, |scanline| {
150+
tri_fill(vs, |scanline| {
151151
// Convert to fragments and shade
152152
stats.frags += target.rasterize(scanline, uniform, shader, ctx);
153153
});
154154
}
155155
*ctx.stats.borrow_mut() += stats.finish();
156156
}
157-
/// Renders the given triangles into `target`.
158-
pub fn render<Vtx: Clone, Var: Lerp + Vary, Uni: Copy, Shd>(
159-
tris: impl AsRef<[Tri<usize>]>,
157+
158+
pub fn render_lines<Vtx: Clone, Var: Lerp + Vary, Uni: Copy, Shd>(
159+
lines: impl AsRef<[[usize; 2]]>,
160160
verts: impl AsRef<[Vtx]>,
161161
shader: &Shd,
162162
uniform: Uni,
@@ -166,83 +166,84 @@ pub fn render<Vtx: Clone, Var: Lerp + Vary, Uni: Copy, Shd>(
166166
) where
167167
Shd: Shader<Vtx, Var, Uni>,
168168
{
169+
let lines = lines.as_ref();
169170
let verts = verts.as_ref();
170-
let tris = tris.as_ref();
171-
let mut stats = Stats::start();
172171

173-
stats.calls = 1.0;
174-
stats.prims.i += tris.len();
175-
stats.verts.i += verts.len();
172+
let mut stats = start_stats(lines.len(), verts.len());
176173

177174
// Vertex shader: transform vertices to clip space
178-
let verts: Vec<_> = verts
179-
.iter()
180-
// TODO Pass vertex as ref to shader
181-
.cloned()
182-
.map(|v| shader.shade_vertex(v, uniform))
183-
.map(ClipVert::new)
184-
.collect();
175+
let verts = transform(verts, shader, uniform);
185176

186-
// Map triangle vertex indices to actual vertices
187-
let tris: Vec<_> = tris
177+
// Map vertex indices to actual vertices
178+
let lines: Vec<_> = lines
188179
.iter()
189-
.map(|Tri(vs)| Tri(vs.map(|i| verts[i].clone())))
180+
.map(|vs| vs.map(|i| verts[i].clone()))
190181
.collect();
191182

192183
// Clip against the view frustum
193184
let mut clipped = vec![];
194-
view_frustum::clip(&tris[..], &mut clipped);
195-
196-
// Optional depth sorting for use case such as transparency
197-
if let Some(d) = ctx.depth_sort {
198-
depth_sort(&mut clipped, d);
199-
}
185+
view_frustum::clip(&lines[..], &mut clipped);
200186

201-
for Tri(vs) in clipped {
187+
for vs in clipped {
202188
// Transform to screen space
203-
let vs = vs.map(|v| {
204-
let [x, y, _, w] = v.pos.0;
205-
// Perspective division (projection to the real plane)
206-
//
207-
// We use the screen-space z coordinate to store the reciprocal
208-
// of the original view-space depth. The interpolated reciprocal
209-
// is used in fragment processing for depth testing (larger values
210-
// are closer) and for perspective correction of the varyings.
211-
let pos = vec3(x, y, 1.0).z_div(w);
212-
Vertex {
213-
// Viewport transform
214-
pos: to_screen.apply(&pos).to_pt(),
215-
// Perspective correction
216-
attrib: v.attrib.z_div(w),
217-
}
218-
});
219-
220-
// Back/frontface culling
221-
//
222-
// TODO This could also be done earlier, before or as part of clipping
223-
match ctx.face_cull {
224-
Some(FaceCull::Back) if is_backface(&vs) => continue,
225-
Some(FaceCull::Front) if !is_backface(&vs) => continue,
226-
_ => {}
227-
}
189+
let vs = project(vs, to_screen);
228190

229191
// Log output stats after culling
230192
stats.prims.o += 1;
231193
stats.verts.o += 3;
232194

233195
// Fragment shader and rasterization
234-
tri_fill(vs, |scanline| {
196+
line(vs, |scanline| {
235197
// Convert to fragments and shade
236198
stats.frags += target.rasterize(scanline, uniform, shader, ctx);
237199
});
238200
}
239201
*ctx.stats.borrow_mut() += stats.finish();
240202
}
241203

204+
fn transform<'a, I, S, U, V, A>(verts: I, shd: &S, uni: U) -> Vec<ClipVert<A>>
205+
where
206+
I: IntoIterator<Item = &'a V>,
207+
S: VertexShader<V, U, Output = Vertex<ProjVec4, A>>,
208+
U: Copy,
209+
V: Clone + 'a,
210+
{
211+
verts
212+
.into_iter()
213+
.cloned()
214+
// TODO Pass vertex as ref to shader
215+
.map(|v| shd.shade_vertex(v, uni))
216+
.map(ClipVert::new)
217+
.collect()
218+
}
219+
220+
fn project<A: ZDiv, const N: usize>(
221+
vs: [ClipVert<A>; N],
222+
to_screen: Mat4x4<NdcToScreen>,
223+
) -> [Vertex<ScreenPt, A>; N] {
224+
vs.map(|v| {
225+
let [x, y, _, w] = v.pos.0;
226+
// Perspective division (projection to the real plane)
227+
//
228+
// We use the screen-space z coordinate to store the reciprocal
229+
// of the original view-space depth. The interpolated reciprocal
230+
// is used in fragment processing for depth testing (larger values
231+
// are closer) and for perspective correction of the varyings.
232+
let pos = vec3(x, y, 1.0).z_div(w);
233+
Vertex {
234+
// Viewport transform
235+
pos: to_screen.apply(&pos).to_pt(),
236+
// Perspective correction
237+
attrib: v.attrib.z_div(w),
238+
}
239+
})
240+
}
241+
242+
/// Sorts triangles by depth.
242243
fn depth_sort<A>(tris: &mut [Tri<ClipVert<A>>], d: DepthSort) {
243-
tris.sort_unstable_by(|t, u| {
244-
let z = t.0[0].pos.z() + t.0[1].pos.z() + t.0[2].pos.z();
245-
let w = u.0[0].pos.z() + u.0[1].pos.z() + u.0[2].pos.z();
244+
tris.sort_unstable_by(|Tri(vs), Tri(us)| {
245+
let z = vs[0].pos.z() + vs[1].pos.z() + vs[2].pos.z();
246+
let w = us[0].pos.z() + us[1].pos.z() + us[2].pos.z();
246247
if d == DepthSort::FrontToBack {
247248
z.total_cmp(&w)
248249
} else {

core/src/render/cam.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ impl<M: Mode> Camera<M> {
133133
self.world_to_view().then(&self.project)
134134
}
135135

136+
#[allow(unused)]
136137
/// Renders the given geometry from the viewpoint of this camera.
137138
pub fn render<B, Vtx: Clone, Var: Lerp + Vary, Uni: Copy, Shd>(
138139
&self,

0 commit comments

Comments
 (0)