Anti-Grain Geometry Tutorial
agg_rasterizer_compound_aa.h
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
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_COMPOUND_AA_INCLUDED
30 #define AGG_RASTERIZER_COMPOUND_AA_INCLUDED
31 
32 #include <limits>
33 #include "agg_rasterizer_cells_aa.h"
34 #include "agg_rasterizer_sl_clip.h"
35 
36 namespace agg
37 {
38 
39  //-----------------------------------------------------------cell_style_aa
40  // A pixel cell. There're no constructors defined and it was done
41  // intentionally in order to avoid extra overhead when allocating an
42  // array of cells.
44  {
45  int x;
46  int y;
47  int cover;
48  int area;
49  int16 left, right;
50 
51  void initial()
52  {
53  x = std::numeric_limits<int>::max();
54  y = std::numeric_limits<int>::max();
55  cover = 0;
56  area = 0;
57  left = -1;
58  right = -1;
59  }
60 
61  void style(const cell_style_aa& c)
62  {
63  left = c.left;
64  right = c.right;
65  }
66 
67  int not_equal(int ex, int ey, const cell_style_aa& c) const
68  {
69  return ((unsigned)ex - (unsigned)x) | ((unsigned)ey - (unsigned)y) |
70  ((unsigned)left - (unsigned)c.left) | ((unsigned)right - (unsigned)c.right);
71  }
72  };
73 
74 
75  //===========================================================layer_order_e
76  enum layer_order_e
77  {
78  layer_unsorted, //------layer_unsorted
79  layer_direct, //------layer_direct
80  layer_inverse //------layer_inverse
81  };
82 
83 
84  //==================================================rasterizer_compound_aa
85  template<class Clip=rasterizer_sl_clip_int> class rasterizer_compound_aa
86  {
87  struct style_info
88  {
89  unsigned start_cell;
90  unsigned num_cells;
91  int last_x;
92  };
93 
94  struct cell_info
95  {
96  int x, area, cover;
97  };
98 
99  public:
100  typedef Clip clip_type;
101  typedef typename Clip::conv_type conv_type;
102  typedef typename Clip::coord_type coord_type;
103 
104  enum aa_scale_e
105  {
106  aa_shift = 8,
107  aa_scale = 1 << aa_shift,
108  aa_mask = aa_scale - 1,
109  aa_scale2 = aa_scale * 2,
110  aa_mask2 = aa_scale2 - 1
111  };
112 
113  //--------------------------------------------------------------------
115  m_outline(),
116  m_clipper(),
117  m_filling_rule(fill_non_zero),
118  m_layer_order(layer_direct),
119  m_styles(), // Active Styles
120  m_ast(), // Active Style Table (unique values)
121  m_asm(), // Active Style Mask
122  m_cells(),
123  m_cover_buf(),
124  m_min_style(std::numeric_limits<int>::max()),
125  m_max_style(std::numeric_limits<int>::min()),
126  m_start_x(0),
127  m_start_y(0),
128  m_scan_y(std::numeric_limits<int>::max()),
129  m_sl_start(0),
130  m_sl_len(0)
131  {}
132 
133  //--------------------------------------------------------------------
134  void reset();
135  void reset_clipping();
136  void clip_box(double x1, double y1, double x2, double y2);
137  void filling_rule(filling_rule_e filling_rule);
138  void layer_order(layer_order_e order);
139 
140  //--------------------------------------------------------------------
141  void styles(int left, int right);
142  void move_to(int x, int y);
143  void line_to(int x, int y);
144  void move_to_d(double x, double y);
145  void line_to_d(double x, double y);
146  void add_vertex(double x, double y, unsigned cmd);
147 
148  void edge(int x1, int y1, int x2, int y2);
149  void edge_d(double x1, double y1, double x2, double y2);
150 
151  //-------------------------------------------------------------------
152  template<class VertexSource>
153  void add_path(VertexSource& vs, unsigned path_id=0)
154  {
155  double x;
156  double y;
157 
158  unsigned cmd;
159  vs.rewind(path_id);
160  if(m_outline.sorted()) reset();
161  while(!is_stop(cmd = vs.vertex(&x, &y)))
162  {
163  add_vertex(x, y, cmd);
164  }
165  }
166 
167 
168  //--------------------------------------------------------------------
169  int min_x() const { return m_outline.min_x(); }
170  int min_y() const { return m_outline.min_y(); }
171  int max_x() const { return m_outline.max_x(); }
172  int max_y() const { return m_outline.max_y(); }
173  int min_style() const { return m_min_style; }
174  int max_style() const { return m_max_style; }
175 
176  //--------------------------------------------------------------------
177  void sort();
178  bool rewind_scanlines();
179  unsigned sweep_styles();
180  int scanline_start() const { return m_sl_start; }
181  unsigned scanline_length() const { return m_sl_len; }
182  unsigned style(unsigned style_idx) const;
183 
184  cover_type* allocate_cover_buffer(unsigned len);
185 
186  //--------------------------------------------------------------------
187  bool navigate_scanline(int y);
188  bool hit_test(int tx, int ty);
189 
190  //--------------------------------------------------------------------
191  AGG_INLINE unsigned calculate_alpha(int area) const
192  {
193  int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift);
194  if(cover < 0) cover = -cover;
195  if(m_filling_rule == fill_even_odd)
196  {
197  cover &= aa_mask2;
198  if(cover > aa_scale)
199  {
200  cover = aa_scale2 - cover;
201  }
202  }
203  if(cover > aa_mask) cover = aa_mask;
204  return cover;
205  }
206 
207  //--------------------------------------------------------------------
208  // Sweeps one scanline with one style index. The style ID can be
209  // determined by calling style().
210  template<class Scanline> bool sweep_scanline(Scanline& sl, int style_idx)
211  {
212  int scan_y = m_scan_y - 1;
213  if(scan_y > m_outline.max_y()) return false;
214 
215  sl.reset_spans();
216 
217  if(style_idx < 0)
218  {
219  style_idx = 0;
220  }
221  else
222  {
223  style_idx++;
224  }
225 
226  const style_info& st = m_styles[m_ast[style_idx]];
227 
228  unsigned num_cells = st.num_cells;
229  cell_info* cell = &m_cells[st.start_cell];
230 
231  int cover = 0;
232  while(num_cells--)
233  {
234  unsigned alpha;
235  int x = cell->x;
236  int area = cell->area;
237 
238  cover += cell->cover;
239 
240  ++cell;
241 
242  if(area)
243  {
244  alpha = calculate_alpha((cover << (poly_subpixel_shift + 1)) - area);
245  sl.add_cell(x, alpha);
246  x++;
247  }
248 
249  if(num_cells && cell->x > x)
250  {
251  alpha = calculate_alpha(cover << (poly_subpixel_shift + 1));
252  if(alpha)
253  {
254  sl.add_span(x, cell->x - x, alpha);
255  }
256  }
257  }
258 
259  if(sl.num_spans() == 0) return false;
260  sl.finalize(scan_y);
261  return true;
262  }
263 
264  private:
265  void add_style(int style_id);
266 
267  //--------------------------------------------------------------------
268  // Disable copying
271  operator = (const rasterizer_compound_aa<Clip>&);
272 
273  private:
275  clip_type m_clipper;
276  filling_rule_e m_filling_rule;
277  layer_order_e m_layer_order;
278  pod_vector<style_info> m_styles; // Active Styles
279  pod_vector<unsigned> m_ast; // Active Style Table (unique values)
280  pod_vector<int8u> m_asm; // Active Style Mask
281  pod_vector<cell_info> m_cells;
282  pod_vector<cover_type> m_cover_buf;
283 
284  int m_min_style;
285  int m_max_style;
286  coord_type m_start_x;
287  coord_type m_start_y;
288  int m_scan_y;
289  int m_sl_start;
290  unsigned m_sl_len;
291  };
292 
293 
294 
295 
296 
297 
298 
299 
300 
301 
302  //------------------------------------------------------------------------
303  template<class Clip>
305  {
306  m_outline.reset();
307  m_min_style = std::numeric_limits<int>::max();
308  m_max_style = std::numeric_limits<int>::min();
309  m_scan_y = std::numeric_limits<int>::max();
310  m_sl_start = 0;
311  m_sl_len = 0;
312  }
313 
314  //------------------------------------------------------------------------
315  template<class Clip>
316  void rasterizer_compound_aa<Clip>::filling_rule(filling_rule_e filling_rule)
317  {
318  m_filling_rule = filling_rule;
319  }
320 
321  //------------------------------------------------------------------------
322  template<class Clip>
323  void rasterizer_compound_aa<Clip>::layer_order(layer_order_e order)
324  {
325  m_layer_order = order;
326  }
327 
328  //------------------------------------------------------------------------
329  template<class Clip>
330  void rasterizer_compound_aa<Clip>::clip_box(double x1, double y1,
331  double x2, double y2)
332  {
333  reset();
334  m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1),
335  conv_type::upscale(x2), conv_type::upscale(y2));
336  }
337 
338  //------------------------------------------------------------------------
339  template<class Clip>
341  {
342  reset();
343  m_clipper.reset_clipping();
344  }
345 
346  //------------------------------------------------------------------------
347  template<class Clip>
348  void rasterizer_compound_aa<Clip>::styles(int left, int right)
349  {
350  cell_style_aa cell;
351  cell.initial();
352  cell.left = (int16)left;
353  cell.right = (int16)right;
354  m_outline.style(cell);
355  if(left >= 0 && left < m_min_style) m_min_style = left;
356  if(left >= 0 && left > m_max_style) m_max_style = left;
357  if(right >= 0 && right < m_min_style) m_min_style = right;
358  if(right >= 0 && right > m_max_style) m_max_style = right;
359  }
360 
361  //------------------------------------------------------------------------
362  template<class Clip>
363  void rasterizer_compound_aa<Clip>::move_to(int x, int y)
364  {
365  if(m_outline.sorted()) reset();
366  m_clipper.move_to(m_start_x = conv_type::downscale(x),
367  m_start_y = conv_type::downscale(y));
368  }
369 
370  //------------------------------------------------------------------------
371  template<class Clip>
372  void rasterizer_compound_aa<Clip>::line_to(int x, int y)
373  {
374  m_clipper.line_to(m_outline,
375  conv_type::downscale(x),
376  conv_type::downscale(y));
377  }
378 
379  //------------------------------------------------------------------------
380  template<class Clip>
381  void rasterizer_compound_aa<Clip>::move_to_d(double x, double y)
382  {
383  if(m_outline.sorted()) reset();
384  m_clipper.move_to(m_start_x = conv_type::upscale(x),
385  m_start_y = conv_type::upscale(y));
386  }
387 
388  //------------------------------------------------------------------------
389  template<class Clip>
390  void rasterizer_compound_aa<Clip>::line_to_d(double x, double y)
391  {
392  m_clipper.line_to(m_outline,
393  conv_type::upscale(x),
394  conv_type::upscale(y));
395  }
396 
397  //------------------------------------------------------------------------
398  template<class Clip>
399  void rasterizer_compound_aa<Clip>::add_vertex(double x, double y, unsigned cmd)
400  {
401  if(is_move_to(cmd))
402  {
403  move_to_d(x, y);
404  }
405  else
406  if(is_vertex(cmd))
407  {
408  line_to_d(x, y);
409  }
410  else
411  if(is_close(cmd))
412  {
413  m_clipper.line_to(m_outline, m_start_x, m_start_y);
414  }
415  }
416 
417  //------------------------------------------------------------------------
418  template<class Clip>
419  void rasterizer_compound_aa<Clip>::edge(int x1, int y1, int x2, int y2)
420  {
421  if(m_outline.sorted()) reset();
422  m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1));
423  m_clipper.line_to(m_outline,
424  conv_type::downscale(x2),
425  conv_type::downscale(y2));
426  }
427 
428  //------------------------------------------------------------------------
429  template<class Clip>
430  void rasterizer_compound_aa<Clip>::edge_d(double x1, double y1,
431  double x2, double y2)
432  {
433  if(m_outline.sorted()) reset();
434  m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1));
435  m_clipper.line_to(m_outline,
436  conv_type::upscale(x2),
437  conv_type::upscale(y2));
438  }
439 
440  //------------------------------------------------------------------------
441  template<class Clip>
442  AGG_INLINE void rasterizer_compound_aa<Clip>::sort()
443  {
444  m_outline.sort_cells();
445  }
446 
447  //------------------------------------------------------------------------
448  template<class Clip>
450  {
451  m_outline.sort_cells();
452  if(m_outline.total_cells() == 0)
453  {
454  return false;
455  }
456  if(m_max_style < m_min_style)
457  {
458  return false;
459  }
460  m_scan_y = m_outline.min_y();
461  m_styles.allocate(m_max_style - m_min_style + 2, 128);
462  return true;
463  }
464 
465  //------------------------------------------------------------------------
466  template<class Clip>
467  AGG_INLINE void rasterizer_compound_aa<Clip>::add_style(int style_id)
468  {
469  if(style_id < 0) style_id = 0;
470  else style_id -= m_min_style - 1;
471 
472  unsigned nbyte = style_id >> 3;
473  unsigned mask = 1 << (style_id & 7);
474 
475  style_info* style = &m_styles[style_id];
476  if((m_asm[nbyte] & mask) == 0)
477  {
478  m_ast.add(style_id);
479  m_asm[nbyte] |= mask;
480  style->start_cell = 0;
481  style->num_cells = 0;
482  style->last_x = std::numeric_limits<int>::min();
483  }
484  ++style->start_cell;
485  }
486 
487  //------------------------------------------------------------------------
488  // Returns the number of styles
489  template<class Clip>
491  {
492  for(;;)
493  {
494  if(m_scan_y > m_outline.max_y()) return 0;
495  unsigned num_cells = m_outline.scanline_num_cells(m_scan_y);
496  const cell_style_aa* const* cells = m_outline.scanline_cells(m_scan_y);
497  unsigned num_styles = m_max_style - m_min_style + 2;
498  const cell_style_aa* curr_cell;
499  unsigned style_id;
500  style_info* style;
501  cell_info* cell;
502 
503  m_cells.allocate(num_cells * 2, 256); // Each cell can have two styles
504  m_ast.capacity(num_styles, 64);
505  m_asm.allocate((num_styles + 7) >> 3, 8);
506  m_asm.zero();
507 
508  if(num_cells)
509  {
510  // Pre-add zero (for no-fill style, that is, -1).
511  // We need that to ensure that the "-1 style" would go first.
512  m_asm[0] |= 1;
513  m_ast.add(0);
514  style = &m_styles[0];
515  style->start_cell = 0;
516  style->num_cells = 0;
517  style->last_x = std::numeric_limits<int>::min();
518 
519  m_sl_start = cells[0]->x;
520  m_sl_len = cells[num_cells-1]->x - m_sl_start + 1;
521  while(num_cells--)
522  {
523  curr_cell = *cells++;
524  add_style(curr_cell->left);
525  add_style(curr_cell->right);
526  }
527 
528  // Convert the Y-histogram into the array of starting indexes
529  unsigned i;
530  unsigned start_cell = 0;
531  for(i = 0; i < m_ast.size(); i++)
532  {
533  style_info& st = m_styles[m_ast[i]];
534  unsigned v = st.start_cell;
535  st.start_cell = start_cell;
536  start_cell += v;
537  }
538 
539  cells = m_outline.scanline_cells(m_scan_y);
540  num_cells = m_outline.scanline_num_cells(m_scan_y);
541 
542  while(num_cells--)
543  {
544  curr_cell = *cells++;
545  style_id = (curr_cell->left < 0) ? 0 :
546  curr_cell->left - m_min_style + 1;
547 
548  style = &m_styles[style_id];
549  if(curr_cell->x == style->last_x)
550  {
551  cell = &m_cells[style->start_cell + style->num_cells - 1];
552  cell->area += curr_cell->area;
553  cell->cover += curr_cell->cover;
554  }
555  else
556  {
557  cell = &m_cells[style->start_cell + style->num_cells];
558  cell->x = curr_cell->x;
559  cell->area = curr_cell->area;
560  cell->cover = curr_cell->cover;
561  style->last_x = curr_cell->x;
562  style->num_cells++;
563  }
564 
565  style_id = (curr_cell->right < 0) ? 0 :
566  curr_cell->right - m_min_style + 1;
567 
568  style = &m_styles[style_id];
569  if(curr_cell->x == style->last_x)
570  {
571  cell = &m_cells[style->start_cell + style->num_cells - 1];
572  cell->area -= curr_cell->area;
573  cell->cover -= curr_cell->cover;
574  }
575  else
576  {
577  cell = &m_cells[style->start_cell + style->num_cells];
578  cell->x = curr_cell->x;
579  cell->area = -curr_cell->area;
580  cell->cover = -curr_cell->cover;
581  style->last_x = curr_cell->x;
582  style->num_cells++;
583  }
584  }
585  }
586  if(m_ast.size() > 1) break;
587  ++m_scan_y;
588  }
589  ++m_scan_y;
590 
591  if(m_layer_order != layer_unsorted)
592  {
593  range_adaptor<pod_vector<unsigned> > ra(m_ast, 1, m_ast.size() - 1);
594  if(m_layer_order == layer_direct) quick_sort(ra, unsigned_greater);
595  else quick_sort(ra, unsigned_less);
596  }
597 
598  return m_ast.size() - 1;
599  }
600 
601  //------------------------------------------------------------------------
602  // Returns style ID depending of the existing style index
603  template<class Clip>
604  AGG_INLINE
605  unsigned rasterizer_compound_aa<Clip>::style(unsigned style_idx) const
606  {
607  return m_ast[style_idx + 1] + m_min_style - 1;
608  }
609 
610  //------------------------------------------------------------------------
611  template<class Clip>
613  {
614  m_outline.sort_cells();
615  if(m_outline.total_cells() == 0)
616  {
617  return false;
618  }
619  if(m_max_style < m_min_style)
620  {
621  return false;
622  }
623  if(y < m_outline.min_y() || y > m_outline.max_y())
624  {
625  return false;
626  }
627  m_scan_y = y;
628  m_styles.allocate(m_max_style - m_min_style + 2, 128);
629  return true;
630  }
631 
632  //------------------------------------------------------------------------
633  template<class Clip>
634  bool rasterizer_compound_aa<Clip>::hit_test(int tx, int ty)
635  {
636  if(!navigate_scanline(ty))
637  {
638  return false;
639  }
640 
641  unsigned num_styles = sweep_styles();
642  if(num_styles <= 0)
643  {
644  return false;
645  }
646 
647  scanline_hit_test sl(tx);
648  sweep_scanline(sl, -1);
649  return sl.hit();
650  }
651 
652  //------------------------------------------------------------------------
653  template<class Clip>
655  {
656  m_cover_buf.allocate(len, 256);
657  return &m_cover_buf[0];
658  }
659 
660 }
661 
662 
663 
664 #endif
665 
Definition: agg_arc.cpp:24