1 2 //---------------------------------------------------------------------------- 3 // Anti-Grain Geometry - Version 2.3 4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 5 // 6 // Permission to copy, use, modify, sell and distribute this software 7 // is granted provided this copyright notice appears in all copies. 8 // This software is provided "as is" without express or implied 9 // warranty, and with no claim as to its suitability for any purpose. 10 // 11 //---------------------------------------------------------------------------- 12 // 13 // The author gratefully acknowleges the support of David Turner, 14 // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType 15 // libray - in producing this work. See http://www.freetype.org for details. 16 // 17 //---------------------------------------------------------------------------- 18 // Contact: mcseem (at) antigrain.com 19 // mcseemagg (at) yahoo.com 20 // http://www.antigrain.com 21 //---------------------------------------------------------------------------- 22 // 23 // Adaptation for 32-bit screen coordinates has been sponsored by 24 // Liberty Technology Systems, Inc., visit http://lib-sys.com 25 // 26 // Liberty Technology Systems, Inc. is the provider of 27 // PostScript and PDF technology for software developers. 28 // 29 //---------------------------------------------------------------------------- 30 #ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED 31 #define AGG_RASTERIZER_SCANLINE_AA_INCLUDED 32 #include "../../../../include/fxge/fx_ge.h" 33 #include "agg_basics.h" 34 #include "agg_math.h" 35 #include "agg_array.h" 36 #include "agg_clip_liang_barsky.h" 37 #include "agg_render_scanlines.h" 38 namespace agg 39 { 40 enum poly_base_scale_e { 41 poly_base_shift = 8, 42 poly_base_size = 1 << poly_base_shift, 43 poly_base_mask = poly_base_size - 1 44 }; 45 inline int poly_coord(FX_FLOAT c) 46 { 47 return int(c * poly_base_size); 48 } 49 struct cell_aa : public CFX_Object { 50 int x; 51 int y; 52 int cover; 53 int area; 54 void set(int x, int y, int c, int a); 55 void set_coord(int x, int y); 56 void set_cover(int c, int a); 57 void add_cover(int c, int a); 58 }; 59 class outline_aa : public CFX_Object 60 { 61 enum cell_block_scale_e { 62 cell_block_shift = 12, 63 cell_block_size = 1 << cell_block_shift, 64 cell_block_mask = cell_block_size - 1, 65 cell_block_pool = 256, 66 cell_block_limit = 1024 67 }; 68 struct sorted_y : public CFX_Object { 69 unsigned start; 70 unsigned num; 71 }; 72 public: 73 ~outline_aa(); 74 outline_aa(); 75 void reset(); 76 void move_to(int x, int y); 77 void line_to(int x, int y); 78 int min_x() const 79 { 80 return m_min_x; 81 } 82 int min_y() const 83 { 84 return m_min_y; 85 } 86 int max_x() const 87 { 88 return m_max_x; 89 } 90 int max_y() const 91 { 92 return m_max_y; 93 } 94 void sort_cells(); 95 unsigned total_cells() const 96 { 97 return m_num_cells; 98 } 99 unsigned scanline_num_cells(unsigned y) const 100 { 101 return m_sorted_y[y - m_min_y].num; 102 } 103 const cell_aa* const* scanline_cells(unsigned y) const 104 { 105 return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start; 106 } 107 bool sorted() const 108 { 109 return m_sorted; 110 } 111 private: 112 outline_aa(const outline_aa&); 113 const outline_aa& operator = (const outline_aa&); 114 void set_cur_cell(int x, int y); 115 void add_cur_cell(); 116 void render_hline(int ey, int x1, int y1, int x2, int y2); 117 void render_line(int x1, int y1, int x2, int y2); 118 void allocate_block(); 119 private: 120 unsigned m_num_blocks; 121 unsigned m_max_blocks; 122 unsigned m_cur_block; 123 unsigned m_num_cells; 124 cell_aa** m_cells; 125 cell_aa* m_cur_cell_ptr; 126 pod_array<cell_aa*> m_sorted_cells; 127 pod_array<sorted_y> m_sorted_y; 128 cell_aa m_cur_cell; 129 int m_cur_x; 130 int m_cur_y; 131 int m_min_x; 132 int m_min_y; 133 int m_max_x; 134 int m_max_y; 135 bool m_sorted; 136 }; 137 class scanline_hit_test : public CFX_Object 138 { 139 public: 140 scanline_hit_test(int x) : m_x(x), m_hit(false) {} 141 void reset_spans() {} 142 void finalize(int) {} 143 void add_cell(int x, int) 144 { 145 if(m_x == x) { 146 m_hit = true; 147 } 148 } 149 void add_span(int x, int len, int) 150 { 151 if(m_x >= x && m_x < x + len) { 152 m_hit = true; 153 } 154 } 155 unsigned num_spans() const 156 { 157 return 1; 158 } 159 bool hit() const 160 { 161 return m_hit; 162 } 163 private: 164 int m_x; 165 bool m_hit; 166 }; 167 enum filling_rule_e { 168 fill_non_zero, 169 fill_even_odd 170 }; 171 class rasterizer_scanline_aa : public CFX_Object 172 { 173 enum status { 174 status_initial, 175 status_line_to, 176 status_closed 177 }; 178 public: 179 enum aa_scale_e { 180 aa_num = 1 << 8, 181 aa_mask = aa_num - 1, 182 aa_2num = aa_num * 2, 183 aa_2mask = aa_2num - 1 184 }; 185 rasterizer_scanline_aa() : 186 m_filling_rule(fill_non_zero), 187 m_clipped_start_x(0), 188 m_clipped_start_y(0), 189 m_status(status_initial), 190 m_clipping(false) 191 { 192 } 193 ~rasterizer_scanline_aa() {} 194 void filling_rule(filling_rule_e filling_rule) 195 { 196 m_filling_rule = filling_rule; 197 } 198 int min_x() const 199 { 200 return m_outline.min_x(); 201 } 202 int min_y() const 203 { 204 return m_outline.min_y(); 205 } 206 int max_x() const 207 { 208 return m_outline.max_x(); 209 } 210 int max_y() const 211 { 212 return m_outline.max_y(); 213 } 214 void reset() 215 { 216 m_outline.reset(); 217 m_status = status_initial; 218 } 219 void clip_box(FX_FLOAT x1, FX_FLOAT y1, FX_FLOAT x2, FX_FLOAT y2) 220 { 221 m_clip_box = rect(poly_coord(x1), poly_coord(y1), 222 poly_coord(x2), poly_coord(y2)); 223 m_clip_box.normalize(); 224 m_clipping = true; 225 } 226 void add_vertex(FX_FLOAT x, FX_FLOAT y, unsigned cmd) 227 { 228 if(is_close(cmd)) { 229 close_polygon(); 230 } else { 231 if(is_move_to(cmd)) { 232 move_to(poly_coord(x), poly_coord(y)); 233 } else { 234 if(is_vertex(cmd)) { 235 line_to(poly_coord(x), poly_coord(y)); 236 } 237 } 238 } 239 } 240 void move_to(int x, int y) 241 { 242 if(m_clipping) { 243 if(m_outline.sorted()) { 244 reset(); 245 } 246 if(m_status == status_line_to) { 247 close_polygon(); 248 } 249 m_prev_x = m_start_x = x; 250 m_prev_y = m_start_y = y; 251 m_status = status_initial; 252 m_prev_flags = clipping_flags(x, y, m_clip_box); 253 if(m_prev_flags == 0) { 254 move_to_no_clip(x, y); 255 } 256 } else { 257 move_to_no_clip(x, y); 258 } 259 } 260 void line_to(int x, int y) 261 { 262 if(m_clipping) { 263 clip_segment(x, y); 264 } else { 265 line_to_no_clip(x, y); 266 } 267 } 268 void close_polygon() 269 { 270 if (m_status != status_line_to) { 271 return; 272 } 273 if(m_clipping) { 274 clip_segment(m_start_x, m_start_y); 275 } 276 close_polygon_no_clip(); 277 } 278 AGG_INLINE unsigned calculate_alpha(int area, bool no_smooth) const 279 { 280 int cover = area >> (poly_base_shift * 2 + 1 - 8); 281 if(cover < 0) { 282 cover = -cover; 283 } 284 if(m_filling_rule == fill_even_odd) { 285 cover &= aa_2mask; 286 if(cover > aa_num) { 287 cover = aa_2num - cover; 288 } 289 } 290 if (no_smooth) { 291 cover = cover > aa_mask / 2 ? aa_mask : 0; 292 } 293 if(cover > aa_mask) { 294 cover = aa_mask; 295 } 296 return cover; 297 } 298 AGG_INLINE void sort() 299 { 300 m_outline.sort_cells(); 301 } 302 AGG_INLINE bool rewind_scanlines() 303 { 304 close_polygon(); 305 m_outline.sort_cells(); 306 if(m_outline.total_cells() == 0) { 307 return false; 308 } 309 m_cur_y = m_outline.min_y(); 310 return true; 311 } 312 AGG_INLINE bool navigate_scanline(int y) 313 { 314 close_polygon(); 315 m_outline.sort_cells(); 316 if(m_outline.total_cells() == 0 || 317 y < m_outline.min_y() || 318 y > m_outline.max_y()) { 319 return false; 320 } 321 m_cur_y = y; 322 return true; 323 } 324 template<class Scanline> bool sweep_scanline(Scanline& sl, bool no_smooth) 325 { 326 for(;;) { 327 if(m_cur_y > m_outline.max_y()) { 328 return false; 329 } 330 sl.reset_spans(); 331 unsigned num_cells = m_outline.scanline_num_cells(m_cur_y); 332 const cell_aa* const* cells = m_outline.scanline_cells(m_cur_y); 333 int cover = 0; 334 while(num_cells) { 335 const cell_aa* cur_cell = *cells; 336 int x = cur_cell->x; 337 int area = cur_cell->area; 338 unsigned alpha; 339 cover += cur_cell->cover; 340 while(--num_cells) { 341 cur_cell = *++cells; 342 if(cur_cell->x != x) { 343 break; 344 } 345 area += cur_cell->area; 346 cover += cur_cell->cover; 347 } 348 if(area) { 349 alpha = calculate_alpha((cover << (poly_base_shift + 1)) - area, no_smooth); 350 if(alpha) { 351 sl.add_cell(x, alpha); 352 } 353 x++; 354 } 355 if(num_cells && cur_cell->x > x) { 356 alpha = calculate_alpha(cover << (poly_base_shift + 1), no_smooth); 357 if(alpha) { 358 sl.add_span(x, cur_cell->x - x, alpha); 359 } 360 } 361 } 362 if(sl.num_spans()) { 363 break; 364 } 365 ++m_cur_y; 366 } 367 sl.finalize(m_cur_y); 368 ++m_cur_y; 369 return true; 370 } 371 template<class VertexSource> 372 void add_path(VertexSource& vs, unsigned path_id = 0) 373 { 374 FX_FLOAT x; 375 FX_FLOAT y; 376 unsigned cmd; 377 vs.rewind(path_id); 378 while(!is_stop(cmd = vs.vertex(&x, &y))) { 379 add_vertex(x, y, cmd); 380 } 381 } 382 template<class VertexSource> 383 void add_path_transformed(VertexSource& vs, const CFX_AffineMatrix* pMatrix, unsigned path_id = 0) 384 { 385 FX_FLOAT x; 386 FX_FLOAT y; 387 unsigned cmd; 388 vs.rewind(path_id); 389 while(!is_stop(cmd = vs.vertex(&x, &y))) { 390 if (pMatrix) { 391 pMatrix->Transform(x, y); 392 } 393 add_vertex(x, y, cmd); 394 } 395 } 396 private: 397 rasterizer_scanline_aa(const rasterizer_scanline_aa&); 398 const rasterizer_scanline_aa& 399 operator = (const rasterizer_scanline_aa&); 400 void move_to_no_clip(int x, int y) 401 { 402 if(m_status == status_line_to) { 403 close_polygon_no_clip(); 404 } 405 m_outline.move_to(x * 1, y); 406 m_clipped_start_x = x; 407 m_clipped_start_y = y; 408 m_status = status_line_to; 409 } 410 void line_to_no_clip(int x, int y) 411 { 412 if(m_status != status_initial) { 413 m_outline.line_to(x * 1, y); 414 m_status = status_line_to; 415 } 416 } 417 void close_polygon_no_clip() 418 { 419 if(m_status == status_line_to) { 420 m_outline.line_to(m_clipped_start_x * 1, m_clipped_start_y); 421 m_status = status_closed; 422 } 423 } 424 void clip_segment(int x, int y) 425 { 426 unsigned flags = clipping_flags(x, y, m_clip_box); 427 if(m_prev_flags == flags) { 428 if(flags == 0) { 429 if(m_status == status_initial) { 430 move_to_no_clip(x, y); 431 } else { 432 line_to_no_clip(x, y); 433 } 434 } 435 } else { 436 int cx[4]; 437 int cy[4]; 438 unsigned n = clip_liang_barsky(m_prev_x, m_prev_y, 439 x, y, 440 m_clip_box, 441 cx, cy); 442 const int* px = cx; 443 const int* py = cy; 444 while(n--) { 445 if(m_status == status_initial) { 446 move_to_no_clip(*px++, *py++); 447 } else { 448 line_to_no_clip(*px++, *py++); 449 } 450 } 451 } 452 m_prev_flags = flags; 453 m_prev_x = x; 454 m_prev_y = y; 455 } 456 private: 457 outline_aa m_outline; 458 filling_rule_e m_filling_rule; 459 int m_clipped_start_x; 460 int m_clipped_start_y; 461 int m_start_x; 462 int m_start_y; 463 int m_prev_x; 464 int m_prev_y; 465 unsigned m_prev_flags; 466 unsigned m_status; 467 rect m_clip_box; 468 bool m_clipping; 469 int m_cur_y; 470 }; 471 } 472 #endif 473