virtual void on_key(int x, int y, unsigned key, unsigned flags) { if(key == ' ') { m_shape.read_next(); m_shape.scale(width(), height()); force_redraw(); } if(key == '+' || key == agg::key_kp_plus) { m_scale *= agg::trans_affine_translation(-x, -y); m_scale *= agg::trans_affine_scaling(1.1); m_scale *= agg::trans_affine_translation(x, y); force_redraw(); } if(key == '-' || key == agg::key_kp_minus) { m_scale *= agg::trans_affine_translation(-x, -y); m_scale *= agg::trans_affine_scaling(1/1.1); m_scale *= agg::trans_affine_translation(x, y); force_redraw(); } if(key == agg::key_left) { m_scale *= agg::trans_affine_translation(-x, -y); m_scale *= agg::trans_affine_rotation(-agg::pi / 20.0); m_scale *= agg::trans_affine_translation(x, y); force_redraw(); } if(key == agg::key_right) { m_scale *= agg::trans_affine_translation(-x, -y); m_scale *= agg::trans_affine_rotation(agg::pi / 20.0); m_scale *= agg::trans_affine_translation(x, y); force_redraw(); } }
void on_mouse_button_down(int x, int y, unsigned flags) { if(flags & 1) { double xd = x; double yd = y; double r = 4.0 / m_scale.scale(); m_scale.inverse_transform(&xd, &yd); m_point_idx = m_shape.hit_test(xd, yd, r); force_redraw(); } }
void on_mouse_move(int x, int y, unsigned flags) { if((flags & 1) == 0) { on_mouse_button_up(x, y, flags); } else { if(m_point_idx >= 0) { double xd = x; double yd = y; m_scale.inverse_transform(&xd, &yd); m_shape.modify_vertex(m_point_idx, xd, yd); force_redraw(); } } }
virtual void on_draw() { typedef agg::renderer_base<pixfmt_pre> renderer_base; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_scanline; typedef agg::scanline_u8 scanline; pixfmt_pre pixf(rbuf_window()); renderer_base ren_base(pixf); ren_base.clear(agg::rgba(1.0, 1.0, 0.95)); renderer_scanline ren(ren_base); agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl> ras; agg::scanline_u8 sl; agg::conv_transform<agg::compound_shape> shape(m_shape, m_scale); agg::conv_stroke<agg::conv_transform<agg::compound_shape> > stroke(shape); m_shape.approximation_scale(m_scale.scale()); unsigned i; agg::path_storage tmp_path; ras.clip_box(0, 0, width(), height()); // This is an alternative method of Flash rasterization. // We decompose the compound shape into separate paths // and select the ones that fit the given style (left or right). // So that, we form a sub-shape and draw it as a whole. // // Here the regular scanline rasterizer is used, but it doesn't // automatically close the polygons. So that, the rasterizer // actually works with a set of polylines instead of polygons. // Of course, the data integrity must be preserved, that is, // the polylines must eventually form a closed contour // (or a set of closed contours). So that, first we set // auto_close(false); // // The second important thing is that one path can be rasterized // twice, if it has both, left and right fill. Sometimes the // path has equal left and right fill, so that, the same path // will be added twice even for a single sub-shape. If the // rasterizer can tolerate these degenerates you can add them, // but it's also fine just to omit them. // // The third thing is that for one side (left or right) // you should invert the direction of the paths. // // The main disadvantage of this method is imperfect stitching // of the adjacent polygons. The problem can be solved if we use // compositing operation "plus" instead of alpha-blend. But // in this case we are forced to use an RGBA buffer, clean it with // zero, rasterize using "plus" operation, and then alpha-blend // the result over the final scene. It can be too expensive. //------------------------------------------------------------ ras.auto_close(false); //ras.filling_rule(agg::fill_even_odd); start_timer(); for(int s = m_shape.min_style(); s <= m_shape.max_style(); s++) { ras.reset(); for(i = 0; i < m_shape.paths(); i++) { const agg::path_style& style = m_shape.style(i); if(style.left_fill != style.right_fill) { if(style.left_fill == s) { ras.add_path(shape, style.path_id); } if(style.right_fill == s) { tmp_path.remove_all(); tmp_path.concat_path(shape, style.path_id); tmp_path.invert_polygon(0); ras.add_path(tmp_path); } } } agg::render_scanlines_aa_solid(ras, sl, ren_base, m_colors[s]); } double tfill = elapsed_time(); ras.auto_close(true); // Draw strokes //---------------------- start_timer(); stroke.width(sqrt(m_scale.scale())); stroke.line_join(agg::round_join); stroke.line_cap(agg::round_cap); for(i = 0; i < m_shape.paths(); i++) { ras.reset(); if(m_shape.style(i).line >= 0) { ras.add_path(stroke, m_shape.style(i).path_id); ren.color(agg::srgba8(0,0,0, 128)); agg::render_scanlines(ras, sl, ren); } } double tstroke = elapsed_time(); char buf[256]; agg::gsv_text t; t.size(8.0); t.flip(true); agg::conv_stroke<agg::gsv_text> ts(t); ts.width(1.6); ts.line_cap(agg::round_cap); sprintf(buf, "Fill=%.2fms (%dFPS) Stroke=%.2fms (%dFPS) Total=%.2fms (%dFPS)\n\n" "Space: Next Shape\n\n" "+/- : ZoomIn/ZoomOut (with respect to the mouse pointer)", tfill, int(1000.0 / tfill), tstroke, int(1000.0 / tstroke), tfill+tstroke, int(1000.0 / (tfill+tstroke))); t.start_point(10.0, 20.0); t.text(buf); ras.add_path(ts); ren.color(agg::rgba(0,0,0)); agg::render_scanlines(ras, sl, ren); }
void read_next() { m_shape.read_next(); m_shape.scale(width(), height()); }
bool open(const char* fname) { return m_shape.open(full_file_name(fname)); }
virtual void on_draw() { typedef agg::renderer_base<pixfmt> renderer_base; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_scanline; typedef agg::scanline_u8 scanline; pixfmt pixf(rbuf_window()); renderer_base ren_base(pixf); ren_base.clear(agg::rgba(1.0, 1.0, 0.95)); renderer_scanline ren(ren_base); unsigned i; unsigned w = unsigned(width()); m_gradient.resize(w); agg::rgba8 c1(255, 0, 0, 180); agg::rgba8 c2(0, 0, 255, 180); for(i = 0; i < w; i++) { m_gradient[i] = c1.gradient(c2, i / width()); m_gradient[i].premultiply(); } agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl> ras; agg::rasterizer_compound_aa<agg::rasterizer_sl_clip_dbl> rasc; agg::scanline_u8 sl; agg::scanline_bin sl_bin; agg::conv_transform<agg::compound_shape> shape(m_shape, m_scale); agg::conv_stroke<agg::conv_transform<agg::compound_shape> > stroke(shape); agg::test_styles style_handler(m_colors, m_gradient.data()); agg::span_allocator<agg::rgba8> alloc; m_shape.approximation_scale(m_scale.scale()); // Fill shape //---------------------- rasc.clip_box(0, 0, width(), height()); rasc.reset(); //rasc.filling_rule(agg::fill_even_odd); start_timer(); for(i = 0; i < m_shape.paths(); i++) { if(m_shape.style(i).left_fill >= 0 || m_shape.style(i).right_fill >= 0) { rasc.styles(m_shape.style(i).left_fill, m_shape.style(i).right_fill); rasc.add_path(shape, m_shape.style(i).path_id); } } agg::render_scanlines_compound(rasc, sl, sl_bin, ren_base, alloc, style_handler); double tfill = elapsed_time(); // Hit-test test bool draw_strokes = true; if(m_hit_x >= 0 && m_hit_y >= 0) { if(rasc.hit_test(m_hit_x, m_hit_y)) { draw_strokes = false; } } // Draw strokes //---------------------- start_timer(); if(draw_strokes) { ras.clip_box(0, 0, width(), height()); stroke.width(sqrt(m_scale.scale())); stroke.line_join(agg::round_join); stroke.line_cap(agg::round_cap); for(i = 0; i < m_shape.paths(); i++) { ras.reset(); if(m_shape.style(i).line >= 0) { ras.add_path(stroke, m_shape.style(i).path_id); ren.color(agg::rgba8(0,0,0, 128)); agg::render_scanlines(ras, sl, ren); } } } double tstroke = elapsed_time(); char buf[256]; agg::gsv_text t; t.size(8.0); t.flip(true); agg::conv_stroke<agg::gsv_text> ts(t); ts.width(1.6); ts.line_cap(agg::round_cap); sprintf(buf, "Fill=%.2fms (%dFPS) Stroke=%.2fms (%dFPS) Total=%.2fms (%dFPS)\n\n" "Space: Next Shape\n\n" "+/- : ZoomIn/ZoomOut (with respect to the mouse pointer)", tfill, int(1000.0 / tfill), tstroke, int(1000.0 / tstroke), tfill+tstroke, int(1000.0 / (tfill+tstroke))); t.start_point(10.0, 20.0); t.text(buf); ras.add_path(ts); ren.color(agg::rgba(0,0,0)); agg::render_scanlines(ras, sl, ren); if(m_gamma.gamma() != 1.0) { pixf.apply_gamma_inv(m_gamma); } }