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