1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
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 //----------------------------------------------------------------------------
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.
16 //----------------------------------------------------------------------------
17 // Contact: mcseem@antigrain.com
18 // mcseemagg@yahoo.com
19 // http://www.antigrain.com
20 //----------------------------------------------------------------------------
22 // Adaptation for 32-bit screen coordinates has been sponsored by
23 // Liberty Technology Systems, Inc., visit http://lib-sys.com
25 // Liberty Technology Systems, Inc. is the provider of
26 // PostScript and PDF technology for software developers.
28 //----------------------------------------------------------------------------
29 #ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED
30 #define AGG_RASTERIZER_SCANLINE_AA_INCLUDED
32 #include "agg_rasterizer_cells_aa.h"
33 #include "agg_rasterizer_sl_clip.h"
34 #include "agg_gamma_functions.h"
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
60 void style(const cell_aa
&) {}
62 int not_equal(int ex
, int ey
, const cell_aa
&) const
64 return (ex
- x
) | (ey
- y
);
69 //==================================================rasterizer_scanline_aa
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:
76 // 1. filling_rule(filling_rule_e ft) - optional.
78 // 2. gamma() - optional.
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".
98 // filling_rule() and gamma() can be called anytime before "sweeping".
99 //------------------------------------------------------------------------
100 template<class Clip
=rasterizer_sl_clip_int
> class rasterizer_scanline_aa
111 typedef Clip clip_type
;
112 typedef typename
Clip::conv_type conv_type
;
113 typedef typename
Clip::coord_type coord_type
;
118 aa_scale
= 1 << aa_shift
,
119 aa_mask
= aa_scale
- 1,
120 aa_scale2
= aa_scale
* 2,
121 aa_mask2
= aa_scale2
- 1
124 //--------------------------------------------------------------------
125 rasterizer_scanline_aa() :
128 m_filling_rule(fill_non_zero
),
132 m_status(status_initial
)
135 for(i
= 0; i
< aa_scale
; i
++) m_gamma
[i
] = i
;
138 //--------------------------------------------------------------------
139 template<class GammaF
>
140 rasterizer_scanline_aa(const GammaF
& gamma_function
) :
142 m_clipper(m_outline
),
143 m_filling_rule(fill_non_zero
),
147 m_status(status_initial
)
149 gamma(gamma_function
);
152 //--------------------------------------------------------------------
154 void reset_clipping();
155 void clip_box(double x1
, double y1
, double x2
, double y2
);
156 void filling_rule(filling_rule_e filling_rule
);
157 void auto_close(bool flag
) { m_auto_close
= flag
; }
159 //--------------------------------------------------------------------
160 template<class GammaF
> void gamma(const GammaF
& gamma_function
)
163 for(i
= 0; i
< aa_scale
; i
++)
165 m_gamma
[i
] = uround(gamma_function(double(i
) / aa_mask
) * aa_mask
);
169 //--------------------------------------------------------------------
170 unsigned apply_gamma(unsigned cover
) const
172 return m_gamma
[cover
];
175 //--------------------------------------------------------------------
176 void move_to(int x
, int y
);
177 void line_to(int x
, int y
);
178 void move_to_d(double x
, double y
);
179 void line_to_d(double x
, double y
);
180 void close_polygon();
181 void add_vertex(double x
, double y
, unsigned cmd
);
183 void edge(int x1
, int y1
, int x2
, int y2
);
184 void edge_d(double x1
, double y1
, double x2
, double y2
);
186 //-------------------------------------------------------------------
187 template<class VertexSource
>
188 void add_path(VertexSource
& vs
, unsigned path_id
=0)
195 if(m_outline
.sorted()) reset();
196 while(!is_stop(cmd
= vs
.vertex(&x
, &y
)))
198 add_vertex(x
, y
, cmd
);
202 //--------------------------------------------------------------------
203 int min_x() const { return m_outline
.min_x(); }
204 int min_y() const { return m_outline
.min_y(); }
205 int max_x() const { return m_outline
.max_x(); }
206 int max_y() const { return m_outline
.max_y(); }
208 //--------------------------------------------------------------------
210 bool rewind_scanlines();
211 bool navigate_scanline(int y
);
213 //--------------------------------------------------------------------
214 AGG_INLINE
unsigned calculate_alpha(int area
) const
216 int cover
= area
>> (poly_subpixel_shift
*2 + 1 - aa_shift
);
218 if(cover
< 0) cover
= -cover
;
219 if(m_filling_rule
== fill_even_odd
)
224 cover
= aa_scale2
- cover
;
227 if(cover
> aa_mask
) cover
= aa_mask
;
228 return m_gamma
[cover
];
231 //--------------------------------------------------------------------
232 template<class Scanline
> bool sweep_scanline(Scanline
& sl
)
236 if(m_scan_y
> m_outline
.max_y()) return false;
238 unsigned num_cells
= m_outline
.scanline_num_cells(m_scan_y
);
239 const cell_aa
* const* cells
= m_outline
.scanline_cells(m_scan_y
);
244 const cell_aa
* cur_cell
= *cells
;
246 int area
= cur_cell
->area
;
249 cover
+= cur_cell
->cover
;
251 //accumulate all cells with the same X
255 if(cur_cell
->x
!= x
) break;
256 area
+= cur_cell
->area
;
257 cover
+= cur_cell
->cover
;
262 alpha
= calculate_alpha((cover
<< (poly_subpixel_shift
+ 1)) - area
);
265 sl
.add_cell(x
, alpha
);
270 if(num_cells
&& cur_cell
->x
> x
)
272 alpha
= calculate_alpha(cover
<< (poly_subpixel_shift
+ 1));
275 sl
.add_span(x
, cur_cell
->x
- x
, alpha
);
280 if(sl
.num_spans()) break;
284 sl
.finalize(m_scan_y
);
289 //--------------------------------------------------------------------
290 bool hit_test(int tx
, int ty
);
294 //--------------------------------------------------------------------
296 rasterizer_scanline_aa(const rasterizer_scanline_aa
<Clip
>&);
297 const rasterizer_scanline_aa
<Clip
>&
298 operator = (const rasterizer_scanline_aa
<Clip
>&);
301 rasterizer_cells_aa
<cell_aa
> m_outline
;
303 int m_gamma
[aa_scale
];
304 filling_rule_e m_filling_rule
;
306 coord_type m_start_x
;
307 coord_type m_start_y
;
323 //------------------------------------------------------------------------
325 void rasterizer_scanline_aa
<Clip
>::reset()
328 m_status
= status_initial
;
331 //------------------------------------------------------------------------
333 void rasterizer_scanline_aa
<Clip
>::filling_rule(filling_rule_e filling_rule
)
335 m_filling_rule
= filling_rule
;
338 //------------------------------------------------------------------------
340 void rasterizer_scanline_aa
<Clip
>::clip_box(double x1
, double y1
,
341 double x2
, double y2
)
344 m_clipper
.clip_box(conv_type::upscale(x1
), conv_type::upscale(y1
),
345 conv_type::upscale(x2
), conv_type::upscale(y2
));
348 //------------------------------------------------------------------------
350 void rasterizer_scanline_aa
<Clip
>::reset_clipping()
353 m_clipper
.reset_clipping();
356 //------------------------------------------------------------------------
358 void rasterizer_scanline_aa
<Clip
>::close_polygon()
360 if(m_status
== status_line_to
)
362 m_clipper
.line_to(m_outline
, m_start_x
, m_start_y
);
363 m_status
= status_closed
;
367 //------------------------------------------------------------------------
369 void rasterizer_scanline_aa
<Clip
>::move_to(int x
, int y
)
371 if(m_outline
.sorted()) reset();
372 if(m_auto_close
) close_polygon();
373 m_clipper
.move_to(m_start_x
= conv_type::downscale(x
),
374 m_start_y
= conv_type::downscale(y
));
375 m_status
= status_move_to
;
378 //------------------------------------------------------------------------
380 void rasterizer_scanline_aa
<Clip
>::line_to(int x
, int y
)
382 m_clipper
.line_to(m_outline
,
383 conv_type::downscale(x
),
384 conv_type::downscale(y
));
385 m_status
= status_line_to
;
388 //------------------------------------------------------------------------
390 void rasterizer_scanline_aa
<Clip
>::move_to_d(double x
, double y
)
392 if(m_outline
.sorted()) reset();
393 if(m_auto_close
) close_polygon();
394 m_clipper
.move_to(m_start_x
= conv_type::upscale(x
),
395 m_start_y
= conv_type::upscale(y
));
396 m_status
= status_move_to
;
399 //------------------------------------------------------------------------
401 void rasterizer_scanline_aa
<Clip
>::line_to_d(double x
, double y
)
403 m_clipper
.line_to(m_outline
,
404 conv_type::upscale(x
),
405 conv_type::upscale(y
));
406 m_status
= status_line_to
;
409 //------------------------------------------------------------------------
411 void rasterizer_scanline_aa
<Clip
>::add_vertex(double x
, double y
, unsigned cmd
)
429 //------------------------------------------------------------------------
431 void rasterizer_scanline_aa
<Clip
>::edge(int x1
, int y1
, int x2
, int y2
)
433 if(m_outline
.sorted()) reset();
434 m_clipper
.move_to(conv_type::downscale(x1
), conv_type::downscale(y1
));
435 m_clipper
.line_to(m_outline
,
436 conv_type::downscale(x2
),
437 conv_type::downscale(y2
));
438 m_status
= status_move_to
;
441 //------------------------------------------------------------------------
443 void rasterizer_scanline_aa
<Clip
>::edge_d(double x1
, double y1
,
444 double x2
, double y2
)
446 if(m_outline
.sorted()) reset();
447 m_clipper
.move_to(conv_type::upscale(x1
), conv_type::upscale(y1
));
448 m_clipper
.line_to(m_outline
,
449 conv_type::upscale(x2
),
450 conv_type::upscale(y2
));
451 m_status
= status_move_to
;
454 //------------------------------------------------------------------------
456 void rasterizer_scanline_aa
<Clip
>::sort()
458 m_outline
.sort_cells();
461 //------------------------------------------------------------------------
463 AGG_INLINE
bool rasterizer_scanline_aa
<Clip
>::rewind_scanlines()
465 if(m_auto_close
) close_polygon();
466 m_outline
.sort_cells();
467 if(m_outline
.total_cells() == 0)
471 m_scan_y
= m_outline
.min_y();
476 //------------------------------------------------------------------------
478 AGG_INLINE
bool rasterizer_scanline_aa
<Clip
>::navigate_scanline(int y
)
480 if(m_auto_close
) close_polygon();
481 m_outline
.sort_cells();
482 if(m_outline
.total_cells() == 0 ||
483 y
< m_outline
.min_y() ||
484 y
> m_outline
.max_y())
492 //------------------------------------------------------------------------
494 bool rasterizer_scanline_aa
<Clip
>::hit_test(int tx
, int ty
)
496 if(!navigate_scanline(ty
)) return false;
497 scanline_hit_test
sl(tx
);