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

flash_rasterizer.cpp

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

© sourcejam.com 2005-2008