Skip to main content

agg_rust/
scanline_storage_aa.rs

1//! Anti-aliased scanline storage.
2//!
3//! Port of `agg_scanline_storage_aa.h`.
4//! Stores rasterized scanlines in memory for later boolean operations
5//! or serialized replay. Each span stores per-pixel coverage data.
6
7use crate::rasterizer_scanline_aa::Scanline;
8
9/// Stored span data: x, len (positive=per-pixel, negative=solid), covers offset.
10#[derive(Debug, Clone, Copy, Default)]
11struct SpanData {
12    x: i32,
13    len: i32,
14    covers_offset: usize,
15}
16
17/// Per-scanline metadata.
18#[derive(Debug, Clone, Copy, Default)]
19struct ScanlineData {
20    y: i32,
21    num_spans: u32,
22    start_span: usize,
23}
24
25/// Anti-aliased scanline storage.
26///
27/// Port of C++ `scanline_storage_aa<T>`.
28/// Stores rendered scanlines for later replay, boolean operations, or serialization.
29pub struct ScanlineStorageAa {
30    spans: Vec<SpanData>,
31    covers: Vec<u8>,
32    scanlines: Vec<ScanlineData>,
33    min_x: i32,
34    min_y: i32,
35    max_x: i32,
36    max_y: i32,
37    cur_scanline: usize,
38}
39
40impl ScanlineStorageAa {
41    pub fn new() -> Self {
42        Self {
43            spans: Vec::new(),
44            covers: Vec::new(),
45            scanlines: Vec::new(),
46            min_x: i32::MAX,
47            min_y: i32::MAX,
48            max_x: i32::MIN,
49            max_y: i32::MIN,
50            cur_scanline: 0,
51        }
52    }
53
54    /// Prepare for new rendering (clear all stored data).
55    pub fn prepare(&mut self) {
56        self.spans.clear();
57        self.covers.clear();
58        self.scanlines.clear();
59        self.min_x = i32::MAX;
60        self.min_y = i32::MAX;
61        self.max_x = i32::MIN;
62        self.max_y = i32::MIN;
63        self.cur_scanline = 0;
64    }
65
66    /// Store a scanline from a ScanlineU8 (unpacked, per-pixel covers).
67    pub fn render_scanline_u8(&mut self, sl: &crate::scanline_u::ScanlineU8) {
68        let y = sl.y();
69        if y < self.min_y {
70            self.min_y = y;
71        }
72        if y > self.max_y {
73            self.max_y = y;
74        }
75
76        let start_span = self.spans.len();
77        let mut num_spans = 0u32;
78
79        let spans = sl.begin();
80        let covers_buf = sl.covers();
81
82        for sp in spans {
83            let x = sp.x;
84            let len = sp.len;
85            if len > 0 {
86                // Per-pixel covers
87                let xe = x + len - 1;
88                if x < self.min_x {
89                    self.min_x = x;
90                }
91                if xe > self.max_x {
92                    self.max_x = xe;
93                }
94                let covers_offset = self.covers.len();
95                self.covers
96                    .extend_from_slice(&covers_buf[sp.cover_offset..sp.cover_offset + len as usize]);
97                self.spans.push(SpanData {
98                    x,
99                    len,
100                    covers_offset,
101                });
102            }
103            num_spans += 1;
104        }
105
106        self.scanlines.push(ScanlineData {
107            y,
108            num_spans,
109            start_span,
110        });
111    }
112
113    /// Store a scanline from a ScanlineP8 (packed, may have solid spans).
114    pub fn render_scanline_p8(&mut self, sl: &crate::scanline_p::ScanlineP8) {
115        let y = sl.y();
116        if y < self.min_y {
117            self.min_y = y;
118        }
119        if y > self.max_y {
120            self.max_y = y;
121        }
122
123        let start_span = self.spans.len();
124        let mut num_spans = 0u32;
125
126        let spans = sl.begin();
127        let covers_buf = sl.covers();
128
129        for sp in spans {
130            let x = sp.x;
131            let len = sp.len;
132            let abs_len = len.unsigned_abs() as i32;
133            let xe = x + abs_len - 1;
134            if x < self.min_x {
135                self.min_x = x;
136            }
137            if xe > self.max_x {
138                self.max_x = xe;
139            }
140            let covers_offset = self.covers.len();
141            if len < 0 {
142                // Solid span — store single cover value
143                self.covers.push(covers_buf[sp.cover_offset]);
144            } else {
145                // Per-pixel covers
146                self.covers
147                    .extend_from_slice(&covers_buf[sp.cover_offset..sp.cover_offset + len as usize]);
148            }
149            self.spans.push(SpanData {
150                x,
151                len,
152                covers_offset,
153            });
154            num_spans += 1;
155        }
156
157        self.scanlines.push(ScanlineData {
158            y,
159            num_spans,
160            start_span,
161        });
162    }
163
164    /// Reset the scanline iteration pointer.
165    pub fn rewind_scanlines(&mut self) -> bool {
166        self.cur_scanline = 0;
167        !self.scanlines.is_empty()
168    }
169
170    /// Sweep the next stored scanline into an output scanline container.
171    /// Returns false when all scanlines have been consumed.
172    pub fn sweep_scanline<SL: Scanline>(&mut self, sl: &mut SL) -> bool {
173        sl.reset_spans();
174        loop {
175            if self.cur_scanline >= self.scanlines.len() {
176                return false;
177            }
178            let sld = self.scanlines[self.cur_scanline];
179            let num_spans = sld.num_spans;
180            self.cur_scanline += 1;
181
182            if num_spans == 0 {
183                continue;
184            }
185
186            for i in 0..num_spans as usize {
187                let sp = self.spans[sld.start_span + i];
188                if sp.len < 0 {
189                    // Solid span
190                    sl.add_span(sp.x, (-sp.len) as u32, self.covers[sp.covers_offset] as u32);
191                } else if sp.len > 0 {
192                    // Per-pixel spans — add cell by cell
193                    for j in 0..sp.len as usize {
194                        sl.add_cell(sp.x + j as i32, self.covers[sp.covers_offset + j] as u32);
195                    }
196                }
197            }
198            sl.finalize(sld.y);
199            return true;
200        }
201    }
202
203    pub fn min_x(&self) -> i32 {
204        self.min_x
205    }
206    pub fn min_y(&self) -> i32 {
207        self.min_y
208    }
209    pub fn max_x(&self) -> i32 {
210        self.max_x
211    }
212    pub fn max_y(&self) -> i32 {
213        self.max_y
214    }
215
216    pub fn num_scanlines(&self) -> usize {
217        self.scanlines.len()
218    }
219
220    // ========================================================================
221    // Embedded scanline access (for boolean algebra)
222    // ========================================================================
223
224    /// Get the Y coordinate for a stored scanline by index.
225    pub fn scanline_y(&self, idx: usize) -> i32 {
226        self.scanlines[idx].y
227    }
228
229    /// Get the number of spans for a stored scanline by index.
230    pub fn scanline_num_spans(&self, idx: usize) -> u32 {
231        self.scanlines[idx].num_spans
232    }
233
234    /// Get the covers slice for a span.
235    fn span_covers(&self, sp: &SpanData) -> &[u8] {
236        if sp.len < 0 {
237            &self.covers[sp.covers_offset..sp.covers_offset + 1]
238        } else {
239            &self.covers[sp.covers_offset..sp.covers_offset + sp.len as usize]
240        }
241    }
242
243    /// Iterate over embedded scanline spans for boolean algebra.
244    /// Returns an iterator of (x, len, covers_slice) tuples.
245    pub fn embedded_spans(
246        &self,
247        sl_idx: usize,
248    ) -> impl Iterator<Item = EmbeddedSpan<'_>> + '_ {
249        let sld = &self.scanlines[sl_idx];
250        let spans = &self.spans[sld.start_span..sld.start_span + sld.num_spans as usize];
251        spans.iter().map(move |sp| EmbeddedSpan {
252            x: sp.x,
253            len: sp.len,
254            covers: self.span_covers(sp),
255        })
256    }
257}
258
259impl Default for ScanlineStorageAa {
260    fn default() -> Self {
261        Self::new()
262    }
263}
264
265/// A span reference from embedded scanline iteration.
266#[derive(Debug, Clone, Copy)]
267pub struct EmbeddedSpan<'a> {
268    pub x: i32,
269    pub len: i32,
270    pub covers: &'a [u8],
271}
272
273impl<'a> EmbeddedSpan<'a> {
274    /// Get the absolute length (number of pixels).
275    pub fn abs_len(&self) -> i32 {
276        self.len.abs()
277    }
278
279    /// Get end X (exclusive).
280    pub fn x_end(&self) -> i32 {
281        self.x + self.abs_len()
282    }
283
284    /// Get the coverage at pixel offset `i` from span start.
285    pub fn cover_at(&self, i: usize) -> u8 {
286        if self.len < 0 {
287            self.covers[0] // solid span
288        } else {
289            self.covers[i]
290        }
291    }
292}
293
294#[cfg(test)]
295mod tests {
296    use super::*;
297    use crate::scanline_u::ScanlineU8;
298
299    #[test]
300    fn test_empty_storage() {
301        let storage = ScanlineStorageAa::new();
302        assert_eq!(storage.num_scanlines(), 0);
303    }
304
305    #[test]
306    fn test_store_and_replay() {
307        let mut storage = ScanlineStorageAa::new();
308        storage.prepare();
309
310        // Build a scanline with a few cells
311        let mut sl = ScanlineU8::new();
312        sl.reset(0, 100);
313        sl.add_cell(10, 128);
314        sl.add_cell(11, 255);
315        sl.add_cell(12, 64);
316        sl.finalize(5);
317        storage.render_scanline_u8(&sl);
318
319        assert_eq!(storage.num_scanlines(), 1);
320        assert_eq!(storage.min_x(), 10);
321        assert_eq!(storage.max_x(), 12);
322        assert_eq!(storage.min_y(), 5);
323        assert_eq!(storage.max_y(), 5);
324
325        // Replay into a fresh scanline
326        assert!(storage.rewind_scanlines());
327        let mut sl2 = ScanlineU8::new();
328        sl2.reset(0, 100);
329        assert!(storage.sweep_scanline(&mut sl2));
330        assert_eq!(sl2.y(), 5);
331        assert_eq!(sl2.num_spans(), 1);
332
333        // Check coverage values
334        let spans = sl2.begin();
335        let covers = sl2.covers();
336        assert_eq!(spans[0].x, 10);
337        assert_eq!(spans[0].len, 3);
338        assert_eq!(covers[spans[0].cover_offset], 128);
339        assert_eq!(covers[spans[0].cover_offset + 1], 255);
340        assert_eq!(covers[spans[0].cover_offset + 2], 64);
341    }
342
343    #[test]
344    fn test_multiple_scanlines() {
345        let mut storage = ScanlineStorageAa::new();
346        storage.prepare();
347
348        let mut sl = ScanlineU8::new();
349        sl.reset(0, 100);
350        sl.add_cell(5, 200);
351        sl.finalize(0);
352        storage.render_scanline_u8(&sl);
353
354        sl.reset_spans();
355        sl.add_cell(10, 100);
356        sl.finalize(1);
357        storage.render_scanline_u8(&sl);
358
359        assert_eq!(storage.num_scanlines(), 2);
360        assert_eq!(storage.min_y(), 0);
361        assert_eq!(storage.max_y(), 1);
362
363        // Replay
364        assert!(storage.rewind_scanlines());
365        let mut sl2 = ScanlineU8::new();
366        sl2.reset(0, 100);
367        assert!(storage.sweep_scanline(&mut sl2));
368        assert_eq!(sl2.y(), 0);
369        assert!(storage.sweep_scanline(&mut sl2));
370        assert_eq!(sl2.y(), 1);
371        assert!(!storage.sweep_scanline(&mut sl2));
372    }
373
374    #[test]
375    fn test_prepare_clears() {
376        let mut storage = ScanlineStorageAa::new();
377
378        let mut sl = ScanlineU8::new();
379        sl.reset(0, 100);
380        sl.add_cell(5, 200);
381        sl.finalize(0);
382        storage.render_scanline_u8(&sl);
383
384        storage.prepare();
385        assert_eq!(storage.num_scanlines(), 0);
386    }
387
388    #[test]
389    fn test_embedded_spans() {
390        let mut storage = ScanlineStorageAa::new();
391        storage.prepare();
392
393        let mut sl = ScanlineU8::new();
394        sl.reset(0, 100);
395        sl.add_cell(10, 128);
396        sl.add_cell(11, 255);
397        sl.add_cell(20, 64);
398        sl.finalize(5);
399        storage.render_scanline_u8(&sl);
400
401        let spans: Vec<_> = storage.embedded_spans(0).collect();
402        assert_eq!(spans.len(), 2);
403        assert_eq!(spans[0].x, 10);
404        assert_eq!(spans[0].len, 2);
405        assert_eq!(spans[0].cover_at(0), 128);
406        assert_eq!(spans[0].cover_at(1), 255);
407        assert_eq!(spans[1].x, 20);
408        assert_eq!(spans[1].len, 1);
409        assert_eq!(spans[1].cover_at(0), 64);
410    }
411}