00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED
00025 #define AGG_RASTERIZER_SCANLINE_AA_INCLUDED
00026
00027 #include <string.h>
00028 #include <math.h>
00029 #include "agg_basics.h"
00030 #include "agg_math.h"
00031 #include "agg_gamma_functions.h"
00032 #include "agg_clip_liang_barsky.h"
00033 #include "agg_render_scanlines.h"
00034
00035
00036 namespace agg
00037 {
00038
00039
00040
00041
00042
00043
00044
00045 enum
00046 {
00047 poly_base_shift = 8,
00048 poly_base_size = 1 << poly_base_shift,
00049 poly_base_mask = poly_base_size - 1
00050 };
00051
00052
00053 inline int poly_coord(double c)
00054 {
00055 return int(c * poly_base_size);
00056 }
00057
00058
00059
00060
00061
00062 struct cell_aa
00063 {
00064 int16 x;
00065 int16 y;
00066 int packed_coord;
00067 int cover;
00068 int area;
00069
00070 void set(int x, int y, int c, int a);
00071 void set_coord(int x, int y);
00072 void set_cover(int c, int a);
00073 void add_cover(int c, int a);
00074 };
00075
00076
00077
00078
00079
00080 class outline_aa
00081 {
00082 enum
00083 {
00084 cell_block_shift = 12,
00085 cell_block_size = 1 << cell_block_shift,
00086 cell_block_mask = cell_block_size - 1,
00087 cell_block_pool = 256,
00088 cell_block_limit = 1024
00089 };
00090
00091 public:
00092
00093 ~outline_aa();
00094 outline_aa();
00095
00096 void reset();
00097
00098 void move_to(int x, int y);
00099 void line_to(int x, int y);
00100
00101 int min_x() const { return m_min_x; }
00102 int min_y() const { return m_min_y; }
00103 int max_x() const { return m_max_x; }
00104 int max_y() const { return m_max_y; }
00105
00106 const cell_aa* const* cells();
00107 unsigned num_cells() { cells(); return m_num_cells; }
00108 bool sorted() const { return m_sorted; }
00109
00110 private:
00111 outline_aa(const outline_aa&);
00112 const outline_aa& operator = (const outline_aa&);
00113
00114 void set_cur_cell(int x, int y);
00115 void add_cur_cell();
00116 void sort_cells();
00117 void render_hline(int ey, int x1, int y1, int x2, int y2);
00118 void render_line(int x1, int y1, int x2, int y2);
00119 void allocate_block();
00120
00121 static void qsort_cells(cell_aa** start, unsigned num);
00122
00123 private:
00124 unsigned m_num_blocks;
00125 unsigned m_max_blocks;
00126 unsigned m_cur_block;
00127 unsigned m_num_cells;
00128 cell_aa** m_cells;
00129 cell_aa* m_cur_cell_ptr;
00130 cell_aa** m_sorted_cells;
00131 unsigned m_sorted_size;
00132 cell_aa m_cur_cell;
00133 int m_cur_x;
00134 int m_cur_y;
00135 int m_min_x;
00136 int m_min_y;
00137 int m_max_x;
00138 int m_max_y;
00139 bool m_sorted;
00140 };
00141
00142
00143
00144 enum filling_rule_e
00145 {
00146 fill_non_zero,
00147 fill_even_odd
00148 };
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 template<unsigned XScale=1, unsigned AA_Shift=8> class rasterizer_scanline_aa
00183 {
00184 enum status
00185 {
00186 status_initial,
00187 status_line_to,
00188 status_closed
00189 };
00190
00191 struct iterator
00192 {
00193 const cell_aa* const* cells;
00194 int cover;
00195 int last_y;
00196 };
00197
00198 public:
00199 enum
00200 {
00201 aa_shift = AA_Shift,
00202 aa_num = 1 << aa_shift,
00203 aa_mask = aa_num - 1,
00204 aa_2num = aa_num * 2,
00205 aa_2mask = aa_2num - 1
00206 };
00207
00208
00209 rasterizer_scanline_aa() :
00210 m_filling_rule(fill_non_zero),
00211 m_clipped_start_x(0),
00212 m_clipped_start_y(0),
00213 m_start_x(0),
00214 m_start_y(0),
00215 m_prev_x(0),
00216 m_prev_y(0),
00217 m_prev_flags(0),
00218 m_status(status_initial),
00219 m_clipping(false)
00220 {
00221 int i;
00222 for(i = 0; i < aa_num; i++) m_gamma[i] = i;
00223 }
00224
00225
00226 template<class GammaF>
00227 rasterizer_scanline_aa(const GammaF& gamma_function) :
00228 m_filling_rule(fill_non_zero),
00229 m_clipped_start_x(0),
00230 m_clipped_start_y(0),
00231 m_start_x(0),
00232 m_start_y(0),
00233 m_prev_x(0),
00234 m_prev_y(0),
00235 m_prev_flags(0),
00236 m_status(status_initial),
00237 m_clipping(false)
00238 {
00239 gamma(gamma_function);
00240 }
00241
00242
00243 void reset();
00244 void filling_rule(filling_rule_e filling_rule);
00245 void clip_box(double x1, double y1, double x2, double y2);
00246 void reset_clipping();
00247
00248
00249 template<class GammaF> void gamma(const GammaF& gamma_function)
00250 {
00251 int i;
00252 for(i = 0; i < aa_num; i++)
00253 {
00254 m_gamma[i] = int(floor(gamma_function(double(i) / aa_mask) * aa_mask + 0.5));
00255 }
00256 }
00257
00258
00259 unsigned apply_gamma(unsigned cover) const
00260 {
00261 return m_gamma[cover];
00262 }
00263
00264
00265 void add_vertex(double x, double y, unsigned cmd);
00266 void move_to(int x, int y);
00267 void line_to(int x, int y);
00268 void close_polygon();
00269 void move_to_d(double x, double y);
00270 void line_to_d(double x, double y);
00271
00272
00273 int min_x() const { return m_outline.min_x(); }
00274 int min_y() const { return m_outline.min_y(); }
00275 int max_x() const { return m_outline.max_x(); }
00276 int max_y() const { return m_outline.max_y(); }
00277
00278
00279 unsigned calculate_alpha(int area) const
00280 {
00281 int cover = area >> (poly_base_shift*2 + 1 - aa_shift);
00282
00283 if(cover < 0) cover = -cover;
00284 if(m_filling_rule == fill_even_odd)
00285 {
00286 cover &= aa_2mask;
00287 if(cover > aa_num)
00288 {
00289 cover = aa_2num - cover;
00290 }
00291 }
00292 if(cover > aa_mask) cover = aa_mask;
00293 return m_gamma[cover];
00294 }
00295
00296
00297 void sort()
00298 {
00299 m_outline.cells();
00300 }
00301
00302
00303
00304 bool rewind_scanlines()
00305 {
00306 close_polygon();
00307 m_iterator.cells = m_outline.cells();
00308 if(m_outline.num_cells() == 0)
00309 {
00310 return false;
00311 }
00312 m_iterator.cover = 0;
00313 m_iterator.last_y = (*m_iterator.cells)->y;
00314 return true;
00315 }
00316
00317
00318
00319 template<class Scanline> bool sweep_scanline(Scanline& sl)
00320 {
00321 sl.reset_spans();
00322 for(;;)
00323 {
00324 const cell_aa* cur_cell = *m_iterator.cells;
00325 if(cur_cell == 0) return false;
00326 ++m_iterator.cells;
00327 m_iterator.last_y = cur_cell->y;
00328
00329 for(;;)
00330 {
00331 int coord = cur_cell->packed_coord;
00332 int area = cur_cell->area;
00333 int last_x = cur_cell->x;
00334
00335 m_iterator.cover += cur_cell->cover;
00336
00337
00338 for(; (cur_cell = *m_iterator.cells) != 0; ++m_iterator.cells)
00339 {
00340 if(cur_cell->packed_coord != coord) break;
00341 area += cur_cell->area;
00342 m_iterator.cover += cur_cell->cover;
00343 }
00344
00345 int alpha;
00346 if(cur_cell == 0 || cur_cell->y != m_iterator.last_y)
00347 {
00348
00349 if(area)
00350 {
00351 alpha = calculate_alpha((m_iterator.cover << (poly_base_shift + 1)) - area);
00352 if(alpha)
00353 {
00354 sl.add_cell(last_x, alpha);
00355 }
00356 ++last_x;
00357 }
00358 break;
00359 }
00360
00361 ++m_iterator.cells;
00362
00363 if(area)
00364 {
00365 alpha = calculate_alpha((m_iterator.cover << (poly_base_shift + 1)) - area);
00366 if(alpha)
00367 {
00368 sl.add_cell(last_x, alpha);
00369 }
00370 ++last_x;
00371 }
00372
00373 if(cur_cell->x > last_x)
00374 {
00375 alpha = calculate_alpha(m_iterator.cover << (poly_base_shift + 1));
00376 if(alpha)
00377 {
00378 sl.add_span(last_x, cur_cell->x - last_x, alpha);
00379 }
00380 }
00381 }
00382 if(sl.num_spans())
00383 {
00384 sl.finalize(m_iterator.last_y);
00385 break;
00386 }
00387 }
00388 return true;
00389 }
00390
00391
00392
00393 bool hit_test(int tx, int ty);
00394
00395
00396
00397 void add_xy(const double* x, const double* y, unsigned n)
00398 {
00399 if(n > 2)
00400 {
00401 move_to_d(*x++, *y++);
00402 --n;
00403 do
00404 {
00405 line_to_d(*x++, *y++);
00406 }
00407 while(--n);
00408 }
00409 }
00410
00411
00412 template<class VertexSource>
00413 void add_path(VertexSource& vs, unsigned id=0)
00414 {
00415 double x;
00416 double y;
00417
00418 unsigned cmd;
00419 vs.rewind(id);
00420 while(!is_stop(cmd = vs.vertex(&x, &y)))
00421 {
00422 add_vertex(x, y, cmd);
00423 }
00424 }
00425
00426
00427 private:
00428
00429
00430 rasterizer_scanline_aa(const rasterizer_scanline_aa<XScale, AA_Shift>&);
00431 const rasterizer_scanline_aa<XScale, AA_Shift>&
00432 operator = (const rasterizer_scanline_aa<XScale, AA_Shift>&);
00433
00434
00435 void move_to_no_clip(int x, int y);
00436 void line_to_no_clip(int x, int y);
00437 void close_polygon_no_clip();
00438 void clip_segment(int x, int y);
00439
00440 private:
00441 outline_aa m_outline;
00442 int m_gamma[aa_num];
00443 filling_rule_e m_filling_rule;
00444 int m_clipped_start_x;
00445 int m_clipped_start_y;
00446 int m_start_x;
00447 int m_start_y;
00448 int m_prev_x;
00449 int m_prev_y;
00450 unsigned m_prev_flags;
00451 unsigned m_status;
00452 rect m_clip_box;
00453 bool m_clipping;
00454 iterator m_iterator;
00455 };
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 template<unsigned XScale, unsigned AA_Shift>
00468 void rasterizer_scanline_aa<XScale, AA_Shift>::reset()
00469 {
00470 m_outline.reset();
00471 m_status = status_initial;
00472 }
00473
00474
00475 template<unsigned XScale, unsigned AA_Shift>
00476 void rasterizer_scanline_aa<XScale, AA_Shift>::filling_rule(filling_rule_e filling_rule)
00477 {
00478 m_filling_rule = filling_rule;
00479 }
00480
00481
00482 template<unsigned XScale, unsigned AA_Shift>
00483 void rasterizer_scanline_aa<XScale, AA_Shift>::clip_box(double x1, double y1, double x2, double y2)
00484 {
00485 reset();
00486 m_clip_box = rect(poly_coord(x1), poly_coord(y1),
00487 poly_coord(x2), poly_coord(y2));
00488 m_clip_box.normalize();
00489 m_clipping = true;
00490 }
00491
00492
00493 template<unsigned XScale, unsigned AA_Shift>
00494 void rasterizer_scanline_aa<XScale, AA_Shift>::reset_clipping()
00495 {
00496 reset();
00497 m_clipping = false;
00498 }
00499
00500
00501
00502
00503 template<unsigned XScale, unsigned AA_Shift>
00504 void rasterizer_scanline_aa<XScale, AA_Shift>::move_to_no_clip(int x, int y)
00505 {
00506 if(m_status == status_line_to)
00507 {
00508 close_polygon_no_clip();
00509 }
00510 m_outline.move_to(x * XScale, y);
00511 m_clipped_start_x = x;
00512 m_clipped_start_y = y;
00513 m_status = status_line_to;
00514 }
00515
00516
00517
00518 template<unsigned XScale, unsigned AA_Shift>
00519 void rasterizer_scanline_aa<XScale, AA_Shift>::line_to_no_clip(int x, int y)
00520 {
00521 if(m_status != status_initial)
00522 {
00523 m_outline.line_to(x * XScale, y);
00524 m_status = status_line_to;
00525 }
00526 }
00527
00528
00529
00530 template<unsigned XScale, unsigned AA_Shift>
00531 void rasterizer_scanline_aa<XScale, AA_Shift>::close_polygon_no_clip()
00532 {
00533 if(m_status == status_line_to)
00534 {
00535 m_outline.line_to(m_clipped_start_x * XScale, m_clipped_start_y);
00536 m_status = status_closed;
00537 }
00538 }
00539
00540
00541
00542 template<unsigned XScale, unsigned AA_Shift>
00543 void rasterizer_scanline_aa<XScale, AA_Shift>::clip_segment(int x, int y)
00544 {
00545 unsigned flags = clipping_flags(x, y, m_clip_box);
00546 if(m_prev_flags == flags)
00547 {
00548 if(flags == 0)
00549 {
00550 if(m_status == status_initial)
00551 {
00552 move_to_no_clip(x, y);
00553 }
00554 else
00555 {
00556 line_to_no_clip(x, y);
00557 }
00558 }
00559 }
00560 else
00561 {
00562 int cx[4];
00563 int cy[4];
00564 unsigned n = clip_liang_barsky(m_prev_x, m_prev_y,
00565 x, y,
00566 m_clip_box,
00567 cx, cy);
00568 const int* px = cx;
00569 const int* py = cy;
00570 while(n--)
00571 {
00572 if(m_status == status_initial)
00573 {
00574 move_to_no_clip(*px++, *py++);
00575 }
00576 else
00577 {
00578 line_to_no_clip(*px++, *py++);
00579 }
00580 }
00581 }
00582 m_prev_flags = flags;
00583 m_prev_x = x;
00584 m_prev_y = y;
00585 }
00586
00587
00588
00589
00590 template<unsigned XScale, unsigned AA_Shift>
00591 void rasterizer_scanline_aa<XScale, AA_Shift>::add_vertex(double x, double y, unsigned cmd)
00592 {
00593 if(is_close(cmd))
00594 {
00595 close_polygon();
00596 }
00597 else
00598 {
00599 if(is_move_to(cmd))
00600 {
00601 move_to(poly_coord(x), poly_coord(y));
00602 }
00603 else
00604 {
00605 if(is_vertex(cmd))
00606 {
00607 line_to(poly_coord(x), poly_coord(y));
00608 }
00609 }
00610 }
00611 }
00612
00613
00614
00615
00616 template<unsigned XScale, unsigned AA_Shift>
00617 void rasterizer_scanline_aa<XScale, AA_Shift>::move_to(int x, int y)
00618 {
00619 if(m_clipping)
00620 {
00621 if(m_outline.sorted())
00622 {
00623 reset();
00624 }
00625 if(m_status == status_line_to)
00626 {
00627 close_polygon();
00628 }
00629 m_prev_x = m_start_x = x;
00630 m_prev_y = m_start_y = y;
00631 m_status = status_initial;
00632 m_prev_flags = clipping_flags(x, y, m_clip_box);
00633 if(m_prev_flags == 0)
00634 {
00635 move_to_no_clip(x, y);
00636 }
00637 }
00638 else
00639 {
00640 move_to_no_clip(x, y);
00641 }
00642 }
00643
00644
00645 template<unsigned XScale, unsigned AA_Shift>
00646 void rasterizer_scanline_aa<XScale, AA_Shift>::line_to(int x, int y)
00647 {
00648 if(m_clipping)
00649 {
00650 clip_segment(x, y);
00651 }
00652 else
00653 {
00654 line_to_no_clip(x, y);
00655 }
00656 }
00657
00658
00659 template<unsigned XScale, unsigned AA_Shift>
00660 void rasterizer_scanline_aa<XScale, AA_Shift>::close_polygon()
00661 {
00662 if(m_clipping)
00663 {
00664 clip_segment(m_start_x, m_start_y);
00665 }
00666 close_polygon_no_clip();
00667 }
00668
00669
00670 template<unsigned XScale, unsigned AA_Shift>
00671 void rasterizer_scanline_aa<XScale, AA_Shift>::move_to_d(double x, double y)
00672 {
00673 move_to(poly_coord(x), poly_coord(y));
00674 }
00675
00676
00677 template<unsigned XScale, unsigned AA_Shift>
00678 void rasterizer_scanline_aa<XScale, AA_Shift>::line_to_d(double x, double y)
00679 {
00680 line_to(poly_coord(x), poly_coord(y));
00681 }
00682
00683
00684
00685 template<unsigned XScale, unsigned AA_Shift>
00686 bool rasterizer_scanline_aa<XScale, AA_Shift>::hit_test(int tx, int ty)
00687 {
00688 close_polygon();
00689 const cell_aa* const* cells = m_outline.cells();
00690 if(m_outline.num_cells() == 0) return false;
00691
00692 int cover = 0;
00693
00694 const cell_aa* cur_cell = *cells++;
00695 for(;;)
00696 {
00697 int alpha;
00698 int coord = cur_cell->packed_coord;
00699 int x = cur_cell->x;
00700 int y = cur_cell->y;
00701
00702 if(y > ty) return false;
00703
00704 int area = cur_cell->area;
00705 cover += cur_cell->cover;
00706
00707 while((cur_cell = *cells++) != 0)
00708 {
00709 if(cur_cell->packed_coord != coord) break;
00710 area += cur_cell->area;
00711 cover += cur_cell->cover;
00712 }
00713
00714 if(area)
00715 {
00716 alpha = calculate_alpha((cover << (poly_base_shift + 1)) - area);
00717 if(alpha)
00718 {
00719 if(tx == x && ty == y) return true;
00720 }
00721 x++;
00722 }
00723
00724 if(!cur_cell) break;
00725
00726 if(cur_cell->x > x)
00727 {
00728 alpha = calculate_alpha(cover << (poly_base_shift + 1));
00729 if(alpha)
00730 {
00731 if(ty == y && tx >= x && tx <= cur_cell->x) return true;
00732 }
00733 }
00734 }
00735 return false;
00736 }
00737
00738 }
00739
00740
00741
00742 #endif
00743