Example #1
0
    virtual void on_draw()
    {
        pixfmt pixf(rbuf_window());
        renderer_base rb(pixf);
        renderer_solid r(rb);
        rb.clear(agg::rgba(1, 1, 1));

        g_rasterizer.clip_box(0, 0, width(), height());

        if(m_trans_type.cur_item() == 0)
        {
            agg::trans_bilinear tr(g_x1, g_y1, g_x2, g_y2, m_quad.polygon());
            if(tr.is_valid())
            {
                //--------------------------
                // Render transformed lion
                //
                agg::conv_transform<agg::path_storage, 
                                    agg::trans_bilinear> trans(g_path, tr);

                agg::render_all_paths(g_rasterizer, g_scanline, r, trans, g_colors, g_path_idx, g_npaths);
                //--------------------------



                //--------------------------
                // Render transformed ellipse
                //
                agg::ellipse ell((g_x1 + g_x2) * 0.5, (g_y1 + g_y2) * 0.5, 
                                 (g_x2 - g_x1) * 0.5, (g_y2 - g_y1) * 0.5,
                                 200);
                agg::conv_stroke<agg::ellipse> ell_stroke(ell);
                ell_stroke.width(3.0);
                agg::conv_transform<agg::ellipse, 
                                    agg::trans_bilinear> trans_ell(ell, tr);

                agg::conv_transform<agg::conv_stroke<agg::ellipse>, 
                                    agg::trans_bilinear> trans_ell_stroke(ell_stroke, tr);

                g_rasterizer.add_path(trans_ell);
                r.color(agg::rgba(0.5, 0.3, 0.0, 0.3));
                agg::render_scanlines(g_rasterizer, g_scanline, r);

                g_rasterizer.add_path(trans_ell_stroke);
                r.color(agg::rgba(0.0, 0.3, 0.2, 1.0));
                agg::render_scanlines(g_rasterizer, g_scanline, r);
                //--------------------------

            }
        }
        else
        {
            agg::trans_perspective tr(g_x1, g_y1, g_x2, g_y2, m_quad.polygon());
            if(tr.is_valid())
            {

                //--------------------------
                // Render transformed lion
                //
                agg::conv_transform<agg::path_storage, 
                                    agg::trans_perspective> trans(g_path, tr);

                agg::render_all_paths(g_rasterizer, g_scanline, r, trans, g_colors, g_path_idx, g_npaths);

                //--------------------------



                //--------------------------
                // Render transformed ellipse
                //
                agg::ellipse ell((g_x1 + g_x2) * 0.5, (g_y1 + g_y2) * 0.5, 
                                 (g_x2 - g_x1) * 0.5, (g_y2 - g_y1) * 0.5,
                                 200);

                agg::conv_stroke<agg::ellipse> ell_stroke(ell);
                ell_stroke.width(3.0);
                agg::conv_transform<agg::ellipse, 
                                    agg::trans_perspective> trans_ell(ell, tr);


                agg::conv_transform<agg::conv_stroke<agg::ellipse>, 
                                    agg::trans_perspective> trans_ell_stroke(ell_stroke, tr);


                g_rasterizer.add_path(trans_ell);
                r.color(agg::rgba(0.5, 0.3, 0.0, 0.3));
                agg::render_scanlines(g_rasterizer, g_scanline, r);

                g_rasterizer.add_path(trans_ell_stroke);
                r.color(agg::rgba(0.0, 0.3, 0.2, 1.0));
                agg::render_scanlines(g_rasterizer, g_scanline, r);
                //--------------------------


                // Testing the reverse transformations
                //agg::trans_perspective tr2(m_quad.polygon(), g_x1, g_y1, g_x2, g_y2);
                //if(tr2.is_valid())
                //{
                //    double x, y;
                //    x = m_quad.xn(0); y = m_quad.yn(0); tr2.transform(&x, &y);
                //    g_rasterizer.move_to_d(x, y);
                //    x = m_quad.xn(1); y = m_quad.yn(1); tr2.transform(&x, &y);
                //    g_rasterizer.line_to_d(x, y);
                //    x = m_quad.xn(2); y = m_quad.yn(2); tr2.transform(&x, &y);
                //    g_rasterizer.line_to_d(x, y);
                //    x = m_quad.xn(3); y = m_quad.yn(3); tr2.transform(&x, &y);
                //    g_rasterizer.line_to_d(x, y);
                //    r.color(agg::rgba(0.5, 0.0, 0.0, 0.5));
                //    agg::render_scanlines(g_rasterizer, g_scanline, r);
                //}
                //else
                //{
                //    message("Singularity...");
                //}
            }
        }




        //--------------------------
        // Render the "quad" tool and controls
        g_rasterizer.add_path(m_quad);
        r.color(agg::rgba(0, 0.3, 0.5, 0.6));
        agg::render_scanlines(g_rasterizer, g_scanline, r);
        agg::render_ctrl(g_rasterizer, g_scanline, rb, m_trans_type);
        //--------------------------
    }
    virtual void on_draw()
    {
        pixfmt            pixf(rbuf_window());
        pixfmt_pre        pixf_pre(rbuf_window());
        renderer_base     rb(pixf);
        renderer_base_pre rb_pre(pixf_pre);

        if(!m_test_flag)
        {
            rb.clear(agg::rgba(1, 1, 1));
        }

        if(m_trans_type.cur_item() == 0)
        {
            // For the affine parallelogram transformations we
            // calculate the 4-th (implicit) point of the parallelogram
            m_quad.xn(3) = m_quad.xn(0) + (m_quad.xn(2) - m_quad.xn(1));
            m_quad.yn(3) = m_quad.yn(0) + (m_quad.yn(2) - m_quad.yn(1));
        }

        if(!m_test_flag)
        {
            //--------------------------
            // Render the "quad" tool and controls
            g_rasterizer.add_path(m_quad);
            agg::render_scanlines_aa_solid(g_rasterizer, g_scanline, rb, agg::rgba(0, 0.3, 0.5, 0.6));

            //--------------------------
            agg::render_ctrl(g_rasterizer, g_scanline, rb, m_trans_type);
        }

        // Prepare the polygon to rasterize. Here we need to fill
        // the destination (transformed) polygon.
        g_rasterizer.clip_box(0, 0, width(), height());
        g_rasterizer.reset();
        g_rasterizer.move_to_d(m_quad.xn(0), m_quad.yn(0));
        g_rasterizer.line_to_d(m_quad.xn(1), m_quad.yn(1));
        g_rasterizer.line_to_d(m_quad.xn(2), m_quad.yn(2));
        g_rasterizer.line_to_d(m_quad.xn(3), m_quad.yn(3));


        typedef agg::span_allocator<color_type> span_alloc_type;
        span_alloc_type sa;
        agg::image_filter<agg::image_filter_hanning> filter;
    
        typedef agg::wrap_mode_reflect_auto_pow2 remainder_type;
        typedef agg::image_accessor_wrap<pixfmt, 
                                         remainder_type, 
                                         remainder_type> img_source_type;

        pixfmt img_pixf(rbuf_img(0));
        img_source_type img_src(img_pixf);

        enum subdiv_shift_e { subdiv_shift = 2 };
         
        switch(m_trans_type.cur_item())
        {
            case 0:
            {
                // Note that we consruct an affine matrix that transforms
                // a parallelogram to a rectangle, i.e., it's inverted.
                // It's actually the same as:
                // tr(g_x1, g_y1, g_x2, g_y2, m_triangle.polygon());
                // tr.invert();
                agg::trans_affine tr(m_quad.polygon(), g_x1, g_y1, g_x2, g_y2);

                // Also note that we can use the linear interpolator instead of 
                // arbitrary span_interpolator_trans. It works much faster, 
                // but the transformations must be linear and parellel.
                typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type;
                interpolator_type interpolator(tr);

                typedef span_image_filter_2x2<img_source_type,
                                              interpolator_type> span_gen_type;
                span_gen_type sg(img_src, interpolator, filter);
                agg::render_scanlines_aa(g_rasterizer, g_scanline, rb_pre, sa, sg);
                break;
            }

            case 1:
            {
                agg::trans_bilinear tr(m_quad.polygon(), g_x1, g_y1, g_x2, g_y2);
                if(tr.is_valid())
                {
                    typedef agg::span_interpolator_linear<agg::trans_bilinear> interpolator_type;
                    interpolator_type interpolator(tr);

                    typedef span_image_filter_2x2<img_source_type,
                                                  interpolator_type> span_gen_type;
                    span_gen_type sg(img_src, interpolator, filter);
                    agg::render_scanlines_aa(g_rasterizer, g_scanline, rb_pre, sa, sg);
                }
                break;
            }

            case 2:
            {
                agg::trans_perspective tr(m_quad.polygon(), g_x1, g_y1, g_x2, g_y2);
                if(tr.is_valid())
                {
                    typedef agg::span_interpolator_linear_subdiv<agg::trans_perspective, 8> interpolator_type;
                    interpolator_type interpolator(tr);

                    typedef span_image_filter_2x2<img_source_type,
                                                  interpolator_type> span_gen_type;
                    span_gen_type sg(img_src, interpolator, filter);
                    agg::render_scanlines_aa(g_rasterizer, g_scanline, rb_pre, sa, sg);
                }
                break;
            }
        }
    }
Example #3
0
void roadmap_canvas_agg_configure (unsigned char *buf, int width, int height, int stride) {

   roadmap_log( ROADMAP_ERROR, "roadmap_canvas_agg_configure, height =%d width=%d",height, width);
   agg_rbuf.attach(buf, width, height, stride);

   agg_renb.attach(agg_pixf);
   agg_renb.reset_clipping(true);
   ras.clip_box(0, 0, agg_renb.width() - 1, agg_renb.height() - 1);

   agg::glyph_rendering gren = agg::glyph_ren_outline;
   agg::glyph_rendering image_gren = agg::glyph_ren_agg_gray8;

   roadmap_config_declare
       ("preferences", &RoadMapConfigFont, "font.ttf", NULL);

   roadmap_config_declare
       ("preferences", &RoadMapConfigFontNormal, "font_normal.ttf", NULL);

   char *font_file = roadmap_path_join(roadmap_path_user(),
		   roadmap_config_get (&RoadMapConfigFont));

   if ((width) && (height))
      roadmap_screen_set_screen_type( width, height );

   if (!RoadMapCanvasFontLoaded) {

      if(m_feng.load_font(font_file, 0, gren) &&
            m_image_feng.load_font(font_file, 0, image_gren)) {

         m_feng.hinting(true);

         if ( roadmap_screen_is_hd_screen() )
         {
			 m_feng.height(22);
			 m_feng.width(22);
         }
         else
         {
#ifdef _WIN32
          m_feng.height(12);
          m_feng.width(12);
#else
          m_feng.height(15);
          m_feng.width(15);
#endif
         }

         m_feng.flip_y(true);

         m_image_feng.hinting(true);
         m_image_feng.flip_y(true);

         RoadMapCanvasFontLoaded = 1;
      } else {
         RoadMapCanvasFontLoaded = -1;
         char message[300];
         snprintf(message, sizeof(message), "Can't load font: %s\n", font_file);
         roadmap_messagebox("Error", message);
      }
   }
   RoadMapCanvasFontLoaded = 1;
   roadmap_path_free(font_file);

   font_file = roadmap_path_join(roadmap_path_user(),
         roadmap_config_get (&RoadMapConfigFontNormal));


   if(m_feng_nor.load_font(font_file, 0, gren) &&
            m_image_feng_nor.load_font(font_file, 0, image_gren)) {

         m_feng_nor.hinting(true);

         if ( roadmap_screen_is_hd_screen() )
         {
          m_feng_nor.height(22);
          m_feng_nor.width(22);
         }
         else
         {
#ifdef _WIN32
          m_feng_nor.height(12);
          m_feng_nor.width(12);
#else
          m_feng_nor.height(15);
          m_feng_nor.width(15);
#endif
         }

         m_feng_nor.flip_y(true);

         m_image_feng_nor.hinting(true);
         m_image_feng_nor.flip_y(true);
         RoadMapCanvasNormalFontLoaded = 1;
   }
}
    virtual void on_draw()
    {
        if(m_gamma.value() != m_old_gamma)
        {
            m_gamma_lut.gamma(m_gamma.value());
            load_img(0, "spheres");
            pixfmt pixf(rbuf_img(0));
            pixf.apply_gamma_dir(m_gamma_lut);
            m_old_gamma = m_gamma.value();
        }

        pixfmt            pixf(rbuf_window());
        pixfmt_pre        pixf_pre(rbuf_window());
        renderer_base     rb(pixf);
        renderer_base_pre rb_pre(pixf_pre);

        renderer_solid r(rb);

        rb.clear(agg::rgba(1, 1, 1));

        if(m_trans_type.cur_item() < 2)
        {
            // For the affine parallelogram transformations we
            // calculate the 4-th (implicit) point of the parallelogram
            m_quad.xn(3) = m_quad.xn(0) + (m_quad.xn(2) - m_quad.xn(1));
            m_quad.yn(3) = m_quad.yn(0) + (m_quad.yn(2) - m_quad.yn(1));
        }

        //--------------------------
        // Render the "quad" tool and controls
        g_rasterizer.add_path(m_quad);
        r.color(agg::rgba(0, 0.3, 0.5, 0.1));
        agg::render_scanlines(g_rasterizer, g_scanline, r);

        // Prepare the polygon to rasterize. Here we need to fill
        // the destination (transformed) polygon.
        g_rasterizer.clip_box(0, 0, width(), height());
        g_rasterizer.reset();
        int b = 0;
        g_rasterizer.move_to_d(m_quad.xn(0)-b, m_quad.yn(0)-b);
        g_rasterizer.line_to_d(m_quad.xn(1)+b, m_quad.yn(1)-b);
        g_rasterizer.line_to_d(m_quad.xn(2)+b, m_quad.yn(2)+b);
        g_rasterizer.line_to_d(m_quad.xn(3)-b, m_quad.yn(3)+b);

        typedef agg::span_allocator<color_type> span_alloc_type;
        span_alloc_type sa;
        agg::image_filter_bilinear filter_kernel;
        agg::image_filter_lut filter(filter_kernel, true);

        pixfmt pixf_img(rbuf_img(0));
        typedef agg::image_accessor_clone<pixfmt> source_type;
        source_type source(pixf_img);

        start_timer();
        switch(m_trans_type.cur_item())
        {
            case 0:
            {
                agg::trans_affine tr(m_quad.polygon(), g_x1, g_y1, g_x2, g_y2);

                typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type;
                interpolator_type interpolator(tr);

                typedef image_filter_2x2_type<source_type, 
                                              interpolator_type> span_gen_type;
                span_gen_type sg(source, interpolator, filter);
                agg::render_scanlines_aa(g_rasterizer, g_scanline, rb_pre, sa, sg);
                break;
            }

            case 1:
            {
                agg::trans_affine tr(m_quad.polygon(), g_x1, g_y1, g_x2, g_y2);

                typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type;
                typedef image_resample_affine_type<source_type> span_gen_type;

                interpolator_type interpolator(tr);
                span_gen_type sg(source, interpolator, filter);
                sg.blur(m_blur.value());
                agg::render_scanlines_aa(g_rasterizer, g_scanline, rb_pre, sa, sg);
                break;
            }

            case 2:
            {
                agg::trans_perspective tr(m_quad.polygon(), g_x1, g_y1, g_x2, g_y2);
                if(tr.is_valid())
                {
                    typedef agg::span_interpolator_linear_subdiv<agg::trans_perspective> interpolator_type;
                    interpolator_type interpolator(tr);

                    typedef image_filter_2x2_type<source_type,
                                                  interpolator_type> span_gen_type;
                    span_gen_type sg(source, interpolator, filter);
                    agg::render_scanlines_aa(g_rasterizer, g_scanline, rb_pre, sa, sg);
                }
                break;
            }

            case 3:
            {
                agg::trans_perspective tr(m_quad.polygon(), g_x1, g_y1, g_x2, g_y2);
                if(tr.is_valid())
                {
                    typedef agg::span_interpolator_trans<agg::trans_perspective> interpolator_type;
                    interpolator_type interpolator(tr);

                    typedef image_filter_2x2_type<source_type, 
                                                  interpolator_type> span_gen_type;
                    span_gen_type sg(source, interpolator, filter);
                    agg::render_scanlines_aa(g_rasterizer, g_scanline, rb_pre, sa, sg);
                }
                break;
            }

            case 4:
            {
                typedef agg::span_interpolator_persp_lerp<> interpolator_type;
                typedef agg::span_subdiv_adaptor<interpolator_type> subdiv_adaptor_type;

                interpolator_type interpolator(m_quad.polygon(), g_x1, g_y1, g_x2, g_y2);
                subdiv_adaptor_type subdiv_adaptor(interpolator);

                if(interpolator.is_valid())
                {
                    typedef image_resample_type<source_type, 
                                                subdiv_adaptor_type> span_gen_type;
                    span_gen_type sg(source, subdiv_adaptor, filter);
                    sg.blur(m_blur.value());
                    agg::render_scanlines_aa(g_rasterizer, g_scanline, rb_pre, sa, sg);
                }
                break;
            }

            case 5:
            {
                typedef agg::span_interpolator_persp_exact<> interpolator_type;
                typedef agg::span_subdiv_adaptor<interpolator_type> subdiv_adaptor_type;

                interpolator_type interpolator(m_quad.polygon(), g_x1, g_y1, g_x2, g_y2);
                subdiv_adaptor_type subdiv_adaptor(interpolator);

                if(interpolator.is_valid())
                {
                    typedef image_resample_type<source_type, 
                                                subdiv_adaptor_type> span_gen_type;
                    span_gen_type sg(source, subdiv_adaptor, filter);
                    sg.blur(m_blur.value());
                    agg::render_scanlines_aa(g_rasterizer, g_scanline, rb_pre, sa, sg);
                }
                break;
            }
        }
        double tm = elapsed_time();
        pixf.apply_gamma_inv(m_gamma_lut);

        char buf[64]; 
        agg::gsv_text t;
        t.size(10.0);

        agg::conv_stroke<agg::gsv_text> pt(t);
        pt.width(1.5);

        sprintf(buf, "%3.2f ms", tm);
        t.start_point(10.0, 70.0);
        t.text(buf);

        g_rasterizer.add_path(pt);
        r.color(agg::rgba(0,0,0));
        agg::render_scanlines(g_rasterizer, g_scanline, r);

        //--------------------------
        agg::render_ctrl(g_rasterizer, g_scanline, rb, m_trans_type);
        agg::render_ctrl(g_rasterizer, g_scanline, rb, m_gamma);
        agg::render_ctrl(g_rasterizer, g_scanline, rb, m_blur);
    }
Example #5
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 #6
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);
    }