Anti-Grain Geometry - AGG (libagg)  2.5
agg-2.5/include/agg_rasterizer_scanline_aa.h
Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 // Anti-Grain Geometry (AGG) - Version 2.5
00003 // A high quality rendering engine for C++
00004 // Copyright (C) 2002-2006 Maxim Shemanarev
00005 // Contact: mcseem@antigrain.com
00006 //          mcseemagg@yahoo.com
00007 //          http://antigrain.com
00008 // 
00009 // AGG is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU General Public License
00011 // as published by the Free Software Foundation; either version 2
00012 // of the License, or (at your option) any later version.
00013 // 
00014 // AGG is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 // 
00019 // You should have received a copy of the GNU General Public License
00020 // along with AGG; if not, write to the Free Software
00021 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
00022 // MA 02110-1301, USA.
00023 //----------------------------------------------------------------------------
00024 //
00025 // The author gratefully acknowleges the support of David Turner, 
00026 // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType 
00027 // libray - in producing this work. See http://www.freetype.org for details.
00028 //
00029 //----------------------------------------------------------------------------
00030 //
00031 // Adaptation for 32-bit screen coordinates has been sponsored by 
00032 // Liberty Technology Systems, Inc., visit http://lib-sys.com
00033 //
00034 // Liberty Technology Systems, Inc. is the provider of
00035 // PostScript and PDF technology for software developers.
00036 // 
00037 //----------------------------------------------------------------------------
00038 
00039 #ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED
00040 #define AGG_RASTERIZER_SCANLINE_AA_INCLUDED
00041 
00042 #include "agg_rasterizer_cells_aa.h"
00043 #include "agg_rasterizer_sl_clip.h"
00044 #include "agg_gamma_functions.h"
00045 
00046 
00047 namespace agg
00048 {
00049 
00050 
00051     //-----------------------------------------------------------------cell_aa
00052     // A pixel cell. There're no constructors defined and it was done 
00053     // intentionally in order to avoid extra overhead when allocating an 
00054     // array of cells.
00055     struct cell_aa
00056     {
00057         int x;
00058         int y;
00059         int cover;
00060         int area;
00061 
00062         void initial()
00063         {
00064             x = 0x7FFFFFFF;
00065             y = 0x7FFFFFFF;
00066             cover = 0;
00067             area  = 0;
00068         }
00069 
00070         void style(const cell_aa&) {}
00071 
00072         int not_equal(int ex, int ey, const cell_aa&) const
00073         {
00074             return (ex - x) | (ey - y);
00075         }
00076     };
00077 
00078 
00079     //==================================================rasterizer_scanline_aa
00080     // Polygon rasterizer that is used to render filled polygons with 
00081     // high-quality Anti-Aliasing. Internally, by default, the class uses 
00082     // integer coordinates in format 24.8, i.e. 24 bits for integer part 
00083     // and 8 bits for fractional - see poly_subpixel_shift. This class can be 
00084     // used in the following  way:
00085     //
00086     // 1. filling_rule(filling_rule_e ft) - optional.
00087     //
00088     // 2. gamma() - optional.
00089     //
00090     // 3. reset()
00091     //
00092     // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create 
00093     //    more than one contour, but each contour must consist of at least 3
00094     //    vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3);
00095     //    is the absolute minimum of vertices that define a triangle.
00096     //    The algorithm does not check either the number of vertices nor
00097     //    coincidence of their coordinates, but in the worst case it just 
00098     //    won't draw anything.
00099     //    The orger of the vertices (clockwise or counterclockwise) 
00100     //    is important when using the non-zero filling rule (fill_non_zero).
00101     //    In this case the vertex order of all the contours must be the same
00102     //    if you want your intersecting polygons to be without "holes".
00103     //    You actually can use different vertices order. If the contours do not 
00104     //    intersect each other the order is not important anyway. If they do, 
00105     //    contours with the same vertex order will be rendered without "holes" 
00106     //    while the intersecting contours with different orders will have "holes".
00107     //
00108     // filling_rule() and gamma() can be called anytime before "sweeping".
00109     //------------------------------------------------------------------------
00110     template<class Clip=rasterizer_sl_clip_int> class rasterizer_scanline_aa
00111     {
00112         enum status
00113         {
00114             status_initial,
00115             status_move_to,
00116             status_line_to,
00117             status_closed
00118         };
00119 
00120     public:
00121         typedef Clip                      clip_type;
00122         typedef typename Clip::conv_type  conv_type;
00123         typedef typename Clip::coord_type coord_type;
00124 
00125         enum aa_scale_e
00126         {
00127             aa_shift  = 8,
00128             aa_scale  = 1 << aa_shift,
00129             aa_mask   = aa_scale - 1,
00130             aa_scale2 = aa_scale * 2,
00131             aa_mask2  = aa_scale2 - 1
00132         };
00133 
00134         //--------------------------------------------------------------------
00135         rasterizer_scanline_aa() : 
00136             m_outline(),
00137             m_clipper(),
00138             m_filling_rule(fill_non_zero),
00139             m_auto_close(true),
00140             m_start_x(0),
00141             m_start_y(0),
00142             m_status(status_initial)
00143         {
00144             int i;
00145             for(i = 0; i < aa_scale; i++) m_gamma[i] = i;
00146         }
00147 
00148         //--------------------------------------------------------------------
00149         template<class GammaF> 
00150         rasterizer_scanline_aa(const GammaF& gamma_function) : 
00151             m_outline(),
00152             m_clipper(m_outline),
00153             m_filling_rule(fill_non_zero),
00154             m_auto_close(true),
00155             m_start_x(0),
00156             m_start_y(0),
00157             m_status(status_initial)
00158         {
00159             gamma(gamma_function);
00160         }
00161 
00162         //--------------------------------------------------------------------
00163         void reset(); 
00164         void reset_clipping();
00165         void clip_box(double x1, double y1, double x2, double y2);
00166         void filling_rule(filling_rule_e filling_rule);
00167         void auto_close(bool flag) { m_auto_close = flag; }
00168 
00169         //--------------------------------------------------------------------
00170         template<class GammaF> void gamma(const GammaF& gamma_function)
00171         { 
00172             int i;
00173             for(i = 0; i < aa_scale; i++)
00174             {
00175                 m_gamma[i] = uround(gamma_function(double(i) / aa_mask) * aa_mask);
00176             }
00177         }
00178 
00179         //--------------------------------------------------------------------
00180         unsigned apply_gamma(unsigned cover) const 
00181         { 
00182             return m_gamma[cover]; 
00183         }
00184 
00185         //--------------------------------------------------------------------
00186         void move_to(int x, int y);
00187         void line_to(int x, int y);
00188         void move_to_d(double x, double y);
00189         void line_to_d(double x, double y);
00190         void close_polygon();
00191         void add_vertex(double x, double y, unsigned cmd);
00192 
00193         void edge(int x1, int y1, int x2, int y2);
00194         void edge_d(double x1, double y1, double x2, double y2);
00195 
00196         //-------------------------------------------------------------------
00197         template<class VertexSource>
00198         void add_path(VertexSource& vs, unsigned path_id=0)
00199         {
00200             double x;
00201             double y;
00202 
00203             unsigned cmd;
00204             vs.rewind(path_id);
00205             if(m_outline.sorted()) reset();
00206             while(!is_stop(cmd = vs.vertex(&x, &y)))
00207             {
00208                 add_vertex(x, y, cmd);
00209             }
00210         }
00211         
00212         //--------------------------------------------------------------------
00213         int min_x() const { return m_outline.min_x(); }
00214         int min_y() const { return m_outline.min_y(); }
00215         int max_x() const { return m_outline.max_x(); }
00216         int max_y() const { return m_outline.max_y(); }
00217 
00218         //--------------------------------------------------------------------
00219         void sort();
00220         bool rewind_scanlines();
00221         bool navigate_scanline(int y);
00222 
00223         //--------------------------------------------------------------------
00224         AGG_INLINE unsigned calculate_alpha(int area) const
00225         {
00226             int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift);
00227 
00228             if(cover < 0) cover = -cover;
00229             if(m_filling_rule == fill_even_odd)
00230             {
00231                 cover &= aa_mask2;
00232                 if(cover > aa_scale)
00233                 {
00234                     cover = aa_scale2 - cover;
00235                 }
00236             }
00237             if(cover > aa_mask) cover = aa_mask;
00238             return m_gamma[cover];
00239         }
00240 
00241         //--------------------------------------------------------------------
00242         template<class Scanline> bool sweep_scanline(Scanline& sl)
00243         {
00244             for(;;)
00245             {
00246                 if(m_scan_y > m_outline.max_y()) return false;
00247                 sl.reset_spans();
00248                 unsigned num_cells = m_outline.scanline_num_cells(m_scan_y);
00249                 const cell_aa* const* cells = m_outline.scanline_cells(m_scan_y);
00250                 int cover = 0;
00251 
00252                 while(num_cells)
00253                 {
00254                     const cell_aa* cur_cell = *cells;
00255                     int x    = cur_cell->x;
00256                     int area = cur_cell->area;
00257                     unsigned alpha;
00258 
00259                     cover += cur_cell->cover;
00260 
00261                     //accumulate all cells with the same X
00262                     while(--num_cells)
00263                     {
00264                         cur_cell = *++cells;
00265                         if(cur_cell->x != x) break;
00266                         area  += cur_cell->area;
00267                         cover += cur_cell->cover;
00268                     }
00269 
00270                     if(area)
00271                     {
00272                         alpha = calculate_alpha((cover << (poly_subpixel_shift + 1)) - area);
00273                         if(alpha)
00274                         {
00275                             sl.add_cell(x, alpha);
00276                         }
00277                         x++;
00278                     }
00279 
00280                     if(num_cells && cur_cell->x > x)
00281                     {
00282                         alpha = calculate_alpha(cover << (poly_subpixel_shift + 1));
00283                         if(alpha)
00284                         {
00285                             sl.add_span(x, cur_cell->x - x, alpha);
00286                         }
00287                     }
00288                 }
00289         
00290                 if(sl.num_spans()) break;
00291                 ++m_scan_y;
00292             }
00293 
00294             sl.finalize(m_scan_y);
00295             ++m_scan_y;
00296             return true;
00297         }
00298 
00299         //--------------------------------------------------------------------
00300         bool hit_test(int tx, int ty);
00301 
00302 
00303     private:
00304         //--------------------------------------------------------------------
00305         // Disable copying
00306         rasterizer_scanline_aa(const rasterizer_scanline_aa<Clip>&);
00307         const rasterizer_scanline_aa<Clip>& 
00308         operator = (const rasterizer_scanline_aa<Clip>&);
00309 
00310     private:
00311         rasterizer_cells_aa<cell_aa> m_outline;
00312         clip_type      m_clipper;
00313         int            m_gamma[aa_scale];
00314         filling_rule_e m_filling_rule;
00315         bool           m_auto_close;
00316         coord_type     m_start_x;
00317         coord_type     m_start_y;
00318         unsigned       m_status;
00319         int            m_scan_y;
00320     };
00321 
00322 
00323 
00324 
00325 
00326 
00327 
00328 
00329 
00330 
00331 
00332 
00333     //------------------------------------------------------------------------
00334     template<class Clip> 
00335     void rasterizer_scanline_aa<Clip>::reset() 
00336     { 
00337         m_outline.reset(); 
00338         m_status = status_initial;
00339     }
00340 
00341     //------------------------------------------------------------------------
00342     template<class Clip> 
00343     void rasterizer_scanline_aa<Clip>::filling_rule(filling_rule_e filling_rule) 
00344     { 
00345         m_filling_rule = filling_rule; 
00346     }
00347 
00348     //------------------------------------------------------------------------
00349     template<class Clip> 
00350     void rasterizer_scanline_aa<Clip>::clip_box(double x1, double y1, 
00351                                                 double x2, double y2)
00352     {
00353         reset();
00354         m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), 
00355                            conv_type::upscale(x2), conv_type::upscale(y2));
00356     }
00357 
00358     //------------------------------------------------------------------------
00359     template<class Clip> 
00360     void rasterizer_scanline_aa<Clip>::reset_clipping()
00361     {
00362         reset();
00363         m_clipper.reset_clipping();
00364     }
00365 
00366     //------------------------------------------------------------------------
00367     template<class Clip> 
00368     void rasterizer_scanline_aa<Clip>::close_polygon()
00369     {
00370         if(m_status == status_line_to)
00371         {
00372             m_clipper.line_to(m_outline, m_start_x, m_start_y);
00373             m_status = status_closed;
00374         }
00375     }
00376 
00377     //------------------------------------------------------------------------
00378     template<class Clip> 
00379     void rasterizer_scanline_aa<Clip>::move_to(int x, int y)
00380     {
00381         if(m_outline.sorted()) reset();
00382         if(m_auto_close) close_polygon();
00383         m_clipper.move_to(m_start_x = conv_type::downscale(x), 
00384                           m_start_y = conv_type::downscale(y));
00385         m_status = status_move_to;
00386     }
00387 
00388     //------------------------------------------------------------------------
00389     template<class Clip> 
00390     void rasterizer_scanline_aa<Clip>::line_to(int x, int y)
00391     {
00392         m_clipper.line_to(m_outline, 
00393                           conv_type::downscale(x), 
00394                           conv_type::downscale(y));
00395         m_status = status_line_to;
00396     }
00397 
00398     //------------------------------------------------------------------------
00399     template<class Clip> 
00400     void rasterizer_scanline_aa<Clip>::move_to_d(double x, double y) 
00401     { 
00402         if(m_outline.sorted()) reset();
00403         if(m_auto_close) close_polygon();
00404         m_clipper.move_to(m_start_x = conv_type::upscale(x), 
00405                           m_start_y = conv_type::upscale(y)); 
00406         m_status = status_move_to;
00407     }
00408 
00409     //------------------------------------------------------------------------
00410     template<class Clip> 
00411     void rasterizer_scanline_aa<Clip>::line_to_d(double x, double y) 
00412     { 
00413         m_clipper.line_to(m_outline, 
00414                           conv_type::upscale(x), 
00415                           conv_type::upscale(y)); 
00416         m_status = status_line_to;
00417     }
00418 
00419     //------------------------------------------------------------------------
00420     template<class Clip> 
00421     void rasterizer_scanline_aa<Clip>::add_vertex(double x, double y, unsigned cmd)
00422     {
00423         if(is_move_to(cmd)) 
00424         {
00425             move_to_d(x, y);
00426         }
00427         else 
00428         if(is_vertex(cmd))
00429         {
00430             line_to_d(x, y);
00431         }
00432         else
00433         if(is_close(cmd))
00434         {
00435             close_polygon();
00436         }
00437     }
00438 
00439     //------------------------------------------------------------------------
00440     template<class Clip> 
00441     void rasterizer_scanline_aa<Clip>::edge(int x1, int y1, int x2, int y2)
00442     {
00443         if(m_outline.sorted()) reset();
00444         m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1));
00445         m_clipper.line_to(m_outline, 
00446                           conv_type::downscale(x2), 
00447                           conv_type::downscale(y2));
00448         m_status = status_move_to;
00449     }
00450     
00451     //------------------------------------------------------------------------
00452     template<class Clip> 
00453     void rasterizer_scanline_aa<Clip>::edge_d(double x1, double y1, 
00454                                               double x2, double y2)
00455     {
00456         if(m_outline.sorted()) reset();
00457         m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); 
00458         m_clipper.line_to(m_outline, 
00459                           conv_type::upscale(x2), 
00460                           conv_type::upscale(y2)); 
00461         m_status = status_move_to;
00462     }
00463 
00464     //------------------------------------------------------------------------
00465     template<class Clip> 
00466     void rasterizer_scanline_aa<Clip>::sort()
00467     {
00468         if(m_auto_close) close_polygon();
00469         m_outline.sort_cells();
00470     }
00471 
00472     //------------------------------------------------------------------------
00473     template<class Clip> 
00474     AGG_INLINE bool rasterizer_scanline_aa<Clip>::rewind_scanlines()
00475     {
00476         if(m_auto_close) close_polygon();
00477         m_outline.sort_cells();
00478         if(m_outline.total_cells() == 0) 
00479         {
00480             return false;
00481         }
00482         m_scan_y = m_outline.min_y();
00483         return true;
00484     }
00485 
00486 
00487     //------------------------------------------------------------------------
00488     template<class Clip> 
00489     AGG_INLINE bool rasterizer_scanline_aa<Clip>::navigate_scanline(int y)
00490     {
00491         if(m_auto_close) close_polygon();
00492         m_outline.sort_cells();
00493         if(m_outline.total_cells() == 0 || 
00494            y < m_outline.min_y() || 
00495            y > m_outline.max_y()) 
00496         {
00497             return false;
00498         }
00499         m_scan_y = y;
00500         return true;
00501     }
00502 
00503     //------------------------------------------------------------------------
00504     template<class Clip> 
00505     bool rasterizer_scanline_aa<Clip>::hit_test(int tx, int ty)
00506     {
00507         if(!navigate_scanline(ty)) return false;
00508         scanline_hit_test sl(tx);
00509         sweep_scanline(sl);
00510         return sl.hit();
00511     }
00512 
00513 
00514 
00515 }
00516 
00517 
00518 
00519 #endif
00520 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines