Anti-Grain Geometry - AGG (libagg)
2.5
|
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