Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages | Examples

agg_rasterizer_scanline_aa.h

00001 //----------------------------------------------------------------------------
00002 // Anti-Grain Geometry - Version 2.2
00003 // Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
00004 //
00005 // Permission to copy, use, modify, sell and distribute this software 
00006 // is granted provided this copyright notice appears in all copies. 
00007 // This software is provided "as is" without express or implied
00008 // warranty, and with no claim as to its suitability for any purpose.
00009 //
00010 // The author gratefully acknowleges the support of David Turner, 
00011 // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType 
00012 // libray - in producing this work. See http://www.freetype.org for details.
00013 //
00014 //----------------------------------------------------------------------------
00015 // Contact: mcseem@antigrain.com
00016 //          mcseemagg@yahoo.com
00017 //          http://www.antigrain.com
00018 //----------------------------------------------------------------------------
00019 //
00020 // Class rasterizer_scanline_aa
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     // These constants determine the subpixel accuracy, to be more precise, 
00041     // the number of bits of the fractional part of the coordinates. 
00042     // The possible coordinate capacity in bits can be calculated by formula:
00043     // sizeof(int) * 8 - poly_base_shift * 2, i.e, for 32-bit integers and
00044     // 8-bits fractional part the capacity is 16 bits or [-32768...32767].
00045     enum
00046     {
00047         poly_base_shift = 8,                       //----poly_base_shift
00048         poly_base_size  = 1 << poly_base_shift,    //----poly_base_size 
00049         poly_base_mask  = poly_base_size - 1       //----poly_base_mask 
00050     };
00051     
00052     //--------------------------------------------------------------poly_coord
00053     inline int poly_coord(double c)
00054     {
00055         return int(c * poly_base_size);
00056     }
00057 
00058     //-----------------------------------------------------------------cell_aa
00059     // A pixel cell. There're no constructors defined and it was done 
00060     // intentionally in order to avoid extra overhead when allocating an 
00061     // array of cells.
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     //--------------------------------------------------------------outline_aa
00078     // An internal class that implements the main rasterization algorithm.
00079     // Used in the rasterizer. Should not be used direcly.
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     //----------------------------------------------------------filling_rule_e
00144     enum filling_rule_e
00145     {
00146         fill_non_zero,
00147         fill_even_odd
00148     };
00149 
00150 
00151     //==================================================rasterizer_scanline_aa
00152     // Polygon rasterizer that is used to render filled polygons with 
00153     // high-quality Anti-Aliasing. Internally, by default, the class uses 
00154     // integer coordinates in format 24.8, i.e. 24 bits for integer part 
00155     // and 8 bits for fractional - see poly_base_shift. This class can be 
00156     // used in the following  way:
00157     //
00158     // 1. filling_rule(filling_rule_e ft) - optional.
00159     //
00160     // 2. gamma() - optional.
00161     //
00162     // 3. reset()
00163     //
00164     // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create 
00165     //    more than one contour, but each contour must consist of at least 3
00166     //    vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3);
00167     //    is the absolute minimum of vertices that define a triangle.
00168     //    The algorithm does not check either the number of vertices nor
00169     //    coincidence of their coordinates, but in the worst case it just 
00170     //    won't draw anything.
00171     //    The orger of the vertices (clockwise or counterclockwise) 
00172     //    is important when using the non-zero filling rule (fill_non_zero).
00173     //    In this case the vertex order of all the contours must be the same
00174     //    if you want your intersecting polygons to be without "holes".
00175     //    You actually can use different vertices order. If the contours do not 
00176     //    intersect each other the order is not important anyway. If they do, 
00177     //    contours with the same vertex order will be rendered without "holes" 
00178     //    while the intersecting contours with different orders will have "holes".
00179     //
00180     // filling_rule() and gamma() can be called anytime before "sweeping".
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                     //accumulate all cells with the same coordinates
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         // Disable copying
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 

Generated on Wed Feb 9 11:31:35 2005 for OpenGUI by  doxygen 1.4.0