Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

flash_rasterizer2.cpp

Go to the documentation of this file.
00001 #include <math.h>
00002 #include <stdio.h>
00003 #include <time.h>
00004 #include "agg_rendering_buffer.h"
00005 #include "agg_trans_viewport.h"
00006 #include "agg_path_storage.h"
00007 #include "agg_conv_transform.h"
00008 #include "agg_conv_curve.h"
00009 #include "agg_conv_stroke.h"
00010 #include "agg_gsv_text.h"
00011 #include "agg_scanline_u.h"
00012 #include "agg_scanline_bin.h"
00013 #include "agg_renderer_scanline.h"
00014 #include "agg_rasterizer_outline_aa.h"
00015 #include "agg_rasterizer_scanline_aa.h"
00016 #include "agg_span_allocator.h"
00017 #include "agg_gamma_lut.h"
00018 #include "agg_pixfmt_rgba.h"
00019 #include "agg_bounding_rect.h"
00020 #include "platform/agg_platform_support.h"
00021 
00022 
00023 enum { flip_y = false };
00024 
00025 typedef agg::pixfmt_bgra32_pre pixfmt;
00026 
00027 
00028 
00029 namespace agg
00030 {
00031     struct path_style
00032     {
00033         unsigned path_id;
00034         int left_fill;
00035         int right_fill;
00036         int line;
00037     };
00038 
00039     class compound_shape
00040     {
00041     public:
00042         ~compound_shape() 
00043         { 
00044             if(m_fd)
00045             {
00046                 fclose(m_fd);
00047             }
00048         }
00049 
00050         compound_shape() :
00051             m_path(),
00052             m_affine(),
00053             m_curve(m_path),
00054             m_trans(m_curve, m_affine),
00055             m_styles(),
00056             m_min_style(0x7FFFFFFF),
00057             m_max_style(-0x7FFFFFFF)
00058         {}
00059 
00060         bool open(const char* fname)
00061         {
00062             m_fd = fopen(fname, "r");
00063             return m_fd != 0;
00064         }
00065 
00066         bool read_next()
00067         {
00068             m_path.remove_all();
00069             m_styles.remove_all();
00070             m_min_style = 0x7FFFFFFF;
00071             m_max_style = -0x7FFFFFFF;
00072 
00073             const char space[] = " \t\n\r";
00074             double ax, ay, cx, cy;
00075             if(m_fd)
00076             {
00077                 char buf[1024];
00078                 char* ts;
00079 
00080                 for(;;)
00081                 {
00082                     if(fgets(buf, 1022, m_fd) == 0) return false;
00083                     if(buf[0] == '=') break;
00084                 }
00085 
00086                 while(fgets(buf, 1022, m_fd))
00087                 {
00088                     if(buf[0] == '!') break;
00089                     if(buf[0] == 'P')
00090                     {
00091                         // BeginPath
00092                         path_style style;
00093                         style.path_id = m_path.start_new_path();
00094                         ts = strtok(buf, space); // Path;
00095                         ts = strtok(0, space);  // left_style
00096                         style.left_fill = atoi(ts);
00097                         ts = strtok(0, space);  // right_style
00098                         style.right_fill = atoi(ts);
00099                         ts = strtok(0, space);  // line_style
00100                         style.line = atoi(ts);
00101                         ts = strtok(0, space);  // ax
00102                         ax = atof(ts);
00103                         ts = strtok(0, space);  // ay
00104                         ay = atof(ts);
00105                         m_path.move_to(ax, ay);
00106                         m_styles.add(style);
00107                         if(style.left_fill >= 0)
00108                         {
00109                             if(style.left_fill < m_min_style) m_min_style = style.left_fill;
00110                             if(style.left_fill > m_max_style) m_max_style = style.left_fill;
00111                         }
00112                         if(style.right_fill >= 0)
00113                         {
00114                             if(style.right_fill < m_min_style) m_min_style = style.right_fill;
00115                             if(style.right_fill > m_max_style) m_max_style = style.right_fill;
00116                         }
00117                     }
00118 
00119 
00120                     if(buf[0] == 'C')
00121                     {
00122                         ts = strtok(buf, space); // Curve;
00123                         ts = strtok(0, space);  // cx
00124                         cx = atof(ts);
00125                         ts = strtok(0, space);  // cy
00126                         cy = atof(ts);
00127                         ts = strtok(0, space);  // ax
00128                         ax = atof(ts);
00129                         ts = strtok(0, space);  // ay
00130                         ay = atof(ts);
00131                         m_path.curve3(cx, cy, ax, ay);
00132                     }
00133 
00134                     if(buf[0] == 'L')
00135                     {
00136                         ts = strtok(buf, space); // Line;
00137                         ts = strtok(0, space);  // ax
00138                         ax = atof(ts);
00139                         ts = strtok(0, space);  // ay
00140                         ay = atof(ts);
00141                         m_path.line_to(ax, ay);
00142                     }
00143 
00144                     if(buf[0] == '<')
00145                     {
00146                         // EndPath
00147                     }
00148                 }
00149                 return true;
00150             }
00151             return false;
00152         }
00153 
00154         unsigned operator [] (unsigned i) const 
00155         {
00156             return m_styles[i].path_id;
00157         }
00158 
00159         unsigned paths() const { return m_styles.size(); }
00160         const path_style& style(unsigned i) const
00161         {
00162             return m_styles[i];
00163         }
00164 
00165         int min_style() const { return m_min_style; }
00166         int max_style() const { return m_max_style; }
00167 
00168         void rewind(unsigned path_id)
00169         {
00170             m_trans.rewind(path_id);
00171         }
00172 
00173         unsigned vertex(double* x, double* y)
00174         {
00175             return m_trans.vertex(x, y);
00176         }
00177 
00178         double scale() const
00179         {
00180             return m_affine.scale();
00181         }
00182 
00183         void scale(double w, double h)
00184         {
00185             m_affine.reset();
00186             double x1, y1, x2, y2;
00187             bounding_rect(m_path, *this, 0, m_styles.size(), 
00188                           &x1, &y1, &x2, &y2);
00189             if(x1 < x2 && y1 < y2)
00190             {
00191                 trans_viewport vp;
00192                 vp.preserve_aspect_ratio(0.5, 0.5, aspect_ratio_meet);
00193                 vp.world_viewport(x1, y1, x2, y2);
00194                 vp.device_viewport(0, 0, w, h);
00195                 m_affine = vp.to_affine();
00196             }
00197             m_curve.approximation_scale(m_affine.scale());
00198         }
00199 
00200         void approximation_scale(double s)
00201         {
00202             m_curve.approximation_scale(m_affine.scale() * s);
00203         }
00204 
00205         int hit_test(double x, double y, double r)
00206         {
00207             m_affine.inverse_transform(&x, &y);
00208             r /= m_affine.scale();
00209             unsigned i;
00210             for(i = 0; i < m_path.total_vertices(); i++)
00211             {
00212                 double vx, vy;
00213                 unsigned cmd = m_path.vertex(i, &vx, &vy);
00214                 if(is_vertex(cmd))
00215                 {
00216                     if(calc_distance(x, y, vx, vy) <= r)
00217                     {
00218                         return i;
00219                     }
00220                 }
00221             }
00222             return -1;
00223         }
00224 
00225         void modify_vertex(unsigned i, double x, double y)
00226         {
00227             m_affine.inverse_transform(&x, &y);
00228             m_path.modify_vertex(i, x, y);
00229         }
00230 
00231     private:
00232         path_storage                              m_path;
00233         trans_affine                              m_affine;
00234         conv_curve<path_storage>                  m_curve;
00235         conv_transform<conv_curve<path_storage> > m_trans;
00236         pod_bvector<path_style>                   m_styles;
00237         double                                    m_x1, m_y1, m_x2, m_y2;
00238         int                                       m_min_style;
00239         int                                       m_max_style;
00240 
00241         FILE* m_fd;
00242     };
00243 
00244 }
00245 
00246 
00247 
00248 
00249 
00250 
00251 class the_application : public agg::platform_support
00252 {
00253 
00254 public:
00255     agg::compound_shape        m_shape;
00256     agg::rgba8                 m_colors[100];
00257     agg::trans_affine          m_scale;
00258     agg::gamma_lut<>           m_gamma;
00259     int                        m_point_idx;
00260 
00261 
00262     the_application(agg::pix_format_e format, bool flip_y) :
00263         agg::platform_support(format, flip_y),
00264         m_point_idx(-1)
00265     {
00266         m_gamma.gamma(2.0);
00267 
00268         for(unsigned i = 0; i < 100; i++)
00269         {
00270             m_colors[i] = agg::rgba8(
00271                 (rand() & 0xFF), 
00272                 (rand() & 0xFF), 
00273                 (rand() & 0xFF), 
00274                 230);
00275 
00276             m_colors[i].apply_gamma_dir(m_gamma);
00277             m_colors[i].premultiply();
00278         }
00279     }
00280 
00281 
00282 
00283     bool open(const char* fname)
00284     {
00285         return m_shape.open(full_file_name(fname));
00286     }
00287 
00288     void read_next()
00289     {
00290         m_shape.read_next();
00291         m_shape.scale(width(), height());
00292     }
00293 
00294     virtual void on_draw()
00295     {
00296         typedef agg::renderer_base<pixfmt> renderer_base;
00297         typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_scanline;
00298         typedef agg::scanline_u8 scanline;
00299 
00300         pixfmt pixf(rbuf_window());
00301         renderer_base ren_base(pixf);
00302         ren_base.clear(agg::rgba(1.0, 1.0, 0.95));
00303         renderer_scanline ren(ren_base);
00304 
00305         agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl> ras;
00306         agg::scanline_u8 sl;
00307         agg::conv_transform<agg::compound_shape> shape(m_shape, m_scale);
00308         agg::conv_stroke<agg::conv_transform<agg::compound_shape> > stroke(shape);
00309 
00310         m_shape.approximation_scale(m_scale.scale());
00311 
00312         unsigned i;
00313         agg::path_storage tmp_path;
00314 
00315         ras.clip_box(0, 0, width(), height());
00316 
00317         // This is an alternative method of Flash rasterization. 
00318         // We decompose the compound shape into separate paths
00319         // and select the ones that fit the given style (left or right).
00320         // So that, we form a sub-shape and draw it as a whole.
00321         // 
00322         // Here the regular scanline rasterizer is used, but it doesn't
00323         // automatically close the polygons. So that, the rasterizer 
00324         // actually works with a set of polylines instead of polygons.
00325         // Of course, the data integrity must be preserved, that is, 
00326         // the polylines must eventually form a closed contour
00327         // (or a set of closed contours). So that, first we set 
00328         // auto_close(false);
00329         // 
00330         // The second important thing is that one path can be rasterized 
00331         // twice, if it has both, left and right fill. Sometimes the 
00332         // path has equal left and right fill, so that, the same path
00333         // will be added twice even for a single sub-shape. If the 
00334         // rasterizer can tolerate these degenerates you can add them, 
00335         // but it's also fine just to omit them.
00336         //
00337         // The third thing is that for one side (left or right)
00338         // you should invert the direction of the paths.
00339         //
00340         // The main disadvantage of this method is imperfect stitching
00341         // of the adjacent polygons. The problem can be solved if we use
00342         // compositing operation "plus" instead of alpha-blend. But
00343         // in this case we are forced to use an RGBA buffer, clean it with 
00344         // zero, rasterize using "plus" operation, and then alpha-blend
00345         // the result over the final scene. It can be too expensive.
00346         //------------------------------------------------------------
00347         ras.auto_close(false);
00348         //ras.filling_rule(agg::fill_even_odd);
00349         start_timer();
00350         for(int s = m_shape.min_style(); s <= m_shape.max_style(); s++)
00351         {
00352             ras.reset();
00353             for(i = 0; i < m_shape.paths(); i++)
00354             {
00355                 const agg::path_style& style = m_shape.style(i);
00356                 if(style.left_fill != style.right_fill)
00357                 {
00358                     if(style.left_fill == s)
00359                     {
00360                         ras.add_path(shape, style.path_id);
00361                     }
00362                     if(style.right_fill == s)
00363                     {
00364                         tmp_path.remove_all();
00365                         tmp_path.concat_path(shape, style.path_id);
00366                         tmp_path.invert_polygon(0);
00367                         ras.add_path(tmp_path);
00368                     }
00369                 }
00370             }
00371             agg::render_scanlines_aa_solid(ras, sl, ren_base, m_colors[s]);
00372         }
00373         double tfill = elapsed_time();
00374         ras.auto_close(true);
00375 
00376         // Draw strokes
00377         //----------------------
00378         start_timer();
00379         stroke.width(sqrt(m_scale.scale()));
00380         stroke.line_join(agg::round_join);
00381         stroke.line_cap(agg::round_cap);
00382         for(i = 0; i < m_shape.paths(); i++)
00383         {
00384             ras.reset();
00385             if(m_shape.style(i).line >= 0)
00386             {
00387                 ras.add_path(stroke, m_shape.style(i).path_id);
00388                 ren.color(agg::rgba8(0,0,0, 128));
00389                 agg::render_scanlines(ras, sl, ren);
00390             }
00391         }
00392         double tstroke = elapsed_time();
00393 
00394 
00395         char buf[256]; 
00396         agg::gsv_text t;
00397         t.size(8.0);
00398         t.flip(true);
00399 
00400         agg::conv_stroke<agg::gsv_text> ts(t);
00401         ts.width(1.6);
00402         ts.line_cap(agg::round_cap);
00403 
00404         sprintf(buf, "Fill=%.2fms (%dFPS) Stroke=%.2fms (%dFPS) Total=%.2fms (%dFPS)\n\n"
00405                      "Space: Next Shape\n\n"
00406                      "+/- : ZoomIn/ZoomOut (with respect to the mouse pointer)",
00407                      tfill, int(1000.0 / tfill),
00408                      tstroke, int(1000.0 / tstroke),
00409                      tfill+tstroke, int(1000.0 / (tfill+tstroke)));
00410 
00411         t.start_point(10.0, 20.0);
00412         t.text(buf);
00413 
00414         ras.add_path(ts);
00415         ren.color(agg::rgba(0,0,0));
00416         agg::render_scanlines(ras, sl, ren);
00417 
00418         if(m_gamma.gamma() != 1.0)
00419         {
00420             pixf.apply_gamma_inv(m_gamma);
00421         }
00422     }
00423 
00424     
00425     virtual void on_key(int x, int y, unsigned key, unsigned flags)
00426     {
00427         if(key == ' ')
00428         {
00429             m_shape.read_next();
00430             m_shape.scale(width(), height());
00431             force_redraw();
00432         }
00433 
00434         if(key == '+' || key == agg::key_kp_plus)
00435         {
00436             m_scale *= agg::trans_affine_translation(-x, -y);
00437             m_scale *= agg::trans_affine_scaling(1.1);
00438             m_scale *= agg::trans_affine_translation(x, y);
00439             force_redraw();
00440         }
00441 
00442         if(key == '-' || key == agg::key_kp_minus)
00443         {
00444             m_scale *= agg::trans_affine_translation(-x, -y);
00445             m_scale *= agg::trans_affine_scaling(1/1.1);
00446             m_scale *= agg::trans_affine_translation(x, y);
00447             force_redraw();
00448         }
00449 
00450         if(key == agg::key_left)
00451         {
00452             m_scale *= agg::trans_affine_translation(-x, -y);
00453             m_scale *= agg::trans_affine_rotation(-agg::pi / 20.0);
00454             m_scale *= agg::trans_affine_translation(x, y);
00455             force_redraw();
00456         }
00457 
00458         if(key == agg::key_right)
00459         {
00460             m_scale *= agg::trans_affine_translation(-x, -y);
00461             m_scale *= agg::trans_affine_rotation(agg::pi / 20.0);
00462             m_scale *= agg::trans_affine_translation(x, y);
00463             force_redraw();
00464         }
00465     }
00466 
00467     void on_mouse_move(int x, int y, unsigned flags) 
00468     {
00469         if((flags & 1) == 0)
00470         {
00471             on_mouse_button_up(x, y, flags);
00472         }
00473         else
00474         {
00475             if(m_point_idx >= 0)
00476             {
00477                 double xd = x;
00478                 double yd = y;
00479                 m_scale.inverse_transform(&xd, &yd);
00480                 m_shape.modify_vertex(m_point_idx, xd, yd);
00481                 force_redraw();
00482             }
00483         }
00484     }
00485 
00486     void on_mouse_button_down(int x, int y, unsigned flags) 
00487     {
00488         if(flags & 1)
00489         {
00490             double xd = x;
00491             double yd = y;
00492             double r = 4.0 / m_scale.scale();
00493             m_scale.inverse_transform(&xd, &yd);
00494             m_point_idx = m_shape.hit_test(xd, yd, r);
00495             force_redraw();
00496         }
00497     }
00498 
00499     void on_mouse_button_up(int x, int y, unsigned flags) 
00500     {
00501         m_point_idx = -1;
00502     }
00503 
00504 
00505 };
00506 
00507 
00508 
00509 int agg_main(int argc, char* argv[])
00510 {
00511     the_application app(agg::pix_format_bgra32, flip_y);
00512     app.caption("AGG Example - Flash Rasterizer");
00513     const char* fname = "shapes.txt";
00514     if(argc > 1) fname = argv[1];
00515     if(!app.open(fname))
00516     {
00517         char buf[256];
00518         if(strcmp(fname, "shapes.txt") == 0)
00519         {
00520             sprintf(buf, "File not found: %s. Download http://www.antigrain.com/%s\n"
00521                          "or copy it from another directory if available.",
00522                     fname, fname);
00523         }
00524         else
00525         {
00526             sprintf(buf, "File not found: %s", fname);
00527         }
00528         app.message(buf);
00529         return 1;
00530     }
00531 
00532     if(app.init(655, 520, agg::window_resize))
00533     {
00534         app.read_next();
00535         return app.run();
00536     }
00537     return 1;
00538 }
00539 
00540 
00541 
00542 
00543 

© sourcejam.com 2005-2008