1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
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.
10 // The author gratefully acknowleges the support of David Turner,
11 // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
12 // libray - in producing this work. See http://www.freetype.org for details.
14 //----------------------------------------------------------------------------
15 // Contact: mcseem@antigrain.com
16 // mcseemagg@yahoo.com
17 // http://www.antigrain.com
18 //----------------------------------------------------------------------------
20 // Class rasterizer_scanline_aa
23 //----------------------------------------------------------------------------
24 #ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED
25 #define AGG_RASTERIZER_SCANLINE_AA_INCLUDED
29 #include "agg_basics.h"
31 #include "agg_gamma_functions.h"
32 #include "agg_clip_liang_barsky.h"
33 #include "agg_render_scanlines.h"
39 //------------------------------------------------------------------------
40 // These constants determine the subpixel accuracy, to be more precise,
41 // the number of bits of the fractional part of the coordinates.
42 // The possible coordinate capacity in bits can be calculated by formula:
43 // sizeof(int) * 8 - poly_base_shift * 2, i.e, for 32-bit integers and
44 // 8-bits fractional part the capacity is 16 bits or [-32768...32767].
47 poly_base_shift
= 8, //----poly_base_shift
48 poly_base_size
= 1 << poly_base_shift
, //----poly_base_size
49 poly_base_mask
= poly_base_size
- 1 //----poly_base_mask
52 //--------------------------------------------------------------poly_coord
53 inline int poly_coord(double c
)
55 return int(c
* poly_base_size
);
58 //-----------------------------------------------------------------cell_aa
59 // A pixel cell. There're no constructors defined and it was done
60 // intentionally in order to avoid extra overhead when allocating an
70 void set(int x
, int y
, int c
, int a
);
71 void set_coord(int x
, int y
);
72 void set_cover(int c
, int a
);
73 void add_cover(int c
, int a
);
77 //--------------------------------------------------------------outline_aa
78 // An internal class that implements the main rasterization algorithm.
79 // Used in the rasterizer. Should not be used direcly.
84 cell_block_shift
= 12,
85 cell_block_size
= 1 << cell_block_shift
,
86 cell_block_mask
= cell_block_size
- 1,
87 cell_block_pool
= 256,
88 cell_block_limit
= 1024
98 void move_to(int x
, int y
);
99 void line_to(int x
, int y
);
101 int min_x() const { return m_min_x
; }
102 int min_y() const { return m_min_y
; }
103 int max_x() const { return m_max_x
; }
104 int max_y() const { return m_max_y
; }
106 const cell_aa
* const* cells();
107 unsigned num_cells() { cells(); return m_num_cells
; }
108 bool sorted() const { return m_sorted
; }
111 outline_aa(const outline_aa
&);
112 const outline_aa
& operator = (const outline_aa
&);
114 void set_cur_cell(int x
, int y
);
117 void render_hline(int ey
, int x1
, int y1
, int x2
, int y2
);
118 void render_line(int x1
, int y1
, int x2
, int y2
);
119 void allocate_block();
121 static void qsort_cells(cell_aa
** start
, unsigned num
);
124 unsigned m_num_blocks
;
125 unsigned m_max_blocks
;
126 unsigned m_cur_block
;
127 unsigned m_num_cells
;
129 cell_aa
* m_cur_cell_ptr
;
130 cell_aa
** m_sorted_cells
;
131 unsigned m_sorted_size
;
143 //----------------------------------------------------------filling_rule_e
151 //==================================================rasterizer_scanline_aa
152 // Polygon rasterizer that is used to render filled polygons with
153 // high-quality Anti-Aliasing. Internally, by default, the class uses
154 // integer coordinates in format 24.8, i.e. 24 bits for integer part
155 // and 8 bits for fractional - see poly_base_shift. This class can be
156 // used in the following way:
158 // 1. filling_rule(filling_rule_e ft) - optional.
160 // 2. gamma() - optional.
164 // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create
165 // more than one contour, but each contour must consist of at least 3
166 // vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3);
167 // is the absolute minimum of vertices that define a triangle.
168 // The algorithm does not check either the number of vertices nor
169 // coincidence of their coordinates, but in the worst case it just
170 // won't draw anything.
171 // The orger of the vertices (clockwise or counterclockwise)
172 // is important when using the non-zero filling rule (fill_non_zero).
173 // In this case the vertex order of all the contours must be the same
174 // if you want your intersecting polygons to be without "holes".
175 // You actually can use different vertices order. If the contours do not
176 // intersect each other the order is not important anyway. If they do,
177 // contours with the same vertex order will be rendered without "holes"
178 // while the intersecting contours with different orders will have "holes".
180 // filling_rule() and gamma() can be called anytime before "sweeping".
181 //------------------------------------------------------------------------
182 template<unsigned XScale
=1, unsigned AA_Shift
=8> class rasterizer_scanline_aa
193 const cell_aa
* const* cells
;
202 aa_num
= 1 << aa_shift
,
203 aa_mask
= aa_num
- 1,
204 aa_2num
= aa_num
* 2,
205 aa_2mask
= aa_2num
- 1
208 //--------------------------------------------------------------------
209 rasterizer_scanline_aa() :
210 m_filling_rule(fill_non_zero
),
211 m_clipped_start_x(0),
212 m_clipped_start_y(0),
218 m_status(status_initial
),
222 for(i
= 0; i
< aa_num
; i
++) m_gamma
[i
] = i
;
225 //--------------------------------------------------------------------
226 template<class GammaF
>
227 rasterizer_scanline_aa(const GammaF
& gamma_function
) :
228 m_filling_rule(fill_non_zero
),
229 m_clipped_start_x(0),
230 m_clipped_start_y(0),
236 m_status(status_initial
),
239 gamma(gamma_function
);
242 //--------------------------------------------------------------------
244 void filling_rule(filling_rule_e filling_rule
);
245 void clip_box(double x1
, double y1
, double x2
, double y2
);
246 void reset_clipping();
248 //--------------------------------------------------------------------
249 template<class GammaF
> void gamma(const GammaF
& gamma_function
)
252 for(i
= 0; i
< aa_num
; i
++)
254 m_gamma
[i
] = int(floor(gamma_function(double(i
) / aa_mask
) * aa_mask
+ 0.5));
258 //--------------------------------------------------------------------
259 unsigned apply_gamma(unsigned cover
) const
261 return m_gamma
[cover
];
264 //--------------------------------------------------------------------
265 void add_vertex(double x
, double y
, unsigned cmd
);
266 void move_to(int x
, int y
);
267 void line_to(int x
, int y
);
268 void close_polygon();
269 void move_to_d(double x
, double y
);
270 void line_to_d(double x
, double y
);
272 //--------------------------------------------------------------------
273 int min_x() const { return m_outline
.min_x(); }
274 int min_y() const { return m_outline
.min_y(); }
275 int max_x() const { return m_outline
.max_x(); }
276 int max_y() const { return m_outline
.max_y(); }
278 //--------------------------------------------------------------------
279 AGG_INLINE
unsigned calculate_alpha(int area
) const
281 int cover
= area
>> (poly_base_shift
*2 + 1 - aa_shift
);
283 if(cover
< 0) cover
= -cover
;
284 if(m_filling_rule
== fill_even_odd
)
289 cover
= aa_2num
- cover
;
292 if(cover
> aa_mask
) cover
= aa_mask
;
293 return m_gamma
[cover
];
296 //--------------------------------------------------------------------
303 //--------------------------------------------------------------------
304 bool rewind_scanlines()
307 m_iterator
.cells
= m_outline
.cells();
308 if(m_outline
.num_cells() == 0)
312 m_iterator
.cover
= 0;
313 m_iterator
.last_y
= (*m_iterator
.cells
)->y
;
318 //--------------------------------------------------------------------
319 template<class Scanline
> bool sweep_scanline(Scanline
& sl
)
324 const cell_aa
* cur_cell
= *m_iterator
.cells
;
325 if(cur_cell
== 0) return false;
327 m_iterator
.last_y
= cur_cell
->y
;
331 int coord
= cur_cell
->packed_coord
;
332 int area
= cur_cell
->area
;
333 int last_x
= cur_cell
->x
;
335 m_iterator
.cover
+= cur_cell
->cover
;
337 //accumulate all cells with the same coordinates
338 for(; (cur_cell
= *m_iterator
.cells
) != 0; ++m_iterator
.cells
)
340 if(cur_cell
->packed_coord
!= coord
) break;
341 area
+= cur_cell
->area
;
342 m_iterator
.cover
+= cur_cell
->cover
;
346 if(cur_cell
== 0 || cur_cell
->y
!= m_iterator
.last_y
)
351 alpha
= calculate_alpha((m_iterator
.cover
<< (poly_base_shift
+ 1)) - area
);
354 sl
.add_cell(last_x
, alpha
);
365 alpha
= calculate_alpha((m_iterator
.cover
<< (poly_base_shift
+ 1)) - area
);
368 sl
.add_cell(last_x
, alpha
);
373 if(cur_cell
->x
> last_x
)
375 alpha
= calculate_alpha(m_iterator
.cover
<< (poly_base_shift
+ 1));
378 sl
.add_span(last_x
, cur_cell
->x
- last_x
, alpha
);
384 sl
.finalize(m_iterator
.last_y
);
392 //--------------------------------------------------------------------
393 bool hit_test(int tx
, int ty
);
396 //--------------------------------------------------------------------
397 void add_xy(const double* x
, const double* y
, unsigned n
)
401 move_to_d(*x
++, *y
++);
405 line_to_d(*x
++, *y
++);
411 //-------------------------------------------------------------------
412 template<class VertexSource
>
413 void add_path(VertexSource
& vs
, unsigned id
=0)
420 while(!is_stop(cmd
= vs
.vertex(&x
, &y
)))
422 add_vertex(x
, y
, cmd
);
428 //--------------------------------------------------------------------
430 rasterizer_scanline_aa(const rasterizer_scanline_aa
<XScale
, AA_Shift
>&);
431 const rasterizer_scanline_aa
<XScale
, AA_Shift
>&
432 operator = (const rasterizer_scanline_aa
<XScale
, AA_Shift
>&);
434 //--------------------------------------------------------------------
435 void move_to_no_clip(int x
, int y
);
436 void line_to_no_clip(int x
, int y
);
437 void close_polygon_no_clip();
438 void clip_segment(int x
, int y
);
441 outline_aa m_outline
;
443 filling_rule_e m_filling_rule
;
444 int m_clipped_start_x
;
445 int m_clipped_start_y
;
450 unsigned m_prev_flags
;
466 //------------------------------------------------------------------------
467 template<unsigned XScale
, unsigned AA_Shift
>
468 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::reset()
471 m_status
= status_initial
;
474 //------------------------------------------------------------------------
475 template<unsigned XScale
, unsigned AA_Shift
>
476 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::filling_rule(filling_rule_e _filling_rule
)
478 m_filling_rule
= _filling_rule
;
481 //------------------------------------------------------------------------
482 template<unsigned XScale
, unsigned AA_Shift
>
483 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::clip_box(double x1
, double y1
, double x2
, double y2
)
486 m_clip_box
= rect(poly_coord(x1
), poly_coord(y1
),
487 poly_coord(x2
), poly_coord(y2
));
488 m_clip_box
.normalize();
492 //------------------------------------------------------------------------
493 template<unsigned XScale
, unsigned AA_Shift
>
494 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::reset_clipping()
502 //------------------------------------------------------------------------
503 template<unsigned XScale
, unsigned AA_Shift
>
504 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::move_to_no_clip(int x
, int y
)
506 if(m_status
== status_line_to
)
508 close_polygon_no_clip();
510 m_outline
.move_to(x
* XScale
, y
);
511 m_clipped_start_x
= x
;
512 m_clipped_start_y
= y
;
513 m_status
= status_line_to
;
517 //------------------------------------------------------------------------
518 template<unsigned XScale
, unsigned AA_Shift
>
519 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::line_to_no_clip(int x
, int y
)
521 if(m_status
!= status_initial
)
523 m_outline
.line_to(x
* XScale
, y
);
524 m_status
= status_line_to
;
529 //------------------------------------------------------------------------
530 template<unsigned XScale
, unsigned AA_Shift
>
531 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::close_polygon_no_clip()
533 if(m_status
== status_line_to
)
535 m_outline
.line_to(m_clipped_start_x
* XScale
, m_clipped_start_y
);
536 m_status
= status_closed
;
541 //------------------------------------------------------------------------
542 template<unsigned XScale
, unsigned AA_Shift
>
543 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::clip_segment(int x
, int y
)
545 unsigned flags
= clipping_flags(x
, y
, m_clip_box
);
546 if(m_prev_flags
== flags
)
550 if(m_status
== status_initial
)
552 move_to_no_clip(x
, y
);
556 line_to_no_clip(x
, y
);
564 unsigned n
= clip_liang_barsky(m_prev_x
, m_prev_y
,
572 if(m_status
== status_initial
)
574 move_to_no_clip(*px
++, *py
++);
578 line_to_no_clip(*px
++, *py
++);
582 m_prev_flags
= flags
;
589 //------------------------------------------------------------------------
590 template<unsigned XScale
, unsigned AA_Shift
>
591 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::add_vertex(double x
, double y
, unsigned cmd
)
601 move_to(poly_coord(x
), poly_coord(y
));
607 line_to(poly_coord(x
), poly_coord(y
));
615 //------------------------------------------------------------------------
616 template<unsigned XScale
, unsigned AA_Shift
>
617 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::move_to(int x
, int y
)
621 if(m_outline
.sorted())
625 if(m_status
== status_line_to
)
629 m_prev_x
= m_start_x
= x
;
630 m_prev_y
= m_start_y
= y
;
631 m_status
= status_initial
;
632 m_prev_flags
= clipping_flags(x
, y
, m_clip_box
);
633 if(m_prev_flags
== 0)
635 move_to_no_clip(x
, y
);
640 move_to_no_clip(x
, y
);
644 //------------------------------------------------------------------------
645 template<unsigned XScale
, unsigned AA_Shift
>
646 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::line_to(int x
, int y
)
654 line_to_no_clip(x
, y
);
658 //------------------------------------------------------------------------
659 template<unsigned XScale
, unsigned AA_Shift
>
660 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::close_polygon()
664 clip_segment(m_start_x
, m_start_y
);
666 close_polygon_no_clip();
669 //------------------------------------------------------------------------
670 template<unsigned XScale
, unsigned AA_Shift
>
671 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::move_to_d(double x
, double y
)
673 move_to(poly_coord(x
), poly_coord(y
));
676 //------------------------------------------------------------------------
677 template<unsigned XScale
, unsigned AA_Shift
>
678 void rasterizer_scanline_aa
<XScale
, AA_Shift
>::line_to_d(double x
, double y
)
680 line_to(poly_coord(x
), poly_coord(y
));
684 //------------------------------------------------------------------------
685 template<unsigned XScale
, unsigned AA_Shift
>
686 bool rasterizer_scanline_aa
<XScale
, AA_Shift
>::hit_test(int tx
, int ty
)
689 const cell_aa
* const* cells
= m_outline
.cells();
690 if(m_outline
.num_cells() == 0) return false;
694 const cell_aa
* cur_cell
= *cells
++;
698 int coord
= cur_cell
->packed_coord
;
702 if(y
> ty
) return false;
704 int area
= cur_cell
->area
;
705 cover
+= cur_cell
->cover
;
707 while((cur_cell
= *cells
++) != 0)
709 if(cur_cell
->packed_coord
!= coord
) break;
710 area
+= cur_cell
->area
;
711 cover
+= cur_cell
->cover
;
716 alpha
= calculate_alpha((cover
<< (poly_base_shift
+ 1)) - area
);
719 if(tx
== x
&& ty
== y
) return true;
728 alpha
= calculate_alpha(cover
<< (poly_base_shift
+ 1));
731 if(ty
== y
&& tx
>= x
&& tx
<= cur_cell
->x
) return true;