Example #1
0
 void draw_polyline(Rasterizer& ras, 
                    Renderer& ren, 
                    const double* polyline, 
                    int num_points)
 {
     agg::poly_plain_adaptor<double> vs(polyline, num_points, m_line1.close());
     agg::conv_transform<agg::poly_plain_adaptor<double> > trans(vs, m_scale);
     ras.add_path(trans);
 }
Example #2
0
    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);
    }
Example #3
0
    the_application(agg::pix_format_e format, bool flip_y) :
        agg::platform_support(format, flip_y),
        m_method     (10.0, 10.0, 130.0, 55.0, !flip_y),
        m_radius     (130 + 10.0, 10.0 + 4.0, 130 + 300.0, 10.0 + 8.0 + 4.0, !flip_y),
        m_shadow_ctrl(4),
        m_shape(m_path)
    {
        add_ctrl(m_method);
        m_method.text_size(8);
        m_method.add_item("Single Color");
        m_method.add_item("Color LUT");
        m_method.cur_item(1);

        add_ctrl(m_radius);
        m_radius.range(0.0, 40.0);
        m_radius.value(15.0);
        m_radius.label("Blur Radius=%1.2f");

        add_ctrl(m_shadow_ctrl);

        m_path.remove_all();
        m_path.move_to(28.47, 6.45);
        m_path.curve3(21.58, 1.12, 19.82, 0.29);
        m_path.curve3(17.19, -0.93, 14.21, -0.93);
        m_path.curve3(9.57, -0.93, 6.57, 2.25);
        m_path.curve3(3.56, 5.42, 3.56, 10.60);
        m_path.curve3(3.56, 13.87, 5.03, 16.26);
        m_path.curve3(7.03, 19.58, 11.99, 22.51);
        m_path.curve3(16.94, 25.44, 28.47, 29.64);
        m_path.line_to(28.47, 31.40);
        m_path.curve3(28.47, 38.09, 26.34, 40.58);
        m_path.curve3(24.22, 43.07, 20.17, 43.07);
        m_path.curve3(17.09, 43.07, 15.28, 41.41);
        m_path.curve3(13.43, 39.75, 13.43, 37.60);
        m_path.line_to(13.53, 34.77);
        m_path.curve3(13.53, 32.52, 12.38, 31.30);
        m_path.curve3(11.23, 30.08, 9.38, 30.08);
        m_path.curve3(7.57, 30.08, 6.42, 31.35);
        m_path.curve3(5.27, 32.62, 5.27, 34.81);
        m_path.curve3(5.27, 39.01, 9.57, 42.53);
        m_path.curve3(13.87, 46.04, 21.63, 46.04);
        m_path.curve3(27.59, 46.04, 31.40, 44.04);
        m_path.curve3(34.28, 42.53, 35.64, 39.31);
        m_path.curve3(36.52, 37.21, 36.52, 30.71);
        m_path.line_to(36.52, 15.53);
        m_path.curve3(36.52, 9.13, 36.77, 7.69);
        m_path.curve3(37.01, 6.25, 37.57, 5.76);
        m_path.curve3(38.13, 5.27, 38.87, 5.27);
        m_path.curve3(39.65, 5.27, 40.23, 5.62);
        m_path.curve3(41.26, 6.25, 44.19, 9.18);
        m_path.line_to(44.19, 6.45);
        m_path.curve3(38.72, -0.88, 33.74, -0.88);
        m_path.curve3(31.35, -0.88, 29.93, 0.78);
        m_path.curve3(28.52, 2.44, 28.47, 6.45);
        m_path.close_polygon();

        m_path.move_to(28.47, 9.62);
        m_path.line_to(28.47, 26.66);
        m_path.curve3(21.09, 23.73, 18.95, 22.51);
        m_path.curve3(15.09, 20.36, 13.43, 18.02);
        m_path.curve3(11.77, 15.67, 11.77, 12.89);
        m_path.curve3(11.77, 9.38, 13.87, 7.06);
        m_path.curve3(15.97, 4.74, 18.70, 4.74);
        m_path.curve3(22.41, 4.74, 28.47, 9.62);
        m_path.close_polygon();

        agg::trans_affine shape_mtx;
        shape_mtx *= agg::trans_affine_scaling(4.0);
        shape_mtx *= agg::trans_affine_translation(150, 100);
        m_path.transform(shape_mtx);

        agg::bounding_rect_single(m_shape, 0, 
                                  &m_shape_bounds.x1, &m_shape_bounds.y1, 
                                  &m_shape_bounds.x2, &m_shape_bounds.y2);

        m_shadow_ctrl.xn(0) = m_shape_bounds.x1;
        m_shadow_ctrl.yn(0) = m_shape_bounds.y1;
        m_shadow_ctrl.xn(1) = m_shape_bounds.x2;
        m_shadow_ctrl.yn(1) = m_shape_bounds.y1;
        m_shadow_ctrl.xn(2) = m_shape_bounds.x2;
        m_shadow_ctrl.yn(2) = m_shape_bounds.y2;
        m_shadow_ctrl.xn(3) = m_shape_bounds.x1;
        m_shadow_ctrl.yn(3) = m_shape_bounds.y2;
        m_shadow_ctrl.line_color(agg::rgba(0, 0.3, 0.5, 0.3));


        m_color_lut.resize(256);
        unsigned i;
        const agg::int8u* p = g_gradient_colors;
        for(i = 0; i < 256; i++)
        {
            m_color_lut[i] = agg::rgba8(p[0], p[1], p[2], (i > 63) ? 255 : i * 4);//p[3]);
            //m_color_lut[i].premultiply();
            p += 4;
        }
    }
Example #4
0
    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);

    }
Example #5
0
    the_application(agg::pix_format_e format, bool flip_y) :
        agg::platform_support(format, flip_y),
        m_ctrl_color(agg::rgba(0, 0.3, 0.5, 0.3)),
        m_line1(5),
        m_scale_x(5.0,   5.0, 240.0, 12.0, !flip_y),
        m_start_x(250.0, 5.0, 495.0, 12.0, !flip_y)
    {
        m_line1.line_color(m_ctrl_color);
        m_line1.xn(0) = 20;
        m_line1.yn(0) = 20;
        m_line1.xn(1) = 500-20;
        m_line1.yn(1) = 500-20;
        m_line1.xn(2) = 500-60;
        m_line1.yn(2) = 20;
        m_line1.xn(3) = 40;
        m_line1.yn(3) = 500-40;
        m_line1.xn(4) = 100;
        m_line1.yn(4) = 300;
        m_line1.close(false);

        add_ctrl(m_line1);
        m_line1.transform(m_scale);

        m_scale_x.label("Scale X=%.2f");
        m_scale_x.range(0.2, 3.0);
        m_scale_x.value(1.0);
        add_ctrl(m_scale_x);
        m_scale_x.no_transform();

        m_start_x.label("Start X=%.2f");
        m_start_x.range(0.0, 10.0);
        m_start_x.value(0.0);
        add_ctrl(m_start_x);
        m_start_x.no_transform();
    }
Example #6
0
    the_application(agg::pix_format_e format, bool flip_y) :
        agg::platform_support(format, flip_y),
        m_method     (10.0, 10.0, 130.0, 70.0, !flip_y),
        m_radius     (130 + 10.0, 10.0 + 4.0, 130 + 300.0, 10.0 + 8.0 + 4.0, !flip_y),
        m_shadow_ctrl(4),
        m_channel_r  (10.0, 80.0,  "Red", !flip_y),
        m_channel_g  (10.0, 95.0,  "Green", !flip_y),
        m_channel_b  (10.0, 110.0, "Blue", !flip_y),
        m_shape(m_path)
    {
        add_ctrl(m_method);
        m_method.text_size(8);
        m_method.add_item("Stack Blur");
        m_method.add_item("Recursive Blur");
        m_method.add_item("Channels");
        m_method.cur_item(0);

        add_ctrl(m_radius);
        m_radius.range(0.0, 40.0);
        m_radius.value(15.0);
        m_radius.label("Blur Radius=%1.2f");

        add_ctrl(m_shadow_ctrl);

        add_ctrl(m_channel_r);
        add_ctrl(m_channel_g);
        add_ctrl(m_channel_b);
        m_channel_g.status(true);

        m_path.remove_all();
        m_path.move_to(28.47, 6.45);
        m_path.curve3(21.58, 1.12, 19.82, 0.29);
        m_path.curve3(17.19, -0.93, 14.21, -0.93);
        m_path.curve3(9.57, -0.93, 6.57, 2.25);
        m_path.curve3(3.56, 5.42, 3.56, 10.60);
        m_path.curve3(3.56, 13.87, 5.03, 16.26);
        m_path.curve3(7.03, 19.58, 11.99, 22.51);
        m_path.curve3(16.94, 25.44, 28.47, 29.64);
        m_path.line_to(28.47, 31.40);
        m_path.curve3(28.47, 38.09, 26.34, 40.58);
        m_path.curve3(24.22, 43.07, 20.17, 43.07);
        m_path.curve3(17.09, 43.07, 15.28, 41.41);
        m_path.curve3(13.43, 39.75, 13.43, 37.60);
        m_path.line_to(13.53, 34.77);
        m_path.curve3(13.53, 32.52, 12.38, 31.30);
        m_path.curve3(11.23, 30.08, 9.38, 30.08);
        m_path.curve3(7.57, 30.08, 6.42, 31.35);
        m_path.curve3(5.27, 32.62, 5.27, 34.81);
        m_path.curve3(5.27, 39.01, 9.57, 42.53);
        m_path.curve3(13.87, 46.04, 21.63, 46.04);
        m_path.curve3(27.59, 46.04, 31.40, 44.04);
        m_path.curve3(34.28, 42.53, 35.64, 39.31);
        m_path.curve3(36.52, 37.21, 36.52, 30.71);
        m_path.line_to(36.52, 15.53);
        m_path.curve3(36.52, 9.13, 36.77, 7.69);
        m_path.curve3(37.01, 6.25, 37.57, 5.76);
        m_path.curve3(38.13, 5.27, 38.87, 5.27);
        m_path.curve3(39.65, 5.27, 40.23, 5.62);
        m_path.curve3(41.26, 6.25, 44.19, 9.18);
        m_path.line_to(44.19, 6.45);
        m_path.curve3(38.72, -0.88, 33.74, -0.88);
        m_path.curve3(31.35, -0.88, 29.93, 0.78);
        m_path.curve3(28.52, 2.44, 28.47, 6.45);
        m_path.close_polygon();

        m_path.move_to(28.47, 9.62);
        m_path.line_to(28.47, 26.66);
        m_path.curve3(21.09, 23.73, 18.95, 22.51);
        m_path.curve3(15.09, 20.36, 13.43, 18.02);
        m_path.curve3(11.77, 15.67, 11.77, 12.89);
        m_path.curve3(11.77, 9.38, 13.87, 7.06);
        m_path.curve3(15.97, 4.74, 18.70, 4.74);
        m_path.curve3(22.41, 4.74, 28.47, 9.62);
        m_path.close_polygon();

        agg::trans_affine shape_mtx;
        shape_mtx *= agg::trans_affine_scaling(4.0);
        shape_mtx *= agg::trans_affine_translation(150, 100);
        m_path.transform(shape_mtx);

        agg::bounding_rect_single(m_shape, 0, 
                                  &m_shape_bounds.x1, &m_shape_bounds.y1, 
                                  &m_shape_bounds.x2, &m_shape_bounds.y2);

        m_shadow_ctrl.xn(0) = m_shape_bounds.x1;
        m_shadow_ctrl.yn(0) = m_shape_bounds.y1;
        m_shadow_ctrl.xn(1) = m_shape_bounds.x2;
        m_shadow_ctrl.yn(1) = m_shape_bounds.y1;
        m_shadow_ctrl.xn(2) = m_shape_bounds.x2;
        m_shadow_ctrl.yn(2) = m_shape_bounds.y2;
        m_shadow_ctrl.xn(3) = m_shape_bounds.x1;
        m_shadow_ctrl.yn(3) = m_shape_bounds.y2;
        m_shadow_ctrl.line_color(agg::rgba(0, 0.3, 0.5, 0.3));
    }
Example #7
0
    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);
    }