#include <stdlib.h> #include <ctype.h> #include <stdio.h> #include "agg_rendering_buffer.h" #include "agg_rasterizer_scanline_aa.h" #include "agg_scanline_p.h" #include "agg_renderer_scanline.h" #include "agg_conv_bspline.h" #include "agg_conv_segmentator.h" #include "agg_font_freetype.h" #include "agg_trans_double_path.h" #include "ctrl/agg_cbox_ctrl.h" #include "ctrl/agg_slider_ctrl.h" #include "platform/agg_platform_support.h" #include "interactive_polygon.h" #define AGG_BGR24 //#define AGG_RGB24 //#define AGG_BGRA32 //#define AGG_RGBA32 //#define AGG_ARGB32 //#define AGG_ABGR32 //#define AGG_RGB565 //#define AGG_RGB555 #include "pixel_formats.h" enum flip_y_e { flip_y = true }; static char text[] = "Anti-Grain Geometry is designed as a set of loosely coupled " "algorithms and class templates united with a common idea, " "so that all the components can be easily combined. Also, " "the template based design allows you to replace any part of " "the library without the necessity to modify a single byte in " "the existing code. "; class the_application : public agg::platform_support { public: typedef agg::renderer_base<pixfmt> renderer_base; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid; typedef agg::scanline_p8 scanline_type; typedef agg::font_engine_freetype_int16 font_engine_type; typedef agg::font_cache_manager<font_engine_type> font_manager_type; font_engine_type m_feng; font_manager_type m_fman; agg::interactive_polygon m_poly1; agg::interactive_polygon m_poly2; agg::slider_ctrl<agg::rgba8> m_num_points; agg::cbox_ctrl<agg::rgba8> m_fixed_len; agg::cbox_ctrl<agg::rgba8> m_preserve_x_scale; agg::cbox_ctrl<agg::rgba8> m_animate; double m_dx1[6]; double m_dy1[6]; double m_dx2[6]; double m_dy2[6]; bool m_prev_animate; the_application(agg::pix_format_e format, bool flip_y) : agg::platform_support(format, flip_y), m_feng(), m_fman(m_feng), m_poly1(6, 5.0), m_poly2(6, 5.0), m_num_points (5.0, 5.0, 340.0, 12.0, !flip_y), m_fixed_len (350, 5.0, "Fixed Length", !flip_y), m_preserve_x_scale(465, 5.0, "Preserve X scale", !flip_y), m_animate (350, 25.0, "Animate", !flip_y), m_prev_animate(false) { add_ctrl(m_fixed_len); add_ctrl(m_preserve_x_scale); add_ctrl(m_animate); m_fixed_len.status(true); m_preserve_x_scale.status(true); m_num_points.range(10.0, 400.0); m_num_points.value(200.0); m_num_points.label("Number of intermediate Points = %.3f"); add_ctrl(m_num_points); m_poly1.close(false); m_poly2.close(false); } virtual void on_init() { m_poly1.xn(0) = 10 + 50; m_poly1.yn(0) = -10 + 50; m_poly1.xn(1) = 10 + 150 + 20; m_poly1.yn(1) = -10 + 150 - 20; m_poly1.xn(2) = 10 + 250 - 20; m_poly1.yn(2) = -10 + 250 + 20; m_poly1.xn(3) = 10 + 350 + 20; m_poly1.yn(3) = -10 + 350 - 20; m_poly1.xn(4) = 10 + 450 - 20; m_poly1.yn(4) = -10 + 450 + 20; m_poly1.xn(5) = 10 + 550; m_poly1.yn(5) = -10 + 550; m_poly2.xn(0) = -10 + 50; m_poly2.yn(0) = 10 + 50; m_poly2.xn(1) = -10 + 150 + 20; m_poly2.yn(1) = 10 + 150 - 20; m_poly2.xn(2) = -10 + 250 - 20; m_poly2.yn(2) = 10 + 250 + 20; m_poly2.xn(3) = -10 + 350 + 20; m_poly2.yn(3) = 10 + 350 - 20; m_poly2.xn(4) = -10 + 450 - 20; m_poly2.yn(4) = 10 + 450 + 20; m_poly2.xn(5) = -10 + 550; m_poly2.yn(5) = 10 + 550; } virtual void on_draw() { pixfmt pixf(rbuf_window()); renderer_base rb(pixf); renderer_solid r(rb); rb.clear(agg::rgba(1, 1, 1)); scanline_type sl; agg::rasterizer_scanline_aa<> ras; agg::simple_polygon_vertex_source path1(m_poly1.polygon(), m_poly1.num_points(), false, false); agg::simple_polygon_vertex_source path2(m_poly2.polygon(), m_poly2.num_points(), false, false); typedef agg::conv_bspline<agg::simple_polygon_vertex_source> conv_bspline_type; conv_bspline_type bspline1(path1); conv_bspline_type bspline2(path2); bspline1.interpolation_step(1.0 / m_num_points.value()); bspline2.interpolation_step(1.0 / m_num_points.value()); typedef agg::conv_curve<font_manager_type::path_adaptor_type> conv_font_curve_type; typedef agg::conv_segmentator<conv_font_curve_type> conv_font_segm_type; typedef agg::conv_transform<conv_font_segm_type, agg::trans_double_path> conv_font_trans_type; agg::trans_double_path tcurve; conv_font_curve_type fcurves(m_fman.path_adaptor()); conv_font_segm_type fsegm(fcurves); conv_font_trans_type ftrans(fsegm, tcurve); tcurve.preserve_x_scale(m_preserve_x_scale.status()); if(m_fixed_len.status()) tcurve.base_length(1140.0); tcurve.base_height(30.0); tcurve.add_paths(bspline1, bspline2); fsegm.approximation_scale(3.0); fcurves.approximation_scale(5.0); if(m_feng.load_font(full_file_name("timesi.ttf"), 0, agg::glyph_ren_outline)) { double x = 0.0; double y = 3.0; const char* p = text; m_feng.hinting(false); m_feng.height(40); while(*p) { const agg::glyph_cache* glyph = m_fman.glyph(*p); if(glyph) { if(x > tcurve.total_length1()) break; m_fman.add_kerning(&x, &y); m_fman.init_embedded_adaptors(glyph, x, y); if(glyph->data_type == agg::glyph_data_outline) { ras.reset(); ras.add_path(ftrans); r.color(agg::rgba8(0, 0, 0)); agg::render_scanlines(ras, sl, r); } // increment pen position x += glyph->advance_x; y += glyph->advance_y; } ++p; } } else { message("Please copy file timesi.ttf to the current directory\n" "or download it from http://www.antigrain.com/timesi.zip"); } typedef agg::conv_stroke<conv_bspline_type> conv_stroke_type; conv_stroke_type stroke1(bspline1); conv_stroke_type stroke2(bspline2); stroke1.width(2.0); stroke2.width(2.0); r.color(agg::rgba8(170, 50, 20, 100)); ras.add_path(stroke1); agg::render_scanlines(ras, sl, r); ras.add_path(stroke2); agg::render_scanlines(ras, sl, r); //-------------------------- // Render the "poly" tool and controls r.color(agg::rgba(0, 0.3, 0.5, 0.2)); ras.add_path(m_poly1); agg::render_scanlines(ras, sl, r); ras.add_path(m_poly2); agg::render_scanlines(ras, sl, r); agg::render_ctrl(ras, sl, rb, m_fixed_len); agg::render_ctrl(ras, sl, rb, m_preserve_x_scale); agg::render_ctrl(ras, sl, rb, m_animate); agg::render_ctrl(ras, sl, rb, m_num_points); //-------------------------- } virtual void on_mouse_button_down(int x, int y, unsigned flags) { if(flags & agg::mouse_left) { if(m_poly1.on_mouse_button_down(x, y)) { force_redraw(); } if(m_poly2.on_mouse_button_down(x, y)) { force_redraw(); } } } virtual void on_mouse_move(int x, int y, unsigned flags) { if(flags & agg::mouse_left) { if(m_poly1.on_mouse_move(x, y)) { force_redraw(); } if(m_poly2.on_mouse_move(x, y)) { force_redraw(); } } if((flags & agg::mouse_left) == 0) { on_mouse_button_up(x, y, flags); } } virtual void on_mouse_button_up(int x, int y, unsigned flags) { if(m_poly1.on_mouse_button_up(x, y)) { force_redraw(); } if(m_poly2.on_mouse_button_up(x, y)) { force_redraw(); } } virtual void on_key(int x, int y, unsigned key, unsigned flags) { } virtual void on_ctrl_change() { if(m_animate.status() != m_prev_animate) { if(m_animate.status()) { on_init(); int i; for(i = 0; i < 6; i++) { m_dx1[i] = ((rand() % 1000) - 500) * 0.01; m_dy1[i] = ((rand() % 1000) - 500) * 0.01; m_dx2[i] = ((rand() % 1000) - 500) * 0.01; m_dy2[i] = ((rand() % 1000) - 500) * 0.01; } wait_mode(false); } else { wait_mode(true); } m_prev_animate = m_animate.status(); } } void move_point(double& x, double& y, double& dx, double& dy) { if(x < 0.0) { x = 0.0; dx = -dx; } if(x > width()) { x = width(); dx = -dx; } if(y < 0.0) { y = 0.0; dy = -dy; } if(y > height()) { y = height(); dy = -dy; } x += dx; y += dy; } void normalize_point(unsigned i) { double d = agg::calc_distance(m_poly1.xn(i), m_poly1.yn(i), m_poly2.xn(i), m_poly2.yn(i)); // 28.8 is 20 * sqrt(2) if(d > 28.28) { m_poly2.xn(i) = m_poly1.xn(i) + (m_poly2.xn(i) - m_poly1.xn(i)) * 28.28 / d; m_poly2.yn(i) = m_poly1.yn(i) + (m_poly2.yn(i) - m_poly1.yn(i)) * 28.28 / d; } } virtual void on_idle() { int i; for(i = 0; i < 6; i++) { move_point(m_poly1.xn(i), m_poly1.yn(i), m_dx1[i], m_dy1[i]); move_point(m_poly2.xn(i), m_poly2.yn(i), m_dx2[i], m_dy2[i]); normalize_point(i); } force_redraw(); } }; int agg_main(int argc, char* argv[]) { the_application app(pix_format, flip_y); app.caption("AGG Example. Non-linear \"Along-A-Curve\" Transformer"); if(app.init(600, 600, agg::window_resize)) { return app.run(); } return 1; } |