ascii_forge/renderer/
buffer.rs1use crate::prelude::*;
2
3#[derive(Debug)]
22pub struct Buffer {
23 size: Vec2,
24 cells: Vec<Cell>,
25}
26
27impl AsMut<Buffer> for Buffer {
28 fn as_mut(&mut self) -> &mut Buffer {
29 self
30 }
31}
32
33impl Buffer {
34 pub fn new(size: impl Into<Vec2>) -> Self {
36 let size = size.into();
37 Self {
38 size,
39 cells: vec![Cell::default(); size.x as usize * size.y as usize],
40 }
41 }
42
43 pub fn new_filled(size: impl Into<Vec2>, cell: impl Into<Cell>) -> Self {
45 let cell = cell.into();
46 let size = size.into();
47
48 Self {
49 size,
50 cells: vec![cell; size.x as usize * size.y as usize],
51 }
52 }
53
54 pub fn size(&self) -> Vec2 {
56 self.size
57 }
58
59 pub fn set<C: Into<Cell>>(&mut self, loc: impl Into<Vec2>, cell: C) {
61 let loc = loc.into();
62 let idx = self.index_of(loc);
63
64 let Some(idx) = idx else {
66 return;
67 };
68
69 let cell = cell.into();
70
71 for i in 1..cell.width().saturating_sub(1) {
72 self.set(loc + vec2(i, 0), Cell::default());
73 }
74
75 self.cells[idx] = cell;
76 }
77
78 pub fn del(&mut self, loc: impl Into<Vec2>) {
80 self.set(loc, '\0');
81 }
82
83 pub fn fill<C: Into<Cell>>(&mut self, cell: C) {
85 let cell = cell.into();
86 for i in 0..self.cells.len() {
87 self.cells[i] = cell.clone()
88 }
89 }
90
91 pub fn get(&self, loc: impl Into<Vec2>) -> Option<&Cell> {
93 let idx = self.index_of(loc)?;
94 self.cells.get(idx)
95 }
96
97 pub fn get_mut(&mut self, loc: impl Into<Vec2>) -> Option<&mut Cell> {
99 let idx = self.index_of(loc)?;
100 self.cells.get_mut(idx)
101 }
102
103 fn index_of(&self, loc: impl Into<Vec2>) -> Option<usize> {
104 let loc = loc.into();
105 if loc.x > self.size.x || loc.y > self.size.y {
106 return None;
107 }
108
109 let idx = loc.y as usize * self.size.x as usize + loc.x as usize;
110
111 if (idx as u16) >= self.size.x * self.size.y {
112 return None;
113 }
114
115 Some(idx.min((self.size.x as usize * self.size.y as usize) - 1))
116 }
117
118 pub fn clear(&mut self) {
120 *self = Self::new(self.size);
121 }
122
123 pub fn diff<'a>(&self, other: &'a Buffer) -> Vec<(Vec2, &'a Cell)> {
125 assert!(self.size == other.size);
126
127 let mut res = vec![];
128 let mut skip = 0;
129
130 for y in 0..self.size.y {
131 for x in 0..self.size.x {
132 if skip > 0 {
133 skip -= 1;
134 continue;
135 }
136
137 let old = self.get((x, y));
138 let new = other.get((x, y));
139
140 if old != new {
141 let new = new.expect("new should be in bounds");
142 skip = new.width().saturating_sub(1) as usize;
143 res.push((vec2(x, y), new))
144 }
145 }
146 }
147
148 res
149 }
150
151 pub fn shrink(&mut self) {
153 let mut max_whitespace_x = 0;
154 let mut max_whitespace_y = 0;
155 for x in (0..self.size.x).rev() {
156 for y in (0..self.size.y).rev() {
157 if self.get((x, y)).expect("Cell should be in bounds").text() != "\0" {
158 max_whitespace_x = x.max(max_whitespace_x);
159 max_whitespace_y = y.max(max_whitespace_y);
160 }
161 }
162 }
163
164 self.resize(vec2(max_whitespace_x + 1, max_whitespace_y + 1));
165 }
166
167 pub fn resize(&mut self, new_size: impl Into<Vec2>) {
169 let new_size = new_size.into();
170 if self.size == new_size {
171 return;
172 }
173
174 let mut new_elements = vec![];
175
176 for y in 0..new_size.y {
177 for x in 0..new_size.x {
178 new_elements.push(self.get((x, y)).expect("Cell should be in bounds").clone());
179 }
180 }
181
182 self.size = new_size;
183 self.cells = new_elements;
184 }
185
186 pub fn sized_element<R: Render>(item: R) -> Self {
189 let mut buff = Buffer::new((100, 100));
190 render!(buff, vec2(0, 0) => [ item ]);
191 buff.shrink();
192 buff
193 }
194
195 pub fn render_clipped(
197 &self,
198 loc: impl Into<Vec2>,
199 clip_size: impl Into<Vec2>,
200 buffer: &mut Buffer,
201 ) -> Vec2 {
202 let loc = loc.into();
203 let clip_size = clip_size.into();
204
205 for x in 0..clip_size.x.min(self.size().x) {
206 if x + loc.x >= buffer.size().x {
207 break;
208 }
209 for y in 0..clip_size.y.min(self.size().y) {
210 if y + loc.y >= buffer.size().y {
211 break;
212 }
213
214 let source_pos = vec2(x, y);
215 let dest_pos = vec2(x + loc.x, y + loc.y);
216
217 if let Some(cell) = self.get(source_pos) {
218 if cell.text() != "\0" {
219 buffer.set(dest_pos, cell.clone());
220 }
221 }
222 }
223 }
224
225 vec2(
226 loc.x + clip_size.x.min(self.size().x),
227 loc.y + clip_size.y.min(self.size().y),
228 )
229 }
230}
231
232impl Render for Buffer {
233 fn render(&self, loc: Vec2, buffer: &mut Buffer) -> Vec2 {
234 for x in 0..self.size().x {
235 if x + loc.x >= buffer.size().x {
236 break;
237 }
238 for y in 0..self.size().y {
239 if y + loc.y >= buffer.size().y {
240 break;
241 }
242
243 let source_pos = vec2(x, y);
244 let dest_pos = vec2(x + loc.x, y + loc.y);
245
246 if let Some(cell) = self.get(source_pos) {
247 if cell.text() != "\0" {
248 buffer.set(dest_pos, cell.clone());
249 }
250 }
251 }
252 }
253
254 vec2(loc.x + buffer.size().x, loc.y + buffer.size().y)
255 }
256
257 fn size(&self) -> Vec2 {
258 self.size
259 }
260
261 fn render_clipped(&self, loc: Vec2, clip_size: Vec2, buffer: &mut Buffer) -> Vec2 {
262 self.render_clipped(loc, clip_size, buffer)
263 }
264}