Skip to main content

embedded_3dgfx/
command_buffer.rs

1use heapless::Vec;
2
3use crate::{
4    DrawPrimitive,
5    error::{BudgetKind, RenderError},
6};
7
8#[derive(Debug, Clone)]
9pub enum RenderCommand {
10    ClearColor(embedded_graphics_core::pixelcolor::Rgb565),
11    ClearDepth(u32),
12    Draw(DrawPrimitive),
13}
14
15pub struct CommandBuffer<const MAX: usize> {
16    commands: Vec<RenderCommand, MAX>,
17}
18
19impl<const MAX: usize> CommandBuffer<MAX> {
20    pub const fn new() -> Self {
21        Self {
22            commands: Vec::new(),
23        }
24    }
25
26    pub fn clear(&mut self) {
27        self.commands.clear();
28    }
29
30    pub fn len(&self) -> usize {
31        self.commands.len()
32    }
33
34    pub fn is_empty(&self) -> bool {
35        self.commands.is_empty()
36    }
37
38    pub fn push(&mut self, cmd: RenderCommand) -> Result<(), RenderError> {
39        self.commands.push(cmd).map_err(|_| {
40            RenderError::OutOfBudget(BudgetKind::DrawPrimitives {
41                attempted: self.commands.len() + 1,
42                max: MAX,
43            })
44        })
45    }
46
47    pub fn iter(&self) -> core::slice::Iter<'_, RenderCommand> {
48        self.commands.iter()
49    }
50
51    pub fn get(&self, index: usize) -> Option<&RenderCommand> {
52        self.commands.get(index)
53    }
54}
55
56impl<const MAX: usize> Default for CommandBuffer<MAX> {
57    fn default() -> Self {
58        Self::new()
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use embedded_graphics_core::pixelcolor::Rgb565;
66    use nalgebra::Point2;
67
68    #[test]
69    fn new_buffer_starts_empty() {
70        let buf: CommandBuffer<4> = CommandBuffer::new();
71        assert_eq!(buf.len(), 0);
72        assert!(buf.is_empty());
73    }
74
75    #[test]
76    fn push_and_get_roundtrip() {
77        let mut buf: CommandBuffer<4> = CommandBuffer::new();
78        buf.push(RenderCommand::Draw(DrawPrimitive::ColoredPoint(
79            Point2::new(3, 7),
80            Rgb565::new(31, 0, 0),
81        )))
82        .unwrap();
83        assert_eq!(buf.len(), 1);
84        assert!(matches!(
85            buf.get(0),
86            Some(RenderCommand::Draw(DrawPrimitive::ColoredPoint(_, _)))
87        ));
88    }
89
90    #[test]
91    fn push_over_capacity_returns_budget_error() {
92        let mut buf: CommandBuffer<1> = CommandBuffer::new();
93        buf.push(RenderCommand::ClearDepth(0)).unwrap();
94        let err = buf
95            .push(RenderCommand::ClearDepth(1))
96            .expect_err("overflow must fail");
97        assert_eq!(
98            err,
99            RenderError::OutOfBudget(BudgetKind::DrawPrimitives {
100                attempted: 2,
101                max: 1
102            })
103        );
104    }
105}