ascii_forge/renderer/
buffer.rs

1use crate::prelude::*;
2
3/**
4A screen buffer that can be rendered to, has a size
5
6This is the backbone of ascii-forge
7
8`Example`
9```rust, no_run
10use ascii_forge::prelude::*;
11
12// A 30x30 buffer window
13let mut buffer = Buffer::new(30, 30);
14
15// Render Hello World to the top left of the buffer
16render!(
17    buffer, {
18        (0, 0) => "Hello World!"
19    }
20);
21```
22
23*/
24#[derive(Debug)]
25pub struct Buffer {
26    size: Vec2,
27    cells: Vec<Cell>,
28}
29
30impl AsMut<Buffer> for Buffer {
31    fn as_mut(&mut self) -> &mut Buffer {
32        self
33    }
34}
35
36impl Buffer {
37    /// Creates a new buffer of empty cells with the given size.
38    pub fn new(size: impl Into<Vec2>) -> Self {
39        let size = size.into();
40        Self {
41            size,
42            cells: vec![Cell::default(); size.x as usize * size.y as usize],
43        }
44    }
45
46    /// Returns the current size of the buffer.
47    pub fn size(&self) -> Vec2 {
48        self.size
49    }
50
51    /// Sets a cell at the given location to the given cell
52    pub fn set<C: Into<Cell>>(&mut self, loc: impl Into<Vec2>, cell: C) {
53        let idx = self.index_of(loc);
54
55        self.cells[idx] = cell.into();
56    }
57
58    /// Sets all cells at the given location to the given cell
59    pub fn fill<C: Into<Cell>>(&mut self, cell: C) {
60        let cell = cell.into();
61        for i in 0..self.cells.len() {
62            self.cells[i] = cell.clone()
63        }
64    }
65
66    /// Returns a reverence to the cell at the given location.
67    pub fn get(&self, loc: impl Into<Vec2>) -> &Cell {
68        let idx = self.index_of(loc);
69        &self.cells[idx]
70    }
71
72    /// Returns a mutable reference to the cell at the given location.
73    pub fn get_mut(&mut self, loc: impl Into<Vec2>) -> &mut Cell {
74        let idx = self.index_of(loc);
75        &mut self.cells[idx]
76    }
77
78    fn index_of(&self, loc: impl Into<Vec2>) -> usize {
79        let loc = loc.into();
80        let idx = loc.y as usize * self.size.x as usize + loc.x as usize;
81
82        debug_assert!((idx as u16) < self.size.x * self.size.y);
83
84        idx.min((self.size.x as usize * self.size.y as usize) - 1)
85    }
86
87    /// Clears the buffer
88    pub fn clear(&mut self) {
89        *self = Self::new(self.size);
90    }
91
92    /// Returns the cells and locations that are different between the two buffers
93    pub fn diff<'a>(&self, other: &'a Buffer) -> Vec<(Vec2, &'a Cell)> {
94        assert!(self.size == other.size);
95
96        let mut res = vec![];
97
98        for x in 0..self.size.x {
99            for y in 0..self.size.y {
100                if self.get((x, y)) != other.get((x, y)) {
101                    res.push((vec2(x, y), other.get((x, y))))
102                }
103            }
104        }
105
106        res
107    }
108
109    /// Shrinks the buffer to the given size by dropping any cells that are only whitespace
110    pub fn shrink(&mut self) {
111        let mut max_whitespace_x = 0;
112        let mut max_whitespace_y = 0;
113        for x in (0..self.size.x).rev() {
114            for y in (0..self.size.y).rev() {
115                if !self.get((x, y)).is_empty() {
116                    max_whitespace_x = x.max(max_whitespace_x);
117                    max_whitespace_y = y.max(max_whitespace_y);
118                }
119            }
120        }
121
122        self.resize(vec2(max_whitespace_x + 1, max_whitespace_y + 1));
123    }
124
125    /// Resizes the buffer while retaining elements that have already been rendered
126    pub fn resize(&mut self, new_size: impl Into<Vec2>) {
127        let new_size = new_size.into();
128        if self.size == new_size {
129            return;
130        }
131
132        let mut new_elements = vec![];
133
134        for y in 0..new_size.y {
135            for x in 0..new_size.x {
136                new_elements.push(self.get((x, y)).clone());
137            }
138        }
139
140        self.size = new_size;
141        self.cells = new_elements;
142    }
143
144    /// Creates a Buffer from the given element with the minimum size it could have for that element.
145    /// Useful for if you want to store any set of render elements in a custom element.
146    pub fn sized_element<R: Render>(item: R) -> Self {
147        let mut buff = Buffer::new((100, 100));
148        render!(buff, vec2(0, 0) => [ item ]);
149        buff.shrink();
150        buff
151    }
152}
153
154impl Render for Buffer {
155    fn render(&self, loc: Vec2, buffer: &mut Buffer) -> Vec2 {
156        for x in 0..self.size.x {
157            if x + loc.x >= buffer.size.x {
158                break;
159            }
160
161            for y in 0..self.size.y {
162                if y + loc.y >= buffer.size.y {
163                    break;
164                }
165
166                let dest = vec2(x + loc.x, y + loc.y);
167
168                buffer.set(dest, self.get(vec2(x, y)).clone());
169            }
170        }
171        vec2(loc.x + buffer.size().x, loc.y + buffer.size().y)
172    }
173}