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 //-------------------------------------------------------------------- rasterizer_scanline_aa()96 rasterizer_scanline_aa() : 97 m_outline(), 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> rasterizer_scanline_aa(const GammaF & gamma_function)111 rasterizer_scanline_aa(const GammaF& gamma_function) : 112 m_outline(), 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); auto_close(bool flag)128 void auto_close(bool flag) { m_auto_close = flag; } 129 130 //-------------------------------------------------------------------- gamma(const GammaF & gamma_function)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 //-------------------------------------------------------------------- apply_gamma(unsigned cover)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 //-------------------------------------------------------------------- min_x()174 int min_x() const { return m_outline.min_x(); } min_y()175 int min_y() const { return m_outline.min_y(); } max_x()176 int max_x() const { return m_outline.max_x(); } max_y()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 //-------------------------------------------------------------------- calculate_alpha(int area)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 //-------------------------------------------------------------------- sweep_scanline(Scanline & sl)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 267 rasterizer_scanline_aa(const rasterizer_scanline_aa<Clip>&); 268 const rasterizer_scanline_aa<Clip>& 269 operator = (const rasterizer_scanline_aa<Clip>&); 270 271 private: 272 rasterizer_cells_aa<cell_aa> m_outline; 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> reset()296 void rasterizer_scanline_aa<Clip>::reset() 297 { 298 m_outline.reset(); 299 m_status = status_initial; 300 } 301 302 //------------------------------------------------------------------------ 303 template<class Clip> filling_rule(filling_rule_e filling_rule)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> clip_box(double x1,double y1,double x2,double y2)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> reset_clipping()321 void rasterizer_scanline_aa<Clip>::reset_clipping() 322 { 323 reset(); 324 m_clipper.reset_clipping(); 325 } 326 327 //------------------------------------------------------------------------ 328 template<class Clip> close_polygon()329 void rasterizer_scanline_aa<Clip>::close_polygon() 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> move_to(int x,int y)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> line_to(int x,int y)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> move_to_d(double x,double y)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> line_to_d(double x,double y)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> add_vertex(double x,double y,unsigned cmd)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> edge(int x1,int y1,int x2,int y2)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> edge_d(double x1,double y1,double x2,double y2)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> sort()427 void rasterizer_scanline_aa<Clip>::sort() 428 { 429 if(m_auto_close) close_polygon(); 430 m_outline.sort_cells(); 431 } 432 433 //------------------------------------------------------------------------ 434 template<class Clip> rewind_scanlines()435 AGG_INLINE bool rasterizer_scanline_aa<Clip>::rewind_scanlines() 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> navigate_scanline(int y)450 AGG_INLINE bool rasterizer_scanline_aa<Clip>::navigate_scanline(int y) 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> hit_test(int tx,int ty)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 482