#include <stdio.h> #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_rasterizer_scanline_aa.h" #include "agg_scanline_u.h" #include "agg_scanline_p.h" #include "agg_scanline_bin.h" #include "agg_renderer_scanline.h" #include "agg_renderer_primitives.h" #include "agg_span_solid.h" #include "agg_conv_curve.h" #include "agg_conv_stroke.h" #include "agg_gsv_text.h" #include "agg_pixfmt_rgb.h" #include "agg_scanline_boolean_algebra.h" #include "agg_scanline_storage_aa.h" #include "agg_scanline_storage_bin.h" #include "platform/agg_platform_support.h" #include "ctrl/agg_slider_ctrl.h" #include "ctrl/agg_cbox_ctrl.h" #include "ctrl/agg_rbox_ctrl.h" enum flip_y_e { flip_y = true }; class spiral { public: spiral(double x, double y, double r1, double r2, double step, double start_angle=0) : m_x(x), m_y(y), m_r1(r1), m_r2(r2), m_step(step), m_start_angle(start_angle), m_angle(start_angle), m_da(agg::deg2rad(4.0)), m_dr(m_step / 90.0) { } void rewind(unsigned) { m_angle = m_start_angle; m_curr_r = m_r1; m_start = true; } unsigned vertex(double* x, double* y) { if(m_curr_r > m_r2) return agg::path_cmd_stop; *x = m_x + cos(m_angle) * m_curr_r; *y = m_y + sin(m_angle) * m_curr_r; m_curr_r += m_dr; m_angle += m_da; if(m_start) { m_start = false; return agg::path_cmd_move_to; } return agg::path_cmd_line_to; } private: double m_x; double m_y; double m_r1; double m_r2; double m_step; double m_start_angle; double m_angle; double m_curr_r; double m_da; double m_dr; bool m_start; }; template<class Rasterizer, class Scanline> unsigned count_spans(Rasterizer& ras, Scanline& sl) { unsigned n = 0; if(ras.rewind_scanlines()) { sl.reset(ras.min_x(), ras.max_x()); while(ras.sweep_scanline(sl)) { n += sl.num_spans(); } } return n; } void make_gb_poly(agg::path_storage& ps); void make_arrows(agg::path_storage& ps); class the_application : public agg::platform_support { typedef agg::pixfmt_bgr24 pixfmt_type; agg::rbox_ctrl<agg::rgba8> m_polygons; agg::rbox_ctrl<agg::rgba8> m_fill_rule; agg::rbox_ctrl<agg::rgba8> m_scanline_type; agg::rbox_ctrl<agg::rgba8> m_operation; double m_x; double m_y; public: the_application(agg::pix_format_e format, bool flip_y) : agg::platform_support(format, flip_y), m_polygons (5.0, 5.0, 5.0+205.0, 110.0, !flip_y), m_fill_rule (200, 5.0, 200+105.0, 50.0, !flip_y), m_scanline_type(300, 5.0, 300+115.0, 70.0, !flip_y), m_operation (535.0, 5.0, 535.0+115.0, 145.0, !flip_y) { m_operation.add_item("None"); m_operation.add_item("OR"); m_operation.add_item("AND"); m_operation.add_item("XOR Linear"); m_operation.add_item("XOR Saddle"); m_operation.add_item("A-B"); m_operation.add_item("B-A"); m_operation.cur_item(2); add_ctrl(m_operation); m_operation.no_transform(); m_fill_rule.add_item("Even-Odd"); m_fill_rule.add_item("Non Zero"); m_fill_rule.cur_item(1); add_ctrl(m_fill_rule); m_fill_rule.no_transform(); m_scanline_type.add_item("scanline_p"); m_scanline_type.add_item("scanline_u"); m_scanline_type.add_item("scanline_bin"); m_scanline_type.cur_item(1); add_ctrl(m_scanline_type); m_scanline_type.no_transform(); m_polygons.add_item("Two Simple Paths"); m_polygons.add_item("Closed Stroke"); m_polygons.add_item("Great Britain and Arrows"); m_polygons.add_item("Great Britain and Spiral"); m_polygons.add_item("Spiral and Glyph"); m_polygons.cur_item(3); add_ctrl(m_polygons); m_polygons.no_transform(); } template<class Rasterizer> void render_scanline_boolean(Rasterizer& ras1, Rasterizer& ras2) { if(m_operation.cur_item() > 0) { agg::sbool_op_e op; switch(m_operation.cur_item()) { case 1: op = agg::sbool_or; break; case 2: op = agg::sbool_and; break; case 3: op = agg::sbool_xor; break; case 4: op = agg::sbool_xor_saddle;break; case 5: op = agg::sbool_a_minus_b; break; case 6: op = agg::sbool_b_minus_a; break; } typedef agg::renderer_base<pixfmt_type> renderer_base; pixfmt_type pixf(rbuf_window()); renderer_base rb(pixf); double t1 = 0.0; double t2 = 0.0; unsigned num_spans = 0; switch(m_scanline_type.cur_item()) { case 0: { typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid; typedef agg::scanline_p8 scanline_type; renderer_solid ren(rb); scanline_type sl; scanline_type sl1; scanline_type sl2; // The intermediate storage is used only to test the perfoprmance, // the short variant can be as follows: // ------------------------ // ren.color(agg::rgba(0.5, 0.0, 0, 0.5)); // agg::sbool_combine_shapes_aa(op, ras1, ras2, sl1, sl2, sl, ren); agg::scanline_storage_aa8 storage; agg::scanline_storage_aa8 storage1; agg::scanline_storage_aa8 storage2; agg::render_scanlines(ras1, sl, storage1); agg::render_scanlines(ras2, sl, storage2); start_timer(); for(int i = 0; i < 10; i++) { agg::sbool_combine_shapes_aa(op, storage1, storage2, sl1, sl2, sl, storage); } t1 = elapsed_time() / 10.0; start_timer(); ren.color(agg::rgba(0.5, 0.0, 0, 0.5)); agg::render_scanlines(storage, sl, ren); t2 = elapsed_time(); num_spans = count_spans(storage, sl); } break; case 1: { typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid; typedef agg::scanline_u8 scanline_type; renderer_solid ren(rb); scanline_type sl; scanline_type sl1; scanline_type sl2; agg::scanline_storage_aa8 storage; agg::scanline_storage_aa8 storage1; agg::scanline_storage_aa8 storage2; agg::render_scanlines(ras1, sl, storage1); agg::render_scanlines(ras2, sl, storage2); start_timer(); for(int i = 0; i < 10; i++) { agg::sbool_combine_shapes_aa(op, storage1, storage2, sl1, sl2, sl, storage); } t1 = elapsed_time() / 10.0; start_timer(); ren.color(agg::rgba(0.5, 0.0, 0, 0.5)); agg::render_scanlines(storage, sl, ren); t2 = elapsed_time(); num_spans = count_spans(storage, sl); } break; case 2: { typedef agg::renderer_scanline_bin_solid<renderer_base> renderer_solid; typedef agg::scanline_bin scanline_type; renderer_solid ren(rb); scanline_type sl; scanline_type sl1; scanline_type sl2; agg::scanline_storage_bin storage; agg::scanline_storage_bin storage1; agg::scanline_storage_bin storage2; agg::render_scanlines(ras1, sl, storage1); agg::render_scanlines(ras2, sl, storage2); start_timer(); for(int i = 0; i < 10; i++) { agg::sbool_combine_shapes_bin(op, storage1, storage2, sl1, sl2, sl, storage); } t1 = elapsed_time() / 10.0; start_timer(); ren.color(agg::rgba(0.5, 0.0, 0, 0.5)); agg::render_scanlines(storage, sl, ren); t2 = elapsed_time(); num_spans = count_spans(storage, sl); } break; } char buf[100]; sprintf(buf, "Combine=%.3fms\n\nRender=%.3fms\n\nnum_spans=%d", t1, t2, num_spans); agg::renderer_scanline_aa_solid<renderer_base> ren(rb); agg::scanline_p8 sl; agg::gsv_text txt; agg::conv_stroke<agg::gsv_text> txt_stroke(txt); txt_stroke.width(1.0); txt_stroke.line_cap(agg::round_cap); txt.size(8.0); txt.start_point(420, 40); txt.text(buf); ras1.add_path(txt_stroke); ren.color(agg::rgba(0.0, 0.0, 0.0)); agg::render_scanlines(ras1, sl, ren); } } template<class Rasterizer> unsigned render_sbool(Rasterizer& ras1, Rasterizer& ras2) { pixfmt_type pf(rbuf_window()); agg::renderer_base<pixfmt_type> rb(pf); agg::renderer_scanline_aa_solid<agg::renderer_base<pixfmt_type> > ren(rb); agg::scanline_p8 sl; ras1.filling_rule(m_fill_rule.cur_item() ? agg::fill_non_zero : agg::fill_even_odd); ras2.filling_rule(m_fill_rule.cur_item() ? agg::fill_non_zero : agg::fill_even_odd); switch(m_polygons.cur_item()) { case 0: { //------------------------------------ // Two simple paths // agg::path_storage ps1; agg::path_storage ps2; double x = m_x - initial_width()/2 + 100; double y = m_y - initial_height()/2 + 100; ps1.move_to(x+140, y+145); ps1.line_to(x+225, y+44); ps1.line_to(x+296, y+219); ps1.close_polygon(); ps1.line_to(x+226, y+289); ps1.line_to(x+82, y+292); ps1.move_to(x+220, y+222); ps1.line_to(x+363, y+249); ps1.line_to(x+265, y+331); ps1.move_to(x+242, y+243); ps1.line_to(x+325, y+261); ps1.line_to(x+268, y+309); ps1.move_to(x+259, y+259); ps1.line_to(x+273, y+288); ps1.line_to(x+298, y+266); ps2.move_to(100+32, 100+77); ps2.line_to(100+473, 100+263); ps2.line_to(100+351, 100+290); ps2.line_to(100+354, 100+374); ras1.reset(); ras1.add_path(ps1); ren.color(agg::rgba(0, 0, 0, 0.1)); agg::render_scanlines(ras1, sl, ren); ras2.reset(); ras2.add_path(ps2); ren.color(agg::rgba(0, 0.6, 0, 0.1)); agg::render_scanlines(ras2, sl, ren); render_scanline_boolean(ras1, ras2); } break; case 1: { //------------------------------------ // Closed stroke // agg::path_storage ps1; agg::path_storage ps2; agg::conv_stroke<agg::path_storage> stroke(ps2); stroke.width(15.0); double x = m_x - initial_width()/2 + 100; double y = m_y - initial_height()/2 + 100; ps1.move_to(x+140, y+145); ps1.line_to(x+225, y+44); ps1.line_to(x+296, y+219); ps1.close_polygon(); ps1.line_to(x+226, y+289); ps1.line_to(x+82, y+292); ps1.move_to(x+220-50, y+222); ps1.line_to(x+363-50, y+249); ps1.line_to(x+265-50, y+331); ps1.close_polygon(); ps2.move_to(100+32, 100+77); ps2.line_to(100+473, 100+263); ps2.line_to(100+351, 100+290); ps2.line_to(100+354, 100+374); ps2.close_polygon(); ras1.reset(); ras1.add_path(ps1); ren.color(agg::rgba(0, 0, 0, 0.1)); agg::render_scanlines(ras1, sl, ren); ras2.reset(); ras2.add_path(stroke); ren.color(agg::rgba(0, 0.6, 0, 0.1)); agg::render_scanlines(ras2, sl, ren); render_scanline_boolean(ras1, ras2); } break; case 2: { //------------------------------------ // Great Britain and Arrows // agg::path_storage gb_poly; agg::path_storage arrows; make_gb_poly(gb_poly); make_arrows(arrows); agg::trans_affine mtx1; agg::trans_affine mtx2; mtx1 *= agg::trans_affine_translation(-1150, -1150); mtx1 *= agg::trans_affine_scaling(2.0); mtx2 = mtx1; mtx2 *= agg::trans_affine_translation(m_x - initial_width()/2, m_y - initial_height()/2); agg::conv_transform<agg::path_storage> trans_gb_poly(gb_poly, mtx1); agg::conv_transform<agg::path_storage> trans_arrows(arrows, mtx2); ras2.add_path(trans_gb_poly); ren.color(agg::rgba(0.5, 0.5, 0, 0.1)); agg::render_scanlines(ras2, sl, ren); agg::conv_stroke<agg::conv_transform<agg::path_storage> > stroke_gb_poly(trans_gb_poly); stroke_gb_poly.width(0.1); ras1.add_path(stroke_gb_poly); ren.color(agg::rgba(0, 0, 0)); agg::render_scanlines(ras1, sl, ren); ras2.add_path(trans_arrows); ren.color(agg::rgba(0.0, 0.5, 0.5, 0.1)); agg::render_scanlines(ras2, sl, ren); ras1.reset(); ras1.add_path(trans_gb_poly); render_scanline_boolean(ras1, ras2); } break; case 3: { //------------------------------------ // Great Britain and a Spiral // spiral sp(m_x, m_y, 10, 150, 30, 0.0); agg::conv_stroke<spiral> stroke(sp); stroke.width(15.0); agg::path_storage gb_poly; make_gb_poly(gb_poly); agg::trans_affine mtx; mtx *= agg::trans_affine_translation(-1150, -1150); mtx *= agg::trans_affine_scaling(2.0); mtx *= trans_affine_resizing(); agg::conv_transform<agg::path_storage> trans_gb_poly(gb_poly, mtx); ras1.add_path(trans_gb_poly); ren.color(agg::rgba(0.5, 0.5, 0, 0.1)); agg::render_scanlines(ras1, sl, ren); agg::conv_stroke<agg::conv_transform<agg::path_storage> > stroke_gb_poly(trans_gb_poly); stroke_gb_poly.width(0.1); ras1.reset(); ras1.add_path(stroke_gb_poly); ren.color(agg::rgba(0, 0, 0)); agg::render_scanlines(ras1, sl, ren); ras2.reset(); ras2.add_path(stroke); ren.color(agg::rgba(0.0, 0.5, 0.5, 0.1)); agg::render_scanlines(ras2, sl, ren); ras1.reset(); ras1.add_path(trans_gb_poly); render_scanline_boolean(ras1, ras2); } break; case 4: { //------------------------------------ // Spiral and glyph // spiral sp(m_x, m_y, 10, 150, 30, 0.0); agg::conv_stroke<spiral> stroke(sp); stroke.width(15.0); agg::path_storage glyph; glyph.move_to(28.47, 6.45); glyph.curve3(21.58, 1.12, 19.82, 0.29); glyph.curve3(17.19, -0.93, 14.21, -0.93); glyph.curve3(9.57, -0.93, 6.57, 2.25); glyph.curve3(3.56, 5.42, 3.56, 10.60); glyph.curve3(3.56, 13.87, 5.03, 16.26); glyph.curve3(7.03, 19.58, 11.99, 22.51); glyph.curve3(16.94, 25.44, 28.47, 29.64); glyph.line_to(28.47, 31.40); glyph.curve3(28.47, 38.09, 26.34, 40.58); glyph.curve3(24.22, 43.07, 20.17, 43.07); glyph.curve3(17.09, 43.07, 15.28, 41.41); glyph.curve3(13.43, 39.75, 13.43, 37.60); glyph.line_to(13.53, 34.77); glyph.curve3(13.53, 32.52, 12.38, 31.30); glyph.curve3(11.23, 30.08, 9.38, 30.08); glyph.curve3(7.57, 30.08, 6.42, 31.35); glyph.curve3(5.27, 32.62, 5.27, 34.81); glyph.curve3(5.27, 39.01, 9.57, 42.53); glyph.curve3(13.87, 46.04, 21.63, 46.04); glyph.curve3(27.59, 46.04, 31.40, 44.04); glyph.curve3(34.28, 42.53, 35.64, 39.31); glyph.curve3(36.52, 37.21, 36.52, 30.71); glyph.line_to(36.52, 15.53); glyph.curve3(36.52, 9.13, 36.77, 7.69); glyph.curve3(37.01, 6.25, 37.57, 5.76); glyph.curve3(38.13, 5.27, 38.87, 5.27); glyph.curve3(39.65, 5.27, 40.23, 5.62); glyph.curve3(41.26, 6.25, 44.19, 9.18); glyph.line_to(44.19, 6.45); glyph.curve3(38.72, -0.88, 33.74, -0.88); glyph.curve3(31.35, -0.88, 29.93, 0.78); glyph.curve3(28.52, 2.44, 28.47, 6.45); glyph.close_polygon(); glyph.move_to(28.47, 9.62); glyph.line_to(28.47, 26.66); glyph.curve3(21.09, 23.73, 18.95, 22.51); glyph.curve3(15.09, 20.36, 13.43, 18.02); glyph.curve3(11.77, 15.67, 11.77, 12.89); glyph.curve3(11.77, 9.38, 13.87, 7.06); glyph.curve3(15.97, 4.74, 18.70, 4.74); glyph.curve3(22.41, 4.74, 28.47, 9.62); glyph.close_polygon(); agg::trans_affine mtx; mtx *= agg::trans_affine_scaling(4.0); mtx *= agg::trans_affine_translation(220, 200); agg::conv_transform<agg::path_storage> trans(glyph, mtx); agg::conv_curve<agg::conv_transform<agg::path_storage> > curve(trans); ras1.reset(); ras1.add_path(stroke); ren.color(agg::rgba(0, 0, 0, 0.1)); agg::render_scanlines(ras1, sl, ren); ras2.reset(); ras2.add_path(curve); ren.color(agg::rgba(0, 0.6, 0, 0.1)); agg::render_scanlines(ras2, sl, ren); render_scanline_boolean(ras1, ras2); } break; } return 0; } virtual void on_init() { m_x = width() / 2.0; m_y = height() / 2.0; } virtual void on_draw() { typedef agg::renderer_base<pixfmt_type> base_ren_type; typedef agg::renderer_scanline_aa_solid<base_ren_type> renderer_solid; agg::pixfmt_bgr24 pf(rbuf_window()); base_ren_type ren_base(pf); renderer_solid ren_solid(ren_base); ren_base.clear(agg::rgba(1,1,1)); agg::scanline_u8 sl; agg::rasterizer_scanline_aa<> ras; agg::rasterizer_scanline_aa<> ras2; agg::render_ctrl(ras, sl, ren_base, m_polygons); agg::render_ctrl(ras, sl, ren_base, m_fill_rule); agg::render_ctrl(ras, sl, ren_base, m_scanline_type); agg::render_ctrl(ras, sl, ren_base, m_operation); render_sbool(ras, ras2); } virtual void on_mouse_button_down(int x, int y, unsigned flags) { if(flags & agg::mouse_left) { m_x = x; m_y = y; force_redraw(); } if(flags & agg::mouse_right) { char buf[100]; sprintf(buf, "%d %d", x, y); message(buf); } } virtual void on_mouse_move(int x, int y, unsigned flags) { if(flags & agg::mouse_left) { m_x = x; m_y = y; force_redraw(); } } }; int agg_main(int argc, char* argv[]) { the_application app(agg::pix_format_bgr24, flip_y); app.caption("AGG Example. Scanline Boolean"); if(app.init(655, 520, agg::window_resize)) { return app.run(); } return 1; } |