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
00090 path_style style;
00091 style.path_id = m_path.start_new_path();
00092 ts = strtok(buf, space);
00093 ts = strtok(0, space);
00094 style.left_fill = atoi(ts);
00095 ts = strtok(0, space);
00096 style.right_fill = atoi(ts);
00097 ts = strtok(0, space);
00098 style.line = atoi(ts);
00099 ts = strtok(0, space);
00100 ax = atof(ts);
00101 ts = strtok(0, space);
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);
00111 ts = strtok(0, space);
00112 cx = atof(ts);
00113 ts = strtok(0, space);
00114 cy = atof(ts);
00115 ts = strtok(0, space);
00116 ax = atof(ts);
00117 ts = strtok(0, space);
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);
00125 ts = strtok(0, space);
00126 ax = atof(ts);
00127 ts = strtok(0, space);
00128 ay = atof(ts);
00129 m_path.line_to(ax, ay);
00130 }
00131
00132
00133 if(buf[0] == '<')
00134 {
00135
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
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
00243
00244 bool is_solid(unsigned style) const
00245 {
00246 return style != 1;
00247 }
00248
00249
00250
00251 const rgba8& color(unsigned style) const
00252 {
00253 return m_solid_colors[style];
00254 }
00255
00256
00257
00258
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
00362
00363 rasc.clip_box(0, 0, width(), height());
00364 rasc.reset();
00365
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
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
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