virtual void on_draw() { typedef agg::pixfmt_gray8 pixfmt_gray8; typedef agg::renderer_base<pixfmt_gray8> ren_base_gray8; m_ras.clip_box(0,0, width(), height()); pixfmt_gray8 pixf_gray8(m_gray8_rbuf); ren_base_gray8 renb_gray8(pixf_gray8); renb_gray8.clear(agg::gray8(0)); // Testing enhanced compositing operations. // Uncomment and replace renb.blend_from_* to renb_blend.blend_from_* //---------------- //typedef agg::comp_op_rgba_minus<color_type, component_order> blender_type; //typedef agg::comp_adaptor_rgba<blender_type> blend_adaptor_type; //typedef agg::pixfmt_custom_blend_rgba<blend_adaptor_type, agg::rendering_buffer> pixfmt_type; //typedef agg::renderer_base<pixfmt_type> ren_base; //pixfmt_type pixf_blend(rbuf_window()); //agg::renderer_base<pixfmt_type> renb_blend(pixf_blend); pixfmt pixf(rbuf_window()); agg::renderer_base<pixfmt> renb(pixf); renb.clear(agg::rgba(1, 0.95, 0.95)); agg::trans_perspective shadow_persp(m_shape_bounds.x1, m_shape_bounds.y1, m_shape_bounds.x2, m_shape_bounds.y2, m_shadow_ctrl.polygon()); agg::conv_transform<shape_type, agg::trans_perspective> shadow_trans(m_shape, shadow_persp); start_timer(); // Render shadow m_ras.add_path(shadow_trans); agg::render_scanlines_aa_solid(m_ras, m_sl, renb_gray8, agg::gray8(255)); // Calculate the bounding box and extend it by the blur radius agg::rect_d bbox; agg::bounding_rect_single(shadow_trans, 0, &bbox.x1, &bbox.y1, &bbox.x2, &bbox.y2); bbox.x1 -= m_radius.value(); bbox.y1 -= m_radius.value(); bbox.x2 += m_radius.value(); bbox.y2 += m_radius.value(); if(bbox.clip(agg::rect_d(0, 0, width(), height()))) { // Create a new pixel renderer and attach it to the main one as a child image. // It returns true if the attachment suceeded. It fails if the rectangle // (bbox) is fully clipped. //------------------ pixfmt_gray8 pixf2(m_gray8_rbuf2); if(pixf2.attach(pixf_gray8, int(bbox.x1), int(bbox.y1), int(bbox.x2), int(bbox.y2))) { // Blur it agg::stack_blur_gray8(pixf2, agg::uround(m_radius.value()), agg::uround(m_radius.value())); } if(m_method.cur_item() == 0) { renb.blend_from_color(pixf2, agg::rgba8(0, 100, 0), 0, int(bbox.x1), int(bbox.y1)); } else { renb.blend_from_lut(pixf2, m_color_lut.data(), 0, int(bbox.x1), int(bbox.y1)); } } double tm = elapsed_time(); char buf[64]; agg::gsv_text t; t.size(10.0); agg::conv_stroke<agg::gsv_text> st(t); st.width(1.5); sprintf(buf, "%3.2f ms", tm); t.start_point(140.0, 30.0); t.text(buf); m_ras.add_path(st); agg::render_scanlines_aa_solid(m_ras, m_sl, renb, agg::rgba(0,0,0)); agg::render_ctrl(m_ras, m_sl, renb, m_method); agg::render_ctrl(m_ras, m_sl, renb, m_radius); agg::render_ctrl(m_ras, m_sl, renb, m_shadow_ctrl); }
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; m_poly.close(m_close.status()); agg::simple_polygon_vertex_source path(m_poly.polygon(), m_poly.num_points(), false, m_close.status()); typedef agg::conv_bspline<agg::simple_polygon_vertex_source> conv_bspline_type; conv_bspline_type bspline(path); bspline.interpolation_step(1.0 / m_num_points.value()); agg::trans_single_path tcurve; tcurve.add_path(bspline); tcurve.preserve_x_scale(m_preserve_x_scale.status()); if(m_fixed_len.status()) tcurve.base_length(1120); 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_single_path> conv_font_trans_type; conv_font_curve_type fcurves(m_fman.path_adaptor()); conv_font_segm_type fsegm(fcurves); conv_font_trans_type ftrans(fsegm, tcurve); fsegm.approximation_scale(3.0); fcurves.approximation_scale(2.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_length()) 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::srgba8(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 stroke(bspline); stroke.width(2.0); r.color(agg::srgba8(170, 50, 20, 100)); ras.add_path(stroke); agg::render_scanlines(ras, sl, r); //-------------------------- // Render the "poly" tool and controls r.color(agg::rgba(0, 0.3, 0.5, 0.3)); ras.add_path(m_poly); agg::render_scanlines(ras, sl, r); agg::render_ctrl(ras, sl, rb, m_close); agg::render_ctrl(ras, sl, rb, m_preserve_x_scale); agg::render_ctrl(ras, sl, rb, m_fixed_len); agg::render_ctrl(ras, sl, rb, m_animate); agg::render_ctrl(ras, sl, rb, m_num_points); //-------------------------- }
virtual void on_draw() { typedef agg::renderer_base<pixfmt> ren_base; typedef agg::renderer_base<pixfmt_pre> ren_base_pre; agg::gamma_lut<agg::int8u, agg::int8u> lut; #if !LINEAR_RGB lut.gamma(2.2); #endif pixfmt pixf(rbuf_window()); ren_base renb(pixf); pixfmt_pre pixf_pre(rbuf_window()); ren_base_pre renb_pre(pixf_pre); // Clear the window with a gradient agg::pod_vector<color_type> gr(pixf_pre.width()); unsigned i; for(i = 0; i < pixf.width(); i++) { gr.add(agg::rgba8(255, 255, 0).gradient(agg::rgba8(0, 255, 255), double(i) / pixf.width())); } for(i = 0; i < pixf.height(); i++) { renb.copy_color_hspan(0, i, pixf.width(), &gr[0]); } #if !LINEAR_RGB pixf.apply_gamma_dir(lut); #endif agg::rasterizer_scanline_aa<> ras; agg::rasterizer_compound_aa<agg::rasterizer_sl_clip_dbl> rasc; agg::scanline_u8 sl; agg::span_allocator<color_type> alloc; // Draw two triangles ras.move_to_d(0, 0); ras.line_to_d(width(), 0); ras.line_to_d(width(), height()); agg::render_scanlines_aa_solid(ras, sl, renb, agg::rgba8(lut.dir(0), lut.dir(100), lut.dir(0))); ras.move_to_d(0, 0); ras.line_to_d(0, height()); ras.line_to_d(width(), 0); agg::render_scanlines_aa_solid(ras, sl, renb, agg::rgba8(lut.dir(0), lut.dir(100), lut.dir(100))); agg::trans_affine mtx; mtx *= agg::trans_affine_scaling(4.0); mtx *= agg::trans_affine_translation(150, 100); agg::conv_transform<agg::path_storage> trans(m_path, mtx); agg::conv_curve<agg::conv_transform<agg::path_storage> > curve(trans); agg::conv_stroke <agg::conv_curve <agg::conv_transform <agg::path_storage> > > stroke(curve); compose_path(); color_type styles[4]; if(m_invert_order.status()) { rasc.layer_order(agg::layer_inverse); } else { rasc.layer_order(agg::layer_direct); } styles[3] = agg::rgba8(lut.dir(255), lut.dir(0), lut.dir(108), 200).premultiply(); styles[2] = agg::rgba8(lut.dir(51), lut.dir(0), lut.dir(151), 180).premultiply(); styles[1] = agg::rgba8(lut.dir(143), lut.dir(90), lut.dir(6), 200).premultiply(); styles[0] = agg::rgba8(lut.dir(0), lut.dir(0), lut.dir(255), 220).premultiply(); style_handler sh(styles, 4); stroke.width(m_width.value()); rasc.reset(); rasc.master_alpha(3, m_alpha1.value()); rasc.master_alpha(2, m_alpha2.value()); rasc.master_alpha(1, m_alpha3.value()); rasc.master_alpha(0, m_alpha4.value()); agg::ellipse ell(220.0, 180.0, 120.0, 10.0, 128, false); agg::conv_stroke<agg::ellipse> str_ell(ell); str_ell.width(m_width.value() / 2); rasc.styles(3, -1); rasc.add_path(str_ell); rasc.styles(2, -1); rasc.add_path(ell); rasc.styles(1, -1); rasc.add_path(stroke); rasc.styles(0, -1); rasc.add_path(curve); agg::render_scanlines_compound_layered(rasc, sl, renb_pre, alloc, sh); agg::render_ctrl(ras, sl, renb, m_width); agg::render_ctrl(ras, sl, renb, m_alpha1); agg::render_ctrl(ras, sl, renb, m_alpha2); agg::render_ctrl(ras, sl, renb, m_alpha3); agg::render_ctrl(ras, sl, renb, m_alpha4); agg::render_ctrl(ras, sl, renb, m_invert_order); #if !LINEAR_RGB pixf.apply_gamma_inv(lut); #endif }
virtual void on_draw() { double img_width = rbuf_img(0).width(); double img_height = rbuf_img(0).height(); typedef pixfmt pixfmt; typedef agg::renderer_base<pixfmt> renderer_base; pixfmt pixf(rbuf_window()); pixfmt img_pixf(rbuf_img(0)); renderer_base rb(pixf); rb.clear(agg::rgba(1.0, 1.0, 1.0)); agg::trans_affine src_mtx; src_mtx *= agg::trans_affine_translation(-img_width/2, -img_height/2); src_mtx *= agg::trans_affine_rotation(m_angle.value() * agg::pi / 180.0); src_mtx *= agg::trans_affine_translation(img_width/2 + 10, img_height/2 + 10 + 40); src_mtx *= trans_affine_resizing(); agg::trans_affine img_mtx; img_mtx *= agg::trans_affine_translation(-img_width/2, -img_height/2); img_mtx *= agg::trans_affine_rotation(m_angle.value() * agg::pi / 180.0); img_mtx *= agg::trans_affine_scaling(m_scale.value()); img_mtx *= agg::trans_affine_translation(img_width/2 + 10, img_height/2 + 10 + 40); img_mtx *= trans_affine_resizing(); img_mtx.invert(); typedef agg::span_allocator<color_type> span_alloc_type; span_alloc_type sa; typedef agg::span_interpolator_adaptor<agg::span_interpolator_linear<>, periodic_distortion> interpolator_type; periodic_distortion* dist = 0; distortion_wave dist_wave; distortion_swirl dist_swirl; distortion_wave_swirl dist_wave_swirl; distortion_swirl_wave dist_swirl_wave; switch(m_distortion.cur_item()) { case 0: dist = &dist_wave; break; case 1: dist = &dist_swirl; break; case 2: dist = &dist_wave_swirl; break; case 3: dist = &dist_swirl_wave; break; } dist->period(m_period.value()); dist->amplitude(m_amplitude.value()); dist->phase(m_phase); double cx = m_center_x; double cy = m_center_y; img_mtx.transform(&cx, &cy); dist->center(cx, cy); interpolator_type interpolator(img_mtx, *dist); typedef agg::image_accessor_clip<pixfmt> img_source_type; img_source_type img_src(img_pixf, agg::rgba(1,1,1)); /* // Version without filtering (nearest neighbor) //------------------------------------------ typedef agg::span_image_filter_rgb_nn<img_source_type, interpolator_type> span_gen_type; span_gen_type sg(img_src, interpolator); //------------------------------------------ */ // Version with "hardcoded" bilinear filter and without // image_accessor (direct filter, the old variant) //------------------------------------------ typedef agg::span_image_filter_rgb_bilinear_clip<pixfmt, interpolator_type> span_gen_type; span_gen_type sg(img_pixf, agg::rgba(1,1,1), interpolator); //------------------------------------------ /* // Version with arbitrary 2x2 filter //------------------------------------------ typedef agg::span_image_filter_rgb_2x2<img_source_type, interpolator_type> span_gen_type; agg::image_filter<agg::image_filter_kaiser> filter; span_gen_type sg(img_src, interpolator, filter); //------------------------------------------ */ /* // Version with arbitrary filter //------------------------------------------ typedef agg::span_image_filter_rgb<img_source_type, interpolator_type> span_gen_type; agg::image_filter<agg::image_filter_spline36> filter; span_gen_type sg(img_src, interpolator, filter); //------------------------------------------ */ agg::rasterizer_scanline_aa<> ras; agg::scanline_u8 sl; double r = img_width; if(img_height < r) r = img_height; agg::ellipse ell(img_width / 2.0, img_height / 2.0, r / 2.0 - 20.0, r / 2.0 - 20.0, 200); agg::conv_transform<agg::ellipse> tr(ell, src_mtx); ras.add_path(tr); agg::render_scanlines_aa(ras, sl, rb, sa, sg); src_mtx *= ~trans_affine_resizing(); src_mtx *= agg::trans_affine_translation(img_width - img_width/10, 0.0); src_mtx *= trans_affine_resizing(); ras.add_path(tr); agg::render_scanlines_aa_solid(ras, sl, rb, agg::srgba8(0,0,0)); typedef agg::span_gradient<color_type, interpolator_type, agg::gradient_circle, color_array_type> gradient_span_gen; agg::gradient_circle gradient_function; color_array_type gradient_colors(m_gradient_colors); gradient_span_gen span_gradient(interpolator, gradient_function, gradient_colors, 0, 180); agg::trans_affine gr1_mtx; gr1_mtx *= agg::trans_affine_translation(-img_width/2, -img_height/2); gr1_mtx *= agg::trans_affine_scaling(0.8); gr1_mtx *= agg::trans_affine_rotation(m_angle.value() * agg::pi / 180.0); gr1_mtx *= agg::trans_affine_translation(img_width - img_width/10 + img_width/2 + 10, img_height/2 + 10 + 40); gr1_mtx *= trans_affine_resizing(); agg::trans_affine gr2_mtx; gr2_mtx *= agg::trans_affine_rotation(m_angle.value() * agg::pi / 180.0); gr2_mtx *= agg::trans_affine_scaling(m_scale.value()); gr2_mtx *= agg::trans_affine_translation(img_width - img_width/10 + img_width/2 + 10 + 50, img_height/2 + 10 + 40 + 50); gr2_mtx *= trans_affine_resizing(); gr2_mtx.invert(); cx = m_center_x + img_width - img_width/10; cy = m_center_y; gr2_mtx.transform(&cx, &cy); dist->center(cx, cy); interpolator.transformer(gr2_mtx); agg::conv_transform<agg::ellipse> tr2(ell, gr1_mtx); ras.add_path(tr2); agg::render_scanlines_aa(ras, sl, rb, sa, span_gradient); agg::render_ctrl(ras, sl, rb, m_angle); agg::render_ctrl(ras, sl, rb, m_scale); agg::render_ctrl(ras, sl, rb, m_amplitude); agg::render_ctrl(ras, sl, rb, m_period); agg::render_ctrl(ras, sl, rb, m_distortion); }
virtual void on_draw() { typedef agg::renderer_base<pixfmt> ren_base; pixfmt pixf(rbuf_window()); ren_base rbase(pixf); trans_roundoff roundoff; if(m_redraw_flag) { g_rasterizer.gamma(agg::gamma_none()); rbase.clear(agg::rgba8(255,255,255)); g_rasterizer.filling_rule(agg::fill_non_zero); agg::render_ctrl(g_rasterizer, g_scanline, rbase, m_rotate); agg::render_ctrl(g_rasterizer, g_scanline, rbase, m_even_odd); agg::render_ctrl(g_rasterizer, g_scanline, rbase, m_draft); agg::render_ctrl(g_rasterizer, g_scanline, rbase, m_roundoff); agg::render_ctrl(g_rasterizer, g_scanline, rbase, m_angle_delta); m_redraw_flag = false; } else { rbase.copy_bar(0, int(32.0 * rbuf_window().height() / m_dy), rbuf_window().width(), rbuf_window().height(), agg::rgba8(255,255,255)); } if(m_draft.status()) { g_rasterizer.gamma(agg::gamma_threshold(0.4)); } agg::trans_affine mtx; mtx.reset(); mtx *= agg::trans_affine_rotation(g_angle * agg::pi / 180.0); mtx *= agg::trans_affine_translation(m_dx / 2, m_dy / 2 + 10); mtx *= agg::trans_affine_scaling(rbuf_window().width() / m_dx, rbuf_window().height() / m_dy); agg::conv_transform<agg::path_storage> fill(g_path, mtx); agg::conv_transform < agg::conv_transform<agg::path_storage>, trans_roundoff > fill_roundoff(fill, roundoff); agg::conv_stroke < agg::conv_transform<agg::path_storage> > stroke(fill); agg::conv_stroke < agg::conv_transform < agg::conv_transform<agg::path_storage>, trans_roundoff > > stroke_roundoff(fill_roundoff); g_pflag = m_even_odd.status() ? agg::fill_even_odd : agg::fill_non_zero; unsigned i; for(i = 0; i < g_npaths; i++) { g_rasterizer.filling_rule(g_pflag); if(m_roundoff.status()) g_rasterizer.add_path(fill_roundoff, g_attr[i].index); else g_rasterizer.add_path(fill, g_attr[i].index); if(m_draft.status()) { agg::render_scanlines_bin_solid(g_rasterizer, g_scanline, rbase, g_attr[i].fill_color); } else { agg::render_scanlines_aa_solid(g_rasterizer, g_scanline, rbase, g_attr[i].fill_color); } if(g_attr[i].stroke_width > 0.001) { stroke.width(g_attr[i].stroke_width * mtx.scale()); stroke_roundoff.width(g_attr[i].stroke_width * mtx.scale()); if(m_roundoff.status()) g_rasterizer.add_path(stroke_roundoff, g_attr[i].index); else g_rasterizer.add_path(stroke, g_attr[i].index); if(m_draft.status()) { agg::render_scanlines_bin_solid(g_rasterizer, g_scanline, rbase, g_attr[i].stroke_color); } else { agg::render_scanlines_aa_solid(g_rasterizer, g_scanline, rbase, g_attr[i].stroke_color); } } } }
virtual void on_init() { m_dx = rbuf_window().width(); m_dy = rbuf_window().height(); }
virtual void on_draw() { pixfmt pf(rbuf_window()); renderer_base ren_base(pf); ren_base.clear(agg::rgba(0.5, 0.75, 0.85)); renderer_scanline ren(ren_base); rasterizer_scanline ras; scanline sl; ras.clip_box(0, 0, width(), height()); // Pattern source. Must have an interface: // width() const // height() const // pixel(int x, int y) const // Any agg::renderer_base<> or derived // is good for the use as a source. //----------------------------------- pattern_src_brightness_to_alpha_rgba8 p1(rbuf_img(0)); agg::pattern_filter_bilinear_rgba8 fltr; // Filtering functor // agg::line_image_pattern is the main container for the patterns. It creates // a copy of the patterns extended according to the needs of the filter. // agg::line_image_pattern can operate with arbitrary image width, but if the // width of the pattern is power of 2, it's better to use the modified // version agg::line_image_pattern_pow2 because it works about 15-25 percent // faster than agg::line_image_pattern (because of using simple masking instead // of expensive '%' operation). typedef agg::line_image_pattern<agg::pattern_filter_bilinear_rgba8> pattern_type; typedef agg::renderer_base<pixfmt> base_ren_type; typedef agg::renderer_outline_image<base_ren_type, pattern_type> renderer_img_type; typedef agg::rasterizer_outline_aa<renderer_img_type, agg::line_coord_sat> rasterizer_img_type; typedef agg::renderer_outline_aa<base_ren_type> renderer_line_type; typedef agg::rasterizer_outline_aa<renderer_line_type, agg::line_coord_sat> rasterizer_line_type; //-- Create with specifying the source //pattern_type patt(fltr, src); //-- Create uninitialized and set the source pattern_type patt(fltr); patt.create(p1); renderer_img_type ren_img(ren_base, patt); rasterizer_img_type ras_img(ren_img); //-- create uninitialized and set parameters agg::line_profile_aa profile; profile.smoother_width(10.0); //optional profile.width(8.0); //mandatory! renderer_line_type ren_line(ren_base, profile); ren_line.color(agg::rgba8(0,0,127)); //mandatory! rasterizer_line_type ras_line(ren_line); ras_line.round_cap(true); //optional //ras_line.line_join(agg::outline_no_join); //optional // Calculate the dilation value so that, the line caps were // drawn correctly. //--------------- double w2 = 9.0;//p1.height() / 2 + 2; // Set the clip box a bit bigger than you expect. You need it // to draw the clipped line caps correctly. The correct result // is achieved with raster clipping. //------------------------ ren_img.scale_x(m_scale_x.value()); ren_img.start_x(m_start_x.value()); ren_img.clip_box (50-w2, 50-w2, width()-50+w2, height()-50+w2); ren_line.clip_box(50-w2, 50-w2, width()-50+w2, height()-50+w2); // First, draw polyline without raster clipping just to show the idea //------------------------ draw_polyline(ras_line, ren_line, m_line1.polygon(), m_line1.num_points()); draw_polyline(ras_img, ren_img, m_line1.polygon(), m_line1.num_points()); // Clear the area, almost opaque, but not completely //------------------------ ren_base.blend_bar(0, 0, (int)width(), (int)height(), agg::rgba(1,1,1), 200); // Set the raster clip box and then, draw again. // In reality there shouldn't be two calls above. // It's done only for demonstration //------------------------ ren_base.clip_box((int)50, (int)50, (int)width()-50, (int)height()-50); // This "copy_bar" is also for demonstration only //------------------------ ren_base.copy_bar(0, 0, (int)width(), (int)height(), agg::rgba(1,1,1)); // Finally draw polyline correctly clipped: We use double clipping, // first is vector clipping, with extended clip box, second is raster // clipping with normal clip box. //------------------------ ren_img.scale_x(m_scale_x.value()); ren_img.start_x(m_start_x.value()); draw_polyline(ras_line, ren_line, m_line1.polygon(), m_line1.num_points()); draw_polyline(ras_img, ren_img, m_line1.polygon(), m_line1.num_points()); // Reset clipping and draw the controls and stuff ren_base.reset_clipping(true); m_line1.line_width(1/m_scale.scale()); m_line1.point_radius(5/m_scale.scale()); agg::render_ctrl(ras, sl, ren_base, m_line1); agg::render_ctrl(ras, sl, ren_base, m_scale_x); agg::render_ctrl(ras, sl, ren_base, m_start_x); char buf[256]; agg::gsv_text t; t.size(10.0); agg::conv_stroke<agg::gsv_text> pt(t); pt.width(1.5); pt.line_cap(agg::round_cap); const double* p = m_line1.polygon(); sprintf(buf, "Len=%.2f", agg::calc_distance(p[0], p[1], p[2], p[3]) * m_scale.scale()); t.start_point(10.0, 30.0); t.text(buf); ras.add_path(pt); ren.color(agg::rgba(0,0,0)); agg::render_scanlines(ras, sl, ren); }
virtual void on_draw() { typedef agg::renderer_base<agg::pixfmt_bgr24> ren_base; agg::pixfmt_bgr24 pixf(rbuf_window()); ren_base renb(pixf); renb.clear(agg::rgba(1, 1, 1)); m_ras.clip_box(0,0, width(), height()); agg::trans_perspective shadow_persp(m_shape_bounds.x1, m_shape_bounds.y1, m_shape_bounds.x2, m_shape_bounds.y2, m_shadow_ctrl.polygon()); agg::conv_transform<shape_type, agg::trans_perspective> shadow_trans(m_shape, shadow_persp); // Render shadow m_ras.add_path(shadow_trans); agg::render_scanlines_aa_solid(m_ras, m_sl, renb, agg::rgba(0.2,0.3,0)); // Calculate the bounding box and extend it by the blur radius agg::rect_d bbox; agg::bounding_rect_single(shadow_trans, 0, &bbox.x1, &bbox.y1, &bbox.x2, &bbox.y2); bbox.x1 -= m_radius.value(); bbox.y1 -= m_radius.value(); bbox.x2 += m_radius.value(); bbox.y2 += m_radius.value(); if(m_method.cur_item() == 1) { // The recursive blur method represents the true Gussian Blur, // with theoretically infinite kernel. The restricted window size // results in extra influence of edge pixels. It's impossible to // solve correctly, but extending the right and top areas to another // radius value produces fair result. //------------------ bbox.x2 += m_radius.value(); bbox.y2 += m_radius.value(); } start_timer(); if(m_method.cur_item() != 2) { // Create a new pixel renderer and attach it to the main one as a child image. // It returns true if the attachment suceeded. It fails if the rectangle // (bbox) is fully clipped. //------------------ agg::pixfmt_bgr24 pixf2(m_rbuf2); if(pixf2.attach(pixf, int(bbox.x1), int(bbox.y1), int(bbox.x2), int(bbox.y2))) { // Blur it if(m_method.cur_item() == 0) { // More general method, but 30-40% slower. //------------------ //m_stack_blur.blur(pixf2, agg::uround(m_radius.value())); // Faster, but bore specific. // Works only for 8 bits per channel and only with radii <= 254. //------------------ agg::stack_blur_rgb24(pixf2, agg::uround(m_radius.value()), agg::uround(m_radius.value())); } else { // True Gaussian Blur, 3-5 times slower than Stack Blur, // but still constant time of radius. Very sensitive // to precision, doubles are must here. //------------------ m_recursive_blur.blur(pixf2, m_radius.value()); } } } else { // Blur separate channels //------------------ if(m_channel_r.status()) { typedef agg::pixfmt_alpha_blend_gray< agg::blender_gray8, agg::rendering_buffer, 3, 2> pixfmt_gray8r; pixfmt_gray8r pixf2r(m_rbuf2); if(pixf2r.attach(pixf, int(bbox.x1), int(bbox.y1), int(bbox.x2), int(bbox.y2))) { agg::stack_blur_gray8(pixf2r, agg::uround(m_radius.value()), agg::uround(m_radius.value())); } } if(m_channel_g.status()) { typedef agg::pixfmt_alpha_blend_gray< agg::blender_gray8, agg::rendering_buffer, 3, 1> pixfmt_gray8g; pixfmt_gray8g pixf2g(m_rbuf2); if(pixf2g.attach(pixf, int(bbox.x1), int(bbox.y1), int(bbox.x2), int(bbox.y2))) { agg::stack_blur_gray8(pixf2g, agg::uround(m_radius.value()), agg::uround(m_radius.value())); } } if(m_channel_b.status()) { typedef agg::pixfmt_alpha_blend_gray< agg::blender_gray8, agg::rendering_buffer, 3, 0> pixfmt_gray8b; pixfmt_gray8b pixf2b(m_rbuf2); if(pixf2b.attach(pixf, int(bbox.x1), int(bbox.y1), int(bbox.x2), int(bbox.y2))) { agg::stack_blur_gray8(pixf2b, agg::uround(m_radius.value()), agg::uround(m_radius.value())); } } } double tm = elapsed_time(); agg::render_ctrl(m_ras, m_sl, renb, m_shadow_ctrl); // Render the shape itself //------------------ m_ras.add_path(m_shape); agg::render_scanlines_aa_solid(m_ras, m_sl, renb, agg::rgba(0.6,0.9,0.7, 0.8)); char buf[64]; agg::gsv_text t; t.size(10.0); agg::conv_stroke<agg::gsv_text> st(t); st.width(1.5); sprintf(buf, "%3.2f ms", tm); t.start_point(140.0, 30.0); t.text(buf); m_ras.add_path(st); agg::render_scanlines_aa_solid(m_ras, m_sl, renb, agg::rgba(0,0,0)); agg::render_ctrl(m_ras, m_sl, renb, m_method); agg::render_ctrl(m_ras, m_sl, renb, m_radius); agg::render_ctrl(m_ras, m_sl, renb, m_channel_r); agg::render_ctrl(m_ras, m_sl, renb, m_channel_g); agg::render_ctrl(m_ras, m_sl, renb, m_channel_b); }
//------------------------------------------------------------------------ virtual void on_draw() { double width = rbuf_window().width(); double height = rbuf_window().height(); typedef agg::renderer_base<pixfmt> renderer_base; typedef agg::renderer_base<pixfmt_pre> renderer_base_pre; pixfmt pixf(rbuf_window()); pixfmt_pre pixf_pre(rbuf_window()); renderer_base rb(pixf); renderer_base_pre rb_pre(pixf_pre); rb.clear(agg::rgba(1.0, 1.0, 1.0)); agg::trans_affine polygon_mtx; polygon_mtx *= agg::trans_affine_translation(-m_polygon_cx, -m_polygon_cy); polygon_mtx *= agg::trans_affine_rotation(m_polygon_angle.value() * agg::pi / 180.0); polygon_mtx *= agg::trans_affine_scaling(m_polygon_scale.value()); polygon_mtx *= agg::trans_affine_translation(m_polygon_cx, m_polygon_cy); double r = initial_width() / 3.0 - 8.0; create_star(m_polygon_cx, m_polygon_cy, r, r / 1.45, 14); agg::conv_transform<agg::path_storage> tr(m_ps, polygon_mtx); typedef agg::wrap_mode_reflect_auto_pow2 wrap_x_type; typedef agg::wrap_mode_reflect_auto_pow2 wrap_y_type; typedef agg::image_accessor_wrap<pixfmt, wrap_x_type, wrap_y_type> img_source_type; typedef agg::span_pattern_rgba<img_source_type> span_gen_type; unsigned offset_x = 0; unsigned offset_y = 0; if(m_tie_pattern.status()) { offset_x = unsigned(width-m_polygon_cx); offset_y = unsigned(height-m_polygon_cy); } agg::span_allocator<color_type> sa; pixfmt img_pixf(m_pattern_rbuf); img_source_type img_src(img_pixf); span_gen_type sg(img_src, offset_x, offset_y); // Alpha is meaningful for RGB only because RGBA has its own sg.alpha(span_gen_type::value_type(m_pattern_alpha.value() * 255.0)); m_ras.add_path(tr); agg::render_scanlines_aa(m_ras, m_sl, rb_pre, sa, sg); agg::render_ctrl(m_ras, m_sl, rb, m_polygon_angle); agg::render_ctrl(m_ras, m_sl, rb, m_polygon_scale); agg::render_ctrl(m_ras, m_sl, rb, m_pattern_angle); agg::render_ctrl(m_ras, m_sl, rb, m_pattern_size); agg::render_ctrl(m_ras, m_sl, rb, m_pattern_alpha); agg::render_ctrl(m_ras, m_sl, rb, m_rotate_polygon); agg::render_ctrl(m_ras, m_sl, rb, m_rotate_pattern); agg::render_ctrl(m_ras, m_sl, rb, m_tie_pattern); }