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
00092 path_style style;
00093 style.path_id = m_path.start_new_path();
00094 ts = strtok(buf, space);
00095 ts = strtok(0, space);
00096 style.left_fill = atoi(ts);
00097 ts = strtok(0, space);
00098 style.right_fill = atoi(ts);
00099 ts = strtok(0, space);
00100 style.line = atoi(ts);
00101 ts = strtok(0, space);
00102 ax = atof(ts);
00103 ts = strtok(0, space);
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);
00123 ts = strtok(0, space);
00124 cx = atof(ts);
00125 ts = strtok(0, space);
00126 cy = atof(ts);
00127 ts = strtok(0, space);
00128 ax = atof(ts);
00129 ts = strtok(0, space);
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);
00137 ts = strtok(0, space);
00138 ax = atof(ts);
00139 ts = strtok(0, space);
00140 ay = atof(ts);
00141 m_path.line_to(ax, ay);
00142 }
00143
00144 if(buf[0] == '<')
00145 {
00146
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
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 ras.auto_close(false);
00348
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
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