rast/graphics/
framebuffer.rs

1use std::iter::{self, Iterator};
2
3use super::image::Image;
4
5fn fill_image<T: Sized + Copy>(attachment: &mut Image<T>, value: T) {
6    for (x, y) in attachment.coordinates() {
7        attachment.exchange(x, y, value);
8    }
9}
10
11pub struct Framebuffer {
12    width: usize,
13    height: usize,
14
15    color: Vec<Image<u32>>,
16    depth: Option<Image<f32>>,
17}
18
19#[derive(Debug)]
20pub struct ClearValue {
21    pub color: u32,
22    pub depth: f32,
23}
24
25pub struct MutableScanline<'a> {
26    pub y: usize,
27    pub color: Vec<&'a mut [u32]>,
28    pub depth: Option<&'a mut [f32]>,
29}
30
31impl Framebuffer {
32    pub fn new(width: usize, height: usize, num_color: usize, has_depth: bool) -> Framebuffer {
33        Framebuffer {
34            width: width,
35            height: height,
36
37            color: Vec::from_iter(iter::repeat_with(|| Image::new(width, height)).take(num_color)),
38            depth: match has_depth {
39                true => Some(Image::new(width, height)),
40                false => None,
41            },
42        }
43    }
44
45    pub fn size(&self) -> (usize, usize) {
46        (self.width, self.height)
47    }
48
49    pub fn color_attachments(&self) -> &Vec<Image<u32>> {
50        &self.color
51    }
52
53    pub fn depth_attachment(&self) -> &Option<Image<f32>> {
54        &self.depth
55    }
56
57    pub fn clear(&mut self, value: &ClearValue) {
58        for attachment in &mut self.color {
59            fill_image(attachment, value.color);
60        }
61
62        if let Some(depth) = &mut self.depth {
63            fill_image(depth, value.depth);
64        }
65    }
66
67    pub fn scanlines<'a>(&'a mut self, offset: usize, count: usize) -> Vec<MutableScanline<'a>> {
68        if offset >= self.height || offset + count > self.height {
69            panic!("Invalid scanline range!");
70        }
71
72        let start = offset * self.width;
73        let end = (offset + count) * self.width;
74
75        // vector of advancing cursors through the color attachments through the range selected by
76        // the user
77        let mut color_cursors: Vec<_> = self
78            .color
79            .iter_mut()
80            .map(|attachment| &mut attachment.data_mut()[start..end])
81            .collect();
82
83        // advancing cursor through depth attachment if one exists
84        let mut depth_cursor = self
85            .depth
86            .as_mut()
87            .map(|attachment| &mut attachment.data_mut()[start..end]);
88
89        let mut scanlines = Vec::new();
90        for delta_y in 0..count {
91            let mut color = Vec::new();
92            let mut advanced_cursors = Vec::new();
93
94            // advance color attachment cursors by a row and append a shorter slice at the previous
95            // location
96            for cursor in color_cursors {
97                let (first, second) = cursor.split_at_mut(self.width);
98
99                color.push(first);
100                advanced_cursors.push(second);
101            }
102
103            color_cursors = advanced_cursors;
104            scanlines.push(MutableScanline {
105                y: offset + delta_y,
106                color,
107
108                // i would rather use Option::map but it moves the value regardless of if its
109                // Some(_) or None so we have to match
110                depth: match depth_cursor {
111                    // if we have a depth attachment, advance it by a row and return a shorter
112                    // slice at the previous location
113                    Some(cursor) => {
114                        let (first, second) = cursor.split_at_mut(self.width);
115                        depth_cursor = Some(second);
116
117                        Some(first)
118                    }
119
120                    // otherwise we dont care
121                    None => None,
122                },
123            });
124        }
125
126        scanlines
127    }
128}