1use crate::math::{Color3, Color4, Vary};
8use crate::util::{
9 buf::{AsMutSlice2, Buf2, MutSlice2},
10 pixfmt::IntoPixel,
11};
12
13use super::{Context, FragmentShader, raster::Scanline, stats::Throughput};
14
15pub trait Target {
17 fn rasterize<V, Fs>(
21 &mut self,
22 scanline: Scanline<V>,
23 frag_shader: &Fs,
24 ctx: &Context,
25 ) -> Throughput
26 where
27 V: Vary,
28 Fs: FragmentShader<V>;
29}
30
31#[derive(Clone)]
33pub struct Framebuf<Col, Dep> {
34 pub color_buf: Col,
35 pub depth_buf: Dep,
36}
37
38pub struct Colorbuf<B, F> {
40 pub buf: B,
41 pub fmt: F,
42}
43
44impl<B, F: Default> Colorbuf<B, F> {
45 pub fn new(buf: B) -> Self {
46 Self { buf, fmt: F::default() }
47 }
48}
49
50impl<T, B: AsMutSlice2<T>, F> AsMutSlice2<T> for Colorbuf<B, F> {
51 fn as_mut_slice2(&mut self) -> MutSlice2<'_, T> {
52 self.buf.as_mut_slice2()
53 }
54}
55
56impl<Col, Fmt, Dep> Target for Framebuf<Colorbuf<Col, Fmt>, Dep>
57where
58 Col: AsMutSlice2<u32>,
59 Dep: AsMutSlice2<f32>,
60 Color4: IntoPixel<u32, Fmt>,
61{
62 fn rasterize<V: Vary, Fs: FragmentShader<V>>(
64 &mut self,
65 sl: Scanline<V>,
66 fs: &Fs,
67 ctx: &Context,
68 ) -> Throughput {
69 rasterize_fb(
70 &mut self.color_buf,
71 &mut self.depth_buf,
72 sl,
73 fs,
74 Color4::into_pixel,
75 ctx,
76 )
77 }
78}
79
80impl<Buf, Fmt> Target for Colorbuf<Buf, Fmt>
81where
82 Buf: AsMutSlice2<u32>,
83 Color4: IntoPixel<u32, Fmt>,
84{
85 fn rasterize<V: Vary, Fs: FragmentShader<V>>(
88 &mut self,
89 sl: Scanline<V>,
90 fs: &Fs,
91 ctx: &Context,
92 ) -> Throughput {
93 rasterize(&mut self.buf, sl, fs, Color4::into_pixel, ctx)
94 }
95}
96
97impl Target for Buf2<Color4> {
98 fn rasterize<V: Vary, Fs: FragmentShader<V>>(
99 &mut self,
100 sl: Scanline<V>,
101 fs: &Fs,
102 ctx: &Context,
103 ) -> Throughput {
104 rasterize(self, sl, fs, |c| c, ctx)
105 }
106}
107
108impl Target for Buf2<Color3> {
109 fn rasterize<V: Vary, Fs: FragmentShader<V>>(
110 &mut self,
111 sl: Scanline<V>,
112 fs: &Fs,
113 ctx: &Context,
114 ) -> Throughput {
115 rasterize(self, sl, fs, |c| c.to_rgb(), ctx)
116 }
117}
118
119pub fn rasterize<T, V: Vary>(
120 buf: &mut impl AsMutSlice2<T>,
121 mut sl: Scanline<V>,
122 fs: &impl FragmentShader<V>,
123 mut conv: impl FnMut(Color4) -> T,
124 ctx: &Context,
125) -> Throughput {
126 let x0 = sl.xs.start;
127 let x1 = sl.xs.end.max(x0);
128 let mut io = Throughput { i: x1 - x0, o: 0 };
129 let cbuf_span = &mut buf.as_mut_slice2()[sl.y][x0..x1];
130
131 sl.fragments()
132 .zip(cbuf_span)
133 .for_each(|(frag, curr_col)| {
134 if let Some(new_col) = fs.shade_fragment(frag)
135 && ctx.color_write
136 {
137 io.o += 1;
138 *curr_col = conv(new_col);
139 }
140 });
141 io
142}
143
144pub fn rasterize_fb<T, V: Vary>(
145 cbuf: &mut impl AsMutSlice2<T>,
146 zbuf: &mut impl AsMutSlice2<f32>,
147 mut sl: Scanline<V>,
148 fs: &impl FragmentShader<V>,
149 mut conv: impl FnMut(Color4) -> T,
150 ctx: &Context,
151) -> Throughput {
152 let x0 = sl.xs.start;
153 let x1 = sl.xs.end.max(x0);
154 let cbuf_span = &mut cbuf.as_mut_slice2()[sl.y][x0..x1];
155 let zbuf_span = &mut zbuf.as_mut_slice2()[sl.y][x0..x1];
156
157 let mut io = Throughput { i: x1 - x0, o: 0 };
158
159 sl.fragments()
160 .zip(cbuf_span)
161 .zip(zbuf_span)
162 .for_each(|((frag, curr_col), curr_z)| {
163 let new_z = frag.pos.z();
164
165 if ctx.depth_test(new_z, *curr_z)
166 && let Some(new_col) = fs.shade_fragment(frag)
167 {
168 if ctx.color_write {
169 io.o += 1;
170 *curr_col = conv(new_col);
172 }
173 if ctx.depth_write {
174 *curr_z = new_z;
175 }
176 }
177 });
178 io
179}