Anti-Grain Geometry Tutorial
agg_rasterizer_scanline_aa.h
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 //
12 // The author gratefully acknowleges the support of David Turner,
13 // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
14 // libray - in producing this work. See http://www.freetype.org for details.
15 //
16 //----------------------------------------------------------------------------
17 // Contact: mcseem@antigrain.com
18 // mcseemagg@yahoo.com
19 // http://www.antigrain.com
20 //----------------------------------------------------------------------------
21 //
22 // Adaptation for 32-bit screen coordinates has been sponsored by
23 // Liberty Technology Systems, Inc., visit http://lib-sys.com
24 //
25 // Liberty Technology Systems, Inc. is the provider of
26 // PostScript and PDF technology for software developers.
27 //
28 //----------------------------------------------------------------------------
29 #ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED
30 #define AGG_RASTERIZER_SCANLINE_AA_INCLUDED
31 
32 #include "agg_rasterizer_cells_aa.h"
33 #include "agg_rasterizer_sl_clip.h"
34 #include "agg_rasterizer_scanline_aa_nogamma.h"
35 #include "agg_gamma_functions.h"
36 
37 
38 namespace agg
39 {
40  //==================================================rasterizer_scanline_aa
41  // Polygon rasterizer that is used to render filled polygons with
42  // high-quality Anti-Aliasing. Internally, by default, the class uses
43  // integer coordinates in format 24.8, i.e. 24 bits for integer part
44  // and 8 bits for fractional - see poly_subpixel_shift. This class can be
45  // used in the following way:
46  //
47  // 1. filling_rule(filling_rule_e ft) - optional.
48  //
49  // 2. gamma() - optional.
50  //
51  // 3. reset()
52  //
53  // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create
54  // more than one contour, but each contour must consist of at least 3
55  // vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3);
56  // is the absolute minimum of vertices that define a triangle.
57  // The algorithm does not check either the number of vertices nor
58  // coincidence of their coordinates, but in the worst case it just
59  // won't draw anything.
60  // The orger of the vertices (clockwise or counterclockwise)
61  // is important when using the non-zero filling rule (fill_non_zero).
62  // In this case the vertex order of all the contours must be the same
63  // if you want your intersecting polygons to be without "holes".
64  // You actually can use different vertices order. If the contours do not
65  // intersect each other the order is not important anyway. If they do,
66  // contours with the same vertex order will be rendered without "holes"
67  // while the intersecting contours with different orders will have "holes".
68  //
69  // filling_rule() and gamma() can be called anytime before "sweeping".
70  //------------------------------------------------------------------------
71  template<class Clip=rasterizer_sl_clip_int> class rasterizer_scanline_aa
72  {
73  enum status
74  {
75  status_initial,
76  status_move_to,
77  status_line_to,
78  status_closed
79  };
80 
81  public:
82  typedef Clip clip_type;
83  typedef typename Clip::conv_type conv_type;
84  typedef typename Clip::coord_type coord_type;
85 
86  enum aa_scale_e
87  {
88  aa_shift = 8,
89  aa_scale = 1 << aa_shift,
90  aa_mask = aa_scale - 1,
91  aa_scale2 = aa_scale * 2,
92  aa_mask2 = aa_scale2 - 1
93  };
94 
95  //--------------------------------------------------------------------
96  rasterizer_scanline_aa(unsigned cell_block_limit=1024) :
97  m_outline(cell_block_limit),
98  m_clipper(),
99  m_filling_rule(fill_non_zero),
100  m_auto_close(true),
101  m_start_x(0),
102  m_start_y(0),
103  m_status(status_initial)
104  {
105  int i;
106  for(i = 0; i < aa_scale; i++) m_gamma[i] = i;
107  }
108 
109  //--------------------------------------------------------------------
110  template<class GammaF>
111  rasterizer_scanline_aa(const GammaF& gamma_function, unsigned cell_block_limit) :
112  m_outline(cell_block_limit),
113  m_clipper(m_outline),
114  m_filling_rule(fill_non_zero),
115  m_auto_close(true),
116  m_start_x(0),
117  m_start_y(0),
118  m_status(status_initial)
119  {
120  gamma(gamma_function);
121  }
122 
123  //--------------------------------------------------------------------
124  void reset();
125  void reset_clipping();
126  void clip_box(double x1, double y1, double x2, double y2);
127  void filling_rule(filling_rule_e filling_rule);
128  void auto_close(bool flag) { m_auto_close = flag; }
129 
130  //--------------------------------------------------------------------
131  template<class GammaF> void gamma(const GammaF& gamma_function)
132  {
133  int i;
134  for(i = 0; i < aa_scale; i++)
135  {
136  m_gamma[i] = uround(gamma_function(double(i) / aa_mask) * aa_mask);
137  }
138  }
139 
140  //--------------------------------------------------------------------
141  unsigned apply_gamma(unsigned cover) const
142  {
143  return m_gamma[cover];
144  }
145 
146  //--------------------------------------------------------------------
147  void move_to(int x, int y);
148  void line_to(int x, int y);
149  void move_to_d(double x, double y);
150  void line_to_d(double x, double y);
151  void close_polygon();
152  void add_vertex(double x, double y, unsigned cmd);
153 
154  void edge(int x1, int y1, int x2, int y2);
155  void edge_d(double x1, double y1, double x2, double y2);
156 
157  //-------------------------------------------------------------------
158  template<class VertexSource>
159  void add_path(VertexSource& vs, unsigned path_id=0)
160  {
161  double x;
162  double y;
163 
164  unsigned cmd;
165  vs.rewind(path_id);
166  if(m_outline.sorted()) reset();
167  while(!is_stop(cmd = vs.vertex(&x, &y)))
168  {
169  add_vertex(x, y, cmd);
170  }
171  }
172 
173  //--------------------------------------------------------------------
174  int min_x() const { return m_outline.min_x(); }
175  int min_y() const { return m_outline.min_y(); }
176  int max_x() const { return m_outline.max_x(); }
177  int max_y() const { return m_outline.max_y(); }
178 
179  //--------------------------------------------------------------------
180  void sort();
181  bool rewind_scanlines();
182  bool navigate_scanline(int y);
183 
184  //--------------------------------------------------------------------
185  AGG_INLINE unsigned calculate_alpha(int area) const
186  {
187  int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift);
188 
189  if(cover < 0) cover = -cover;
190  if(m_filling_rule == fill_even_odd)
191  {
192  cover &= aa_mask2;
193  if(cover > aa_scale)
194  {
195  cover = aa_scale2 - cover;
196  }
197  }
198  if(cover > aa_mask) cover = aa_mask;
199  return m_gamma[cover];
200  }
201 
202  //--------------------------------------------------------------------
203  template<class Scanline> bool sweep_scanline(Scanline& sl)
204  {
205  for(;;)
206  {
207  if(m_scan_y > m_outline.max_y()) return false;
208  sl.reset_spans();
209  unsigned num_cells = m_outline.scanline_num_cells(m_scan_y);
210  const cell_aa* const* cells = m_outline.scanline_cells(m_scan_y);
211  int cover = 0;
212 
213  while(num_cells)
214  {
215  const cell_aa* cur_cell = *cells;
216  int x = cur_cell->x;
217  int area = cur_cell->area;
218  unsigned alpha;
219 
220  cover += cur_cell->cover;
221 
222  //accumulate all cells with the same X
223  while(--num_cells)
224  {
225  cur_cell = *++cells;
226  if(cur_cell->x != x) break;
227  area += cur_cell->area;
228  cover += cur_cell->cover;
229  }
230 
231  if(area)
232  {
233  alpha = calculate_alpha((cover << (poly_subpixel_shift + 1)) - area);
234  if(alpha)
235  {
236  sl.add_cell(x, alpha);
237  }
238  x++;
239  }
240 
241  if(num_cells && cur_cell->x > x)
242  {
243  alpha = calculate_alpha(cover << (poly_subpixel_shift + 1));
244  if(alpha)
245  {
246  sl.add_span(x, cur_cell->x - x, alpha);
247  }
248  }
249  }
250 
251  if(sl.num_spans()) break;
252  ++m_scan_y;
253  }
254 
255  sl.finalize(m_scan_y);
256  ++m_scan_y;
257  return true;
258  }
259 
260  //--------------------------------------------------------------------
261  bool hit_test(int tx, int ty);
262 
263 
264  private:
265  //--------------------------------------------------------------------
266  // Disable copying
269  operator = (const rasterizer_scanline_aa<Clip>&);
270 
271  private:
273  clip_type m_clipper;
274  int m_gamma[aa_scale];
275  filling_rule_e m_filling_rule;
276  bool m_auto_close;
277  coord_type m_start_x;
278  coord_type m_start_y;
279  unsigned m_status;
280  int m_scan_y;
281  };
282 
283 
284 
285 
286 
287 
288 
289 
290 
291 
292 
293 
294  //------------------------------------------------------------------------
295  template<class Clip>
297  {
298  m_outline.reset();
299  m_status = status_initial;
300  }
301 
302  //------------------------------------------------------------------------
303  template<class Clip>
304  void rasterizer_scanline_aa<Clip>::filling_rule(filling_rule_e filling_rule)
305  {
306  m_filling_rule = filling_rule;
307  }
308 
309  //------------------------------------------------------------------------
310  template<class Clip>
311  void rasterizer_scanline_aa<Clip>::clip_box(double x1, double y1,
312  double x2, double y2)
313  {
314  reset();
315  m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1),
316  conv_type::upscale(x2), conv_type::upscale(y2));
317  }
318 
319  //------------------------------------------------------------------------
320  template<class Clip>
322  {
323  reset();
324  m_clipper.reset_clipping();
325  }
326 
327  //------------------------------------------------------------------------
328  template<class Clip>
330  {
331  if(m_status == status_line_to)
332  {
333  m_clipper.line_to(m_outline, m_start_x, m_start_y);
334  m_status = status_closed;
335  }
336  }
337 
338  //------------------------------------------------------------------------
339  template<class Clip>
340  void rasterizer_scanline_aa<Clip>::move_to(int x, int y)
341  {
342  if(m_outline.sorted()) reset();
343  if(m_auto_close) close_polygon();
344  m_clipper.move_to(m_start_x = conv_type::downscale(x),
345  m_start_y = conv_type::downscale(y));
346  m_status = status_move_to;
347  }
348 
349  //------------------------------------------------------------------------
350  template<class Clip>
351  void rasterizer_scanline_aa<Clip>::line_to(int x, int y)
352  {
353  m_clipper.line_to(m_outline,
354  conv_type::downscale(x),
355  conv_type::downscale(y));
356  m_status = status_line_to;
357  }
358 
359  //------------------------------------------------------------------------
360  template<class Clip>
361  void rasterizer_scanline_aa<Clip>::move_to_d(double x, double y)
362  {
363  if(m_outline.sorted()) reset();
364  if(m_auto_close) close_polygon();
365  m_clipper.move_to(m_start_x = conv_type::upscale(x),
366  m_start_y = conv_type::upscale(y));
367  m_status = status_move_to;
368  }
369 
370  //------------------------------------------------------------------------
371  template<class Clip>
372  void rasterizer_scanline_aa<Clip>::line_to_d(double x, double y)
373  {
374  m_clipper.line_to(m_outline,
375  conv_type::upscale(x),
376  conv_type::upscale(y));
377  m_status = status_line_to;
378  }
379 
380  //------------------------------------------------------------------------
381  template<class Clip>
382  void rasterizer_scanline_aa<Clip>::add_vertex(double x, double y, unsigned cmd)
383  {
384  if(is_move_to(cmd))
385  {
386  move_to_d(x, y);
387  }
388  else
389  if(is_vertex(cmd))
390  {
391  line_to_d(x, y);
392  }
393  else
394  if(is_close(cmd))
395  {
396  close_polygon();
397  }
398  }
399 
400  //------------------------------------------------------------------------
401  template<class Clip>
402  void rasterizer_scanline_aa<Clip>::edge(int x1, int y1, int x2, int y2)
403  {
404  if(m_outline.sorted()) reset();
405  m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1));
406  m_clipper.line_to(m_outline,
407  conv_type::downscale(x2),
408  conv_type::downscale(y2));
409  m_status = status_move_to;
410  }
411 
412  //------------------------------------------------------------------------
413  template<class Clip>
414  void rasterizer_scanline_aa<Clip>::edge_d(double x1, double y1,
415  double x2, double y2)
416  {
417  if(m_outline.sorted()) reset();
418  m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1));
419  m_clipper.line_to(m_outline,
420  conv_type::upscale(x2),
421  conv_type::upscale(y2));
422  m_status = status_move_to;
423  }
424 
425  //------------------------------------------------------------------------
426  template<class Clip>
428  {
429  if(m_auto_close) close_polygon();
430  m_outline.sort_cells();
431  }
432 
433  //------------------------------------------------------------------------
434  template<class Clip>
436  {
437  if(m_auto_close) close_polygon();
438  m_outline.sort_cells();
439  if(m_outline.total_cells() == 0)
440  {
441  return false;
442  }
443  m_scan_y = m_outline.min_y();
444  return true;
445  }
446 
447 
448  //------------------------------------------------------------------------
449  template<class Clip>
451  {
452  if(m_auto_close) close_polygon();
453  m_outline.sort_cells();
454  if(m_outline.total_cells() == 0 ||
455  y < m_outline.min_y() ||
456  y > m_outline.max_y())
457  {
458  return false;
459  }
460  m_scan_y = y;
461  return true;
462  }
463 
464  //------------------------------------------------------------------------
465  template<class Clip>
466  bool rasterizer_scanline_aa<Clip>::hit_test(int tx, int ty)
467  {
468  if(!navigate_scanline(ty)) return false;
469  scanline_hit_test sl(tx);
470  sweep_scanline(sl);
471  return sl.hit();
472  }
473 
474 
475 
476 }
477 
478 
479 
480 #endif
481 
Definition: agg_arc.cpp:24