1 /* 2 * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 * 5 * Copyright 2002-2004 Maxim Shemanarev (http://www.antigrain.com) 6 * 7 * 8 */ 9 10 #ifndef AGG_RASTERIZER_SCANLINE_AA_SUBPIX_INCLUDED 11 #define AGG_RASTERIZER_SCANLINE_AA_SUBPIX_INCLUDED 12 13 #include "agg_rasterizer_cells_aa.h" 14 #include "agg_rasterizer_sl_clip.h" 15 #include "agg_gamma_functions.h" 16 17 18 namespace agg 19 { 20 template<class Clip=rasterizer_sl_clip_int> class rasterizer_scanline_aa_subpix 21 { 22 enum status 23 { 24 status_initial, 25 status_move_to, 26 status_line_to, 27 status_closed 28 }; 29 30 public: 31 typedef Clip clip_type; 32 typedef typename Clip::conv_type conv_type; 33 typedef typename Clip::coord_type coord_type; 34 35 enum aa_scale_e 36 { 37 aa_shift = 8, 38 aa_scale = 1 << aa_shift, 39 aa_mask = aa_scale - 1, 40 aa_scale2 = aa_scale * 2, 41 aa_mask2 = aa_scale2 - 1 42 }; 43 44 //-------------------------------------------------------------------- 45 rasterizer_scanline_aa_subpix() : 46 m_outline(), 47 m_clipper(), 48 m_filling_rule(fill_non_zero), 49 m_auto_close(true), 50 m_start_x(0), 51 m_start_y(0), 52 m_status(status_initial) 53 { 54 int i; 55 for(i = 0; i < aa_scale; i++) m_gamma[i] = i; 56 } 57 58 //-------------------------------------------------------------------- 59 template<class GammaF> 60 rasterizer_scanline_aa_subpix(const GammaF& gamma_function) : 61 m_outline(), 62 m_clipper(m_outline), 63 m_filling_rule(fill_non_zero), 64 m_auto_close(true), 65 m_start_x(0), 66 m_start_y(0), 67 m_status(status_initial) 68 { 69 gamma(gamma_function); 70 } 71 72 //-------------------------------------------------------------------- 73 void reset(); 74 void reset_clipping(); 75 void clip_box(double x1, double y1, double x2, double y2); 76 void filling_rule(filling_rule_e filling_rule); 77 void auto_close(bool flag) { m_auto_close = flag; } 78 79 //-------------------------------------------------------------------- 80 template<class GammaF> void gamma(const GammaF& gamma_function) 81 { 82 int i; 83 for(i = 0; i < aa_scale; i++) 84 { 85 m_gamma[i] = uround(gamma_function(double(i) / aa_mask) * aa_mask); 86 } 87 } 88 89 //-------------------------------------------------------------------- 90 unsigned apply_gamma(unsigned cover) const 91 { 92 return m_gamma[cover]; 93 } 94 95 //-------------------------------------------------------------------- 96 void move_to(int x, int y); 97 void line_to(int x, int y); 98 void move_to_d(double x, double y); 99 void line_to_d(double x, double y); 100 void close_polygon(); 101 void add_vertex(double x, double y, unsigned cmd); 102 103 void edge(int x1, int y1, int x2, int y2); 104 void edge_d(double x1, double y1, double x2, double y2); 105 106 //------------------------------------------------------------------- 107 template<class VertexSource> 108 void add_path(VertexSource& vs, unsigned path_id=0) 109 { 110 double x = 0; 111 double y = 0; 112 113 unsigned cmd; 114 vs.rewind(path_id); 115 if(m_outline.sorted()) reset(); 116 while(!is_stop(cmd = vs.vertex(&x, &y))) 117 { 118 if (is_vertex(cmd)) { 119 x *= 3; 120 } 121 add_vertex(x, y, cmd); 122 } 123 } 124 125 //-------------------------------------------------------------------- 126 int min_x() const { return m_outline.min_x() / 3; } 127 int min_y() const { return m_outline.min_y(); } 128 int max_x() const { return m_outline.max_x() / 3; } 129 int max_y() const { return m_outline.max_y(); } 130 131 //-------------------------------------------------------------------- 132 void sort(); 133 bool rewind_scanlines(); 134 bool navigate_scanline(int y); 135 136 //-------------------------------------------------------------------- 137 AGG_INLINE unsigned calculate_alpha(int area) const 138 { 139 int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift); 140 141 if(cover < 0) cover = -cover; 142 if(m_filling_rule == fill_even_odd) 143 { 144 cover &= aa_mask2; 145 if(cover > aa_scale) 146 { 147 cover = aa_scale2 - cover; 148 } 149 } 150 if(cover > aa_mask) cover = aa_mask; 151 return m_gamma[cover]; 152 } 153 154 //-------------------------------------------------------------------- 155 template<class Scanline> bool sweep_scanline(Scanline& sl) 156 { 157 for(;;) 158 { 159 if(m_scan_y > m_outline.max_y()) return false; 160 sl.reset_spans(); 161 unsigned num_cells = m_outline.scanline_num_cells(m_scan_y); 162 const cell_aa* const* cells = m_outline.scanline_cells(m_scan_y); 163 int cover = 0; 164 int cover2 = 0; 165 int cover3 = 0; 166 167 while(num_cells) 168 { 169 const cell_aa* cur_cell = *cells; 170 int x = cur_cell->x; 171 int area1 = cur_cell->area; 172 int area2; 173 int area3; 174 unsigned alpha1; 175 unsigned alpha2; 176 unsigned alpha3; 177 178 int last_cover = cover3; 179 cover = cover3; 180 cover += cur_cell->cover; 181 182 while(--num_cells) 183 { 184 cur_cell = *++cells; 185 if(cur_cell->x != x) break; 186 area1 += cur_cell->area; 187 cover += cur_cell->cover; 188 } 189 190 if (x % 3 == 0) 191 { 192 if (cur_cell->x == x + 1) 193 { 194 area2 = cur_cell->area; 195 cover2 = cover + cur_cell->cover; 196 197 while (--num_cells) 198 { 199 cur_cell = *++cells; 200 if (cur_cell->x != x+1) break; 201 area2 += cur_cell->area; 202 cover2 += cur_cell->cover; 203 } 204 } 205 else 206 { 207 area2 = 0; 208 cover2 = cover; 209 } 210 211 if (cur_cell->x == x + 2) 212 { 213 area3 = cur_cell->area; 214 cover3 = cover2 + cur_cell->cover; 215 216 while (--num_cells) 217 { 218 cur_cell = *++cells; 219 if (cur_cell->x != x+2) break; 220 area3 += cur_cell->area; 221 cover3 += cur_cell->cover; 222 } 223 } 224 else 225 { 226 area3 = 0; 227 cover3 = cover2; 228 } 229 } 230 else if (x % 3 == 1) 231 { 232 area2 = area1; 233 area1 = 0; 234 cover2 = cover; 235 cover = last_cover; 236 if (cur_cell->x == x+1) 237 { 238 area3 = cur_cell->area; 239 cover3 = cover2 + cur_cell->cover; 240 241 while (--num_cells) 242 { 243 cur_cell = *++cells; 244 if (cur_cell->x != x+1) break; 245 area3 += cur_cell->area; 246 cover3 += cur_cell->cover; 247 } 248 } 249 else 250 { 251 area3 = 0; 252 cover3 = cover2; 253 } 254 } 255 else // if (x % 3 == 2) 256 { 257 area3 = area1; 258 area2 = 0; 259 area1 = 0; 260 cover3 = cover; 261 cover = last_cover; 262 cover2 = last_cover; 263 } 264 265 alpha1 = area1 ? calculate_alpha((cover 266 << (poly_subpixel_shift + 1)) - area1) : 0; 267 alpha2 = area2 ? calculate_alpha((cover2 268 << (poly_subpixel_shift + 1)) - area2) : 0; 269 alpha3 = area3 ? calculate_alpha((cover3 270 << (poly_subpixel_shift + 1)) - area3) : 0; 271 if(alpha1 || alpha2 || alpha3) 272 { 273 x += 3 - (x % 3); 274 if (area1 && !area2 && area3) 275 { 276 alpha2 = calculate_alpha(cover 277 << (poly_subpixel_shift + 1)); 278 } 279 else if (num_cells && cur_cell->x >= x) 280 { 281 if (area1 && !area2) 282 { 283 alpha2 = calculate_alpha(cover 284 << (poly_subpixel_shift + 1)); 285 alpha3 = alpha2; 286 } 287 if (area2 && !area3) 288 { 289 alpha3 = calculate_alpha(cover2 290 << (poly_subpixel_shift + 1)); 291 } 292 } 293 if (!area1) 294 { 295 if (area2) 296 { 297 alpha1 = calculate_alpha(cover 298 << (poly_subpixel_shift + 1)); 299 } 300 else if (area3) 301 { 302 alpha2 = calculate_alpha(cover 303 << (poly_subpixel_shift + 1)); 304 alpha1 = alpha2; 305 } 306 } 307 sl.add_cell(x / 3 - 1, alpha1, alpha2, alpha3); 308 } 309 310 if (num_cells && cur_cell->x - x >= 3) 311 { 312 alpha1 = calculate_alpha(cover3 313 << (poly_subpixel_shift + 1)); 314 sl.add_span(x / 3, cur_cell->x / 3 - x / 3, alpha1); 315 } 316 } 317 318 if(sl.num_spans()) break; 319 ++m_scan_y; 320 } 321 322 sl.finalize(m_scan_y); 323 ++m_scan_y; 324 return true; 325 } 326 327 //-------------------------------------------------------------------- 328 bool hit_test(int tx, int ty); 329 330 331 private: 332 //-------------------------------------------------------------------- 333 // Disable copying 334 rasterizer_scanline_aa_subpix(const rasterizer_scanline_aa_subpix<Clip>&); 335 const rasterizer_scanline_aa_subpix<Clip>& 336 operator = (const rasterizer_scanline_aa_subpix<Clip>&); 337 338 private: 339 rasterizer_cells_aa<cell_aa> m_outline; 340 clip_type m_clipper; 341 int m_gamma[aa_scale]; 342 filling_rule_e m_filling_rule; 343 bool m_auto_close; 344 coord_type m_start_x; 345 coord_type m_start_y; 346 unsigned m_status; 347 int m_scan_y; 348 }; 349 350 351 352 353 354 355 356 357 358 359 360 361 //------------------------------------------------------------------------ 362 template<class Clip> 363 void rasterizer_scanline_aa_subpix<Clip>::reset() 364 { 365 m_outline.reset(); 366 m_status = status_initial; 367 } 368 369 //------------------------------------------------------------------------ 370 template<class Clip> 371 void rasterizer_scanline_aa_subpix<Clip>::filling_rule(filling_rule_e filling_rule) 372 { 373 m_filling_rule = filling_rule; 374 } 375 376 //------------------------------------------------------------------------ 377 template<class Clip> 378 void rasterizer_scanline_aa_subpix<Clip>::clip_box(double x1, double y1, 379 double x2, double y2) 380 { 381 reset(); 382 m_clipper.clip_box(3 * conv_type::downscale(x1), conv_type::upscale(y1), 383 conv_type::upscale(3 * x2), conv_type::upscale(y2)); 384 } 385 386 //------------------------------------------------------------------------ 387 template<class Clip> 388 void rasterizer_scanline_aa_subpix<Clip>::reset_clipping() 389 { 390 reset(); 391 m_clipper.reset_clipping(); 392 } 393 394 //------------------------------------------------------------------------ 395 template<class Clip> 396 void rasterizer_scanline_aa_subpix<Clip>::close_polygon() 397 { 398 if(m_status == status_line_to) 399 { 400 m_clipper.line_to(m_outline, m_start_x, m_start_y); 401 m_status = status_closed; 402 } 403 } 404 405 //------------------------------------------------------------------------ 406 template<class Clip> 407 void rasterizer_scanline_aa_subpix<Clip>::move_to(int x, int y) 408 { 409 if(m_outline.sorted()) reset(); 410 if(m_auto_close) close_polygon(); 411 m_clipper.move_to(m_start_x = conv_type::downscale(x), 412 m_start_y = conv_type::downscale(y)); 413 m_status = status_move_to; 414 } 415 416 //------------------------------------------------------------------------ 417 template<class Clip> 418 void rasterizer_scanline_aa_subpix<Clip>::line_to(int x, int y) 419 { 420 m_clipper.line_to(m_outline, 421 conv_type::downscale(x), 422 conv_type::downscale(y)); 423 m_status = status_line_to; 424 } 425 426 //------------------------------------------------------------------------ 427 template<class Clip> 428 void rasterizer_scanline_aa_subpix<Clip>::move_to_d(double x, double y) 429 { 430 if(m_outline.sorted()) reset(); 431 if(m_auto_close) close_polygon(); 432 m_clipper.move_to(m_start_x = conv_type::upscale(x), 433 m_start_y = conv_type::upscale(y)); 434 m_status = status_move_to; 435 } 436 437 //------------------------------------------------------------------------ 438 template<class Clip> 439 void rasterizer_scanline_aa_subpix<Clip>::line_to_d(double x, double y) 440 { 441 m_clipper.line_to(m_outline, 442 conv_type::upscale(x), 443 conv_type::upscale(y)); 444 m_status = status_line_to; 445 } 446 447 //------------------------------------------------------------------------ 448 template<class Clip> 449 void rasterizer_scanline_aa_subpix<Clip>::add_vertex(double x, double y, unsigned cmd) 450 { 451 if(is_move_to(cmd)) 452 { 453 move_to_d(x, y); 454 } 455 else 456 if(is_vertex(cmd)) 457 { 458 line_to_d(x, y); 459 } 460 else 461 if(is_close(cmd)) 462 { 463 close_polygon(); 464 } 465 } 466 467 //------------------------------------------------------------------------ 468 template<class Clip> 469 void rasterizer_scanline_aa_subpix<Clip>::edge(int x1, int y1, int x2, int y2) 470 { 471 if(m_outline.sorted()) reset(); 472 m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1)); 473 m_clipper.line_to(m_outline, 474 conv_type::downscale(x2), 475 conv_type::downscale(y2)); 476 m_status = status_move_to; 477 } 478 479 //------------------------------------------------------------------------ 480 template<class Clip> 481 void rasterizer_scanline_aa_subpix<Clip>::edge_d(double x1, double y1, 482 double x2, double y2) 483 { 484 if(m_outline.sorted()) reset(); 485 m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); 486 m_clipper.line_to(m_outline, 487 conv_type::upscale(x2), 488 conv_type::upscale(y2)); 489 m_status = status_move_to; 490 } 491 492 //------------------------------------------------------------------------ 493 template<class Clip> 494 void rasterizer_scanline_aa_subpix<Clip>::sort() 495 { 496 m_outline.sort_cells(); 497 } 498 499 //------------------------------------------------------------------------ 500 template<class Clip> 501 AGG_INLINE bool rasterizer_scanline_aa_subpix<Clip>::rewind_scanlines() 502 { 503 if(m_auto_close) close_polygon(); 504 m_outline.sort_cells(); 505 if(m_outline.total_cells() == 0) 506 { 507 return false; 508 } 509 m_scan_y = m_outline.min_y(); 510 return true; 511 } 512 513 514 //------------------------------------------------------------------------ 515 template<class Clip> 516 AGG_INLINE bool rasterizer_scanline_aa_subpix<Clip>::navigate_scanline(int y) 517 { 518 if(m_auto_close) close_polygon(); 519 m_outline.sort_cells(); 520 if(m_outline.total_cells() == 0 || 521 y < m_outline.min_y() || 522 y > m_outline.max_y()) 523 { 524 return false; 525 } 526 m_scan_y = y; 527 return true; 528 } 529 530 //------------------------------------------------------------------------ 531 template<class Clip> 532 bool rasterizer_scanline_aa_subpix<Clip>::hit_test(int tx, int ty) 533 { 534 if(!navigate_scanline(ty)) return false; 535 scanline_hit_test sl(tx); 536 sweep_scanline(sl); 537 return sl.hit(); 538 } 539 540 541 542 } 543 544 545 546 #endif 547 548