agg/
raster.rs

1//! Rasterizer
2
3use crate::POLY_SUBPIXEL_SHIFT;
4use crate::POLY_SUBPIXEL_SCALE;
5//use crate::POLY_SUBPIXEL_MASK;
6
7use crate::clip::Clip;
8use crate::scan::ScanlineU8;
9use crate::cell::RasterizerCell;
10use crate::path_storage::PathCommand;
11use crate::path_storage::Vertex;
12
13//use crate::Rasterize;
14use crate::VertexSource;
15
16use std::cmp::min;
17use std::cmp::max;
18
19struct RasConvInt {
20}
21impl RasConvInt {
22    pub fn upscale(v: f64) -> i64 {
23        (v * POLY_SUBPIXEL_SCALE as f64).round() as i64
24    }
25    //pub fn downscale(v: i64) -> i64 {
26    //    v
27    //}
28}
29
30/// Winding / Filling Rule
31///
32/// See (Non-Zero Filling Rule)[https://en.wikipedia.org/wiki/Nonzero-rule] and
33/// (Even-Odd Filling)[https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule]
34#[derive(Debug,PartialEq,Copy,Clone)]
35pub enum FillingRule {
36    NonZero,
37    EvenOdd,
38}
39impl Default for FillingRule {
40    fn default() -> FillingRule {
41        FillingRule::NonZero
42    }
43}
44
45/// Path Status
46#[derive(Debug,PartialEq,Copy,Clone)]
47pub enum PathStatus {
48    Initial,
49    Closed,
50    MoveTo,
51    LineTo
52}
53impl Default for PathStatus {
54    fn default() -> PathStatus {
55        PathStatus::Initial
56    }
57}
58
59/// Rasterizer Anti-Alias using Scanline
60#[derive(Debug, Default)]
61pub struct RasterizerScanline {
62    /// Clipping Region
63    pub clipper: Clip,
64    /// Collection of Rasterizing Cells
65    pub outline: RasterizerCell,
66    /// Status of Path
67    pub status: PathStatus,
68    /// Current x position
69    pub x0: i64,
70    /// Current y position
71    pub y0: i64,
72    /// Current y row being worked on, for output
73    scan_y: i64,
74    /// Filling Rule for Polygons
75    filling_rule: FillingRule,
76    /// Gamma Corection Values
77    gamma: Vec<u64>,
78}
79
80impl RasterizerScanline {
81    /// Reset Rasterizer
82    ///
83    /// Reset the RasterizerCell and set PathStatus to Initial
84    pub fn reset(&mut self) {
85        self.outline.reset();
86        self.status = PathStatus::Initial;
87    }
88    /// Add a Path
89    ///
90    /// Walks the path from the VertexSource and rasterizes it
91    pub fn add_path<VS: VertexSource>(&mut self, path: &VS) {
92        //path.rewind();
93        if ! self.outline.sorted_y.is_empty() {
94            self.reset();
95        }
96        for seg in path.xconvert() {
97            println!("ADD_PATH: {:?}", seg);
98            match seg.cmd {
99                PathCommand::LineTo => self.line_to_d(seg.x, seg.y),
100                PathCommand::MoveTo => self.move_to_d(seg.x, seg.y),
101                PathCommand::Close  => self.close_polygon(),
102                PathCommand::Stop => unimplemented!("stop encountered"),
103            }
104        }
105    }
106
107    /// Rewind the Scanline
108    ///
109    /// Close active polygon, sort the Rasterizer Cells, set the
110    /// scan_y value to the minimum y value and return if any cells
111    /// are present
112    pub fn rewind_scanlines(&mut self) -> bool {
113        self.close_polygon();
114        self.outline.sort_cells();
115        if self.outline.total_cells() == 0 {
116            false
117        } else {
118            self.scan_y = self.outline.min_y;
119            true
120        }
121    }
122
123    /// Sweep the Scanline
124    ///
125    /// For individual y rows adding any to the input Scanline
126    ///
127    /// Returns true if data exists in the input Scanline
128    pub(crate) fn sweep_scanline(&mut self, sl: &mut ScanlineU8) -> bool {
129        println!("ADD_PATH: SWEEP SCANLINE: Y: {}", self.scan_y);
130        loop {
131            if self.scan_y < 0 {
132                self.scan_y += 1;
133                continue;
134            }
135            if self.scan_y > self.outline.max_y {
136                return false;
137            }
138            sl.reset_spans();
139            let mut num_cells = self.outline.scanline_num_cells( self.scan_y );
140            let cells = self.outline.scanline_cells( self.scan_y );
141
142            let mut cover = 0;
143
144            let mut iter = cells.iter();
145
146            if let Some(mut cur_cell) = iter.next() {
147                while num_cells > 0 {
148                    let mut x = cur_cell.x;
149                    let mut area = cur_cell.area;
150
151                    cover  += cur_cell.cover;
152                    println!("ADD_PATH: SWEEP SCANLINES: x,y {} {} {} {} :: {} {} n: {}", cur_cell.x, self.scan_y, cur_cell.area, cur_cell.cover, area, cover, num_cells);
153                    num_cells -= 1;
154                    //accumulate all cells with the same X
155                    while num_cells > 0 {
156                        cur_cell = iter.next().unwrap();
157                        if cur_cell.x != x {
158                            break;
159                        }
160                        area += cur_cell.area;
161                        cover += cur_cell.cover;
162                        num_cells -= 1;
163                        println!("ADD_PATH: SWEEP SCANLINES: x,y {} {} {} {} :: {} {}", cur_cell.x, self.scan_y, cur_cell.area, cur_cell.cover, area, cover);
164                    }
165                    println!("ADD_PATH: SWEEP SCANLINES: x,y {} {} {} {} :: {} {}", cur_cell.x, self.scan_y, cur_cell.area, cur_cell.cover, area, cover);
166                    if area != 0 {
167                        println!("ADD_PATH: SWEEP SCANLINES: ADDING CELL: x {} y {} area {} cover {}", x, self.scan_y, area, cover);
168                        let alpha = self.calculate_alpha((cover << (POLY_SUBPIXEL_SHIFT + 1)) - area);
169                        if alpha > 0 {
170                            sl.add_cell(x, alpha);
171                        }
172                        x += 1;
173                    }
174                    if num_cells > 0 && cur_cell.x > x {
175                        let alpha = self.calculate_alpha(cover << (POLY_SUBPIXEL_SHIFT + 1));
176                        println!("ADD_PATH: SWEEP SCANLINES: ADDING SPAN: {} -> {} Y: {} area {} cover {}", x, cur_cell.x, self.scan_y, area, cover);
177                        if alpha > 0 {
178                            sl.add_span(x, cur_cell.x - x, alpha);
179                        }
180                    }
181                }
182            }
183            if sl.num_spans() != 0 {
184                break;
185            }
186            self.scan_y += 1;
187        }
188        sl.finalize(self.scan_y);
189        self.scan_y += 1;
190        true
191    }
192    /// Return minimum x value from the RasterizerCell
193    pub fn min_x(&self) -> i64 {
194        self.outline.min_x
195    }
196    /// Return maximum x value from the RasterizerCell
197    pub fn max_x(&self) -> i64 {
198        self.outline.max_x
199    }
200}
201
202impl RasterizerScanline {
203    /// Create a new RasterizerScanline
204    pub fn new() -> Self {
205        Self { clipper: Clip::new(), status: PathStatus::Initial,
206               outline: RasterizerCell::new(),
207               x0: 0, y0: 0, scan_y: 0,
208               filling_rule: FillingRule::NonZero,
209               gamma: (0..256).collect(),
210        }
211    }
212    /// Set the gamma function
213    ///
214    /// Values are set as:
215    ///```ignore
216    ///      gamma = gfunc( v / mask ) * mask
217    ///```
218    /// where v = 0 to 255
219    pub fn gamma<F>(&mut self, gfunc: F)
220        where F: Fn(f64) -> f64
221    {
222        let aa_shift  = 8;
223        let aa_scale  = 1 << aa_shift;
224        let aa_mask   = f64::from(aa_scale - 1);
225
226        self.gamma = (0..256)
227            .map(|i| gfunc(f64::from(i) / aa_mask ))
228            .map(|v| (v * aa_mask).round() as u64)
229            .collect();
230    }
231    /// Create a new RasterizerScanline with a gamma function
232    ///
233    /// See gamma() function for description
234    ///
235    pub fn new_with_gamma<F>(gfunc: F) -> Self
236        where F: Fn(f64) -> f64
237    {
238        let mut new = Self::new();
239        new.gamma( gfunc );
240        new
241    }
242    /// Set Clip Box
243    pub fn clip_box(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) {
244        self.clipper.clip_box(RasConvInt::upscale(x1),
245                              RasConvInt::upscale(y1),
246                              RasConvInt::upscale(x2),
247                              RasConvInt::upscale(y2));
248    }
249    /// Move to point (x,y)
250    ///
251    /// Sets point as the initial point
252    pub fn move_to_d(&mut self, x: f64, y: f64) {
253        self.x0 = RasConvInt::upscale( x );
254        self.y0 = RasConvInt::upscale( y );
255        self.clipper.move_to(self.x0,self.y0);
256        self.status = PathStatus::MoveTo;
257    }
258    /// Draw line from previous point to point (x,y)
259    pub fn line_to_d(&mut self, x: f64, y: f64) {
260        let x = RasConvInt::upscale( x );
261        let y = RasConvInt::upscale( y );
262        self.clipper.line_to(&mut self.outline, x,y);
263        self.status = PathStatus::LineTo;
264    }
265    /// Close the current polygon
266    ///
267    /// Draw a line from current point to initial "move to" point
268    pub fn close_polygon(&mut self) {
269        if self.status == PathStatus::LineTo {
270            self.clipper.line_to(&mut self.outline, self.x0, self.y0);
271            self.status = PathStatus::Closed;
272        }
273    }
274    /// Calculate alpha term based on area
275    ///
276    ///
277    pub fn calculate_alpha(&self, area: i64) -> u64 {
278        let aa_shift  = 8;
279        let aa_scale  = 1 << aa_shift;
280        let aa_scale2 = aa_scale * 2;
281        let aa_mask   = aa_scale  - 1;
282        let aa_mask2  = aa_scale2 - 1;
283
284        let mut cover = area >> (POLY_SUBPIXEL_SHIFT*2 + 1 - aa_shift);
285        cover = cover.abs();
286        if self.filling_rule == FillingRule::EvenOdd {
287            cover *= aa_mask2;
288            if cover > aa_scale {
289                cover = aa_scale2 - cover;
290            }
291        }
292        cover = max(0, min(cover, aa_mask));
293        self.gamma[cover as usize]
294    }
295}
296
297
298
299
300pub(crate) fn len_i64(a: &Vertex<i64>, b: &Vertex<i64>) -> i64 {
301    len_i64_xy(a.x, a.y, b.x, b.y)
302}
303pub(crate) fn len_i64_xy(x1: i64, y1: i64, x2: i64, y2: i64) -> i64 {
304    let dx = x1 as f64 - x2 as f64;
305    let dy = y1 as f64 - y2 as f64;
306    (dx*dx + dy*dy).sqrt().round() as i64
307}
308
309// #[derive(Debug,PartialEq,Copy,Clone)]
310// pub enum LineJoin {
311//     Round,
312//     None,
313//     Miter,
314//     MiterAccurate,
315// }