#include <math.h> 
#include <stdio.h>
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_rasterizer_outline.h"
#include "agg_conv_stroke.h"
#include "agg_conv_dash.h"
#include "agg_conv_curve.h"
#include "agg_conv_contour.h"
#include "agg_conv_marker.h"
#include "agg_conv_shorten_path.h"
#include "agg_conv_marker_adaptor.h"
#include "agg_conv_concat.h"
#include "agg_arrowhead.h"
#include "agg_vcgen_markers_term.h"
#include "agg_scanline_p.h"
#include "agg_scanline_u.h"
#include "agg_renderer_scanline.h"
#include "agg_renderer_primitives.h"
#include "agg_span_allocator.h"
#include "agg_span_gradient.h"
#include "agg_span_interpolator_linear.h"
#include "agg_pixfmt_rgb.h"
#include "agg_pixfmt_rgba.h"
#include "ctrl/agg_slider_ctrl.h"
#include "ctrl/agg_rbox_ctrl.h"
#include "ctrl/agg_cbox_ctrl.h"
#include "platform/agg_platform_support.h"

#define AGG_BGR24
//#define AGG_BGR96
#include "pixel_formats.h"

enum flip_y_e { flip_y = true };

typedef agg::renderer_base<pixfmt> base_renderer;
typedef agg::renderer_primitives<base_renderer> primitives_renderer;

typedef agg::renderer_scanline_aa_solid<base_renderer>  solid_renderer;
typedef agg::renderer_scanline_bin_solid<base_renderer> draft_renderer;

typedef agg::gradient_radial_d gradient_function;
typedef agg::span_interpolator_linear<> interpolator;
typedef agg::pod_auto_array<color_type, 256> color_array_type;
typedef agg::span_gradient<color_type, 
                           interpolator, 
                           gradient_function, 
                           color_array_type> gradient_span_gen;
typedef agg::span_allocator<color_type> gradient_span_alloc;

typedef agg::renderer_scanline_aa<base_renderer, 
                                  gradient_span_alloc,
                                  gradient_span_gen> gradient_renderer;

typedef agg::rasterizer_scanline_aa<> scanline_rasterizer;
typedef agg::rasterizer_outline<primitives_renderer> outline_rasterizer;



//============================================================================
class graph
{
public:
    struct node
    {
        double x, y;
        node() {}
        node(double x_, double y_) : x(x_), y(y_) {}
    };

    struct edge
    {
        int node1;
        int node2;
        edge() {}
        edge(int n1, int n2) : node1(n1), node2(n2) {}
    };

	~graph()
    {
        delete [] m_edges;
        delete [] m_nodes;
    }

    graph(int num_nodes, int num_edges) :
        m_num_nodes(num_nodes),
        m_num_edges(num_edges),
        m_nodes(new node[num_nodes]),
        m_edges(new edge[num_edges])
    {
        int i;

	    srand(100);

	    for(i = 0; i < m_num_nodes; i++)
        {
            m_nodes[i].x = (double(rand()) / RAND_MAX) * 0.75 + 0.2;
            m_nodes[i].y = (double(rand()) / RAND_MAX) * 0.85 + 0.1;
        }

	    for(i = 0; i < m_num_edges; i++)
        {
            m_edges[i].node1 = rand() % m_num_nodes;
            m_edges[i].node2 = rand() % m_num_nodes;
            if(m_edges[i].node1 == m_edges[i].node2) i--;
        }
    }

    int get_num_nodes() const { return m_num_nodes; } 
    int get_num_edges() const { return m_num_edges; } 

	node get_node(int idx, double w, double h) const
    {
        node p(0.0, 0.0);
        if(idx < m_num_nodes)
        {
            p = m_nodes[idx];
            p.x = p.x * w;
            p.y = p.y * h;
        }
        return p;
    }

	edge get_edge(int idx) const
    {
        edge b(0,0);
        if(idx < m_num_edges)
        {
            b = m_edges[idx];
        }
        return b;
    }

private:
    graph(const graph&);
    const graph& operator = (const graph&);

    int m_num_nodes;
    int m_num_edges;
    node* m_nodes;
    edge* m_edges;
};








    
//============================================================================
struct line
{
    double x1, y1, x2, y2;
    int f;

    line(double x1_, double y1_, double x2_, double y2_) : 
        x1(x1_), y1(y1_), x2(x2_), y2(y2_), f(0) {}

    void rewind(unsigned) { f = 0; }
    unsigned vertex(double* x, double* y)
    {
        if(f == 0) { ++f; *x = x1; *y = y1; return agg::path_cmd_move_to; }
        if(f == 1) { ++f; *x = x2; *y = y2; return agg::path_cmd_line_to; }
        return agg::path_cmd_stop;
    }
};




//============================================================================
struct curve
{
    agg::curve4 c;

    curve(double x1, double y1, double x2, double y2, double k=0.5)
    {
        c.init(x1, y1, 
               x1 - (y2 - y1) * k,
               y1 + (x2 - x1) * k,
               x2 + (y2 - y1) * k,
               y2 - (x2 - x1) * k,
               x2, y2);
    }

    void rewind(unsigned path_id) { c.rewind(path_id); }
    unsigned vertex(double* x, double* y) { return c.vertex(x, y); }
};



//============================================================================
template<class Source> struct stroke_draft_simple
{
    Source& s;
    stroke_draft_simple(Source& src, double w) : 
        s(src)
    {
    }

    void rewind(unsigned path_id) { s.rewind(path_id); }
    unsigned vertex(double* x, double* y) { return s.vertex(x, y); }
};


//============================================================================
template<class Source> struct stroke_draft_arrow
{
    typedef agg::conv_marker_adaptor<Source, agg::vcgen_markers_term>           stroke_type;
    typedef agg::conv_marker<typename stroke_type::marker_type, agg::arrowhead> marker_type;
    typedef agg::conv_concat<stroke_type, marker_type>                          concat_type;

    stroke_type    s;
    agg::arrowhead ah;
    marker_type    m;
    concat_type    c;

    stroke_draft_arrow(Source& src, double w) : 
        s(src),
        ah(),
        m(s.markers(), ah),
        c(s, m)
    {
        ah.head(0, 10, 5, 0);
        s.shorten(10.0);
    }

    void rewind(unsigned path_id) { c.rewind(path_id); }
    unsigned vertex(double* x, double* y) { return c.vertex(x, y); }
};



//============================================================================
template<class Source> struct stroke_fine_simple
{
    typedef agg::conv_stroke<Source> stroke_type;

    stroke_type    s;

    stroke_fine_simple(Source& src, double w) : 
        s(src)
    {
        s.width(w); 
    }
    void rewind(unsigned path_id) { s.rewind(path_id); }
    unsigned vertex(double* x, double* y) { return s.vertex(x, y); }
};



//============================================================================
template<class Source> struct stroke_fine_arrow
{
    typedef agg::conv_stroke<Source, agg::vcgen_markers_term>                   stroke_type;
    typedef agg::conv_marker<typename stroke_type::marker_type, agg::arrowhead> marker_type;
    typedef agg::conv_concat<stroke_type, marker_type>                          concat_type;

    stroke_type    s;
    agg::arrowhead ah;
    marker_type    m;
    concat_type    c;

    stroke_fine_arrow(Source& src, double w) : 
        s(src),
        ah(),
        m(s.markers(), ah),
        c(s, m)
    {
        s.width(w); 
        ah.head(0, 10, 5, 0);
        s.shorten(w * 2.0);
    }

    void rewind(unsigned path_id) { c.rewind(path_id); }
    unsigned vertex(double* x, double* y) { return c.vertex(x, y); }
};



//============================================================================
template<class Source> struct dash_stroke_draft_simple
{
    typedef agg::conv_dash<Source, agg::vcgen_markers_term> dash_type;

    dash_type d;
    
    dash_stroke_draft_simple(Source& src, 
                             double dash_len, 
                             double gap_len, 
                             double w) : 
        d(src)
    {
        d.add_dash(dash_len, gap_len);
    }

    void rewind(unsigned path_id) { d.rewind(path_id); }
    unsigned vertex(double* x, double* y) { return d.vertex(x, y); }
};


//============================================================================
template<class Source> struct dash_stroke_draft_arrow
{
    typedef agg::conv_dash<Source, agg::vcgen_markers_term>                   dash_type;
    typedef agg::conv_marker<typename dash_type::marker_type, agg::arrowhead> marker_type;
    typedef agg::conv_concat<dash_type, marker_type>                          concat_type;

    dash_type      d;
    agg::arrowhead ah;
    marker_type    m;
    concat_type    c;

    dash_stroke_draft_arrow(Source& src, 
                            double dash_len, double gap_len, double w) : 
        d(src),
        ah(),
        m(d.markers(), ah),
        c(d, m)
    {
        d.add_dash(dash_len, gap_len);
        ah.head(0, 10, 5, 0);
        d.shorten(10.0);
    }

    void rewind(unsigned path_id) { c.rewind(path_id); }
    unsigned vertex(double* x, double* y) { return c.vertex(x, y); }
};




//============================================================================
template<class Source> struct dash_stroke_fine_simple
{
    typedef agg::conv_dash<Source>       dash_type;
    typedef agg::conv_stroke<dash_type>  stroke_type;

    dash_type      d;
    stroke_type    s;

    dash_stroke_fine_simple(Source& src, 
                           double dash_len, double gap_len, double w) : 
        d(src),
        s(d)
    {
        d.add_dash(dash_len, gap_len);
        s.width(w);
    }

    void rewind(unsigned path_id) { s.rewind(path_id); }
    unsigned vertex(double* x, double* y) { return s.vertex(x, y); }
};






//============================================================================
template<class Source> struct dash_stroke_fine_arrow
{
    typedef agg::conv_dash<Source, agg::vcgen_markers_term>                   dash_type;
    typedef agg::conv_stroke<dash_type>                                       stroke_type;
    typedef agg::conv_marker<typename dash_type::marker_type, agg::arrowhead> marker_type;
    typedef agg::conv_concat<stroke_type, marker_type>                        concat_type;

    dash_type      d;
    stroke_type    s;
    agg::arrowhead ah;
    marker_type    m;
    concat_type    c;

    dash_stroke_fine_arrow(Source& src, 
                           double dash_len, double gap_len, double w) : 
        d(src),
        s(d),
        ah(),
        m(d.markers(), ah),
        c(s, m)
    {
        d.add_dash(dash_len, gap_len);
        s.width(w);
        ah.head(0, 10, 5, 0);
        d.shorten(w * 2.0);
    }

    void rewind(unsigned path_id) { c.rewind(path_id); }
    unsigned vertex(double* x, double* y) { return c.vertex(x, y); }
};



//#define stroke_draft      stroke_draft_simple
//#define dash_stroke_draft dash_stroke_draft_simple
//#define stroke_fine       stroke_fine_simple
//#define dash_stroke_fine  dash_stroke_fine_simple

#define stroke_draft      stroke_draft_arrow
#define dash_stroke_draft dash_stroke_draft_arrow
#define stroke_fine       stroke_fine_arrow
#define dash_stroke_fine  dash_stroke_fine_arrow





class the_application : public agg::platform_support
{
    agg::rbox_ctrl<agg::rgba>   m_type;
    agg::slider_ctrl<agg::rgba> m_width;
    agg::cbox_ctrl<agg::rgba>   m_benchmark;
    agg::cbox_ctrl<agg::rgba>   m_draw_nodes;
    agg::cbox_ctrl<agg::rgba>   m_draw_edges;
    agg::cbox_ctrl<agg::rgba>   m_draft;
    agg::cbox_ctrl<agg::rgba>   m_translucent;
    graph                       m_graph;
    color_array_type            m_gradient_colors;
    int                         m_draw;
    agg::scanline_u8            m_sl;


public:
    the_application(agg::pix_format_e format, bool flip_y) :
        agg::platform_support(format, flip_y),
        m_type(-1, -1, -1, -1, !flip_y),
        m_width(110+80, 8.0, 110+200.0+80, 8.0 + 7.0, !flip_y),
        m_benchmark(110+200+80+8, 8.0-2.0, "Benchmark", !flip_y),
        m_draw_nodes(110+200+80+8, 8.0-2.0+15.0, "Draw Nodes", !flip_y),
        m_draw_edges(200+200+80+8, 8.0-2.0+15.0, "Draw Edges", !flip_y),
        m_draft(200+200+80+8, 8.0-2.0, "Draft Mode", !flip_y),
        m_translucent(110+80, 8.0-2.0+15.0, "Translucent Mode", !flip_y),
        m_graph(200, 100),
        m_gradient_colors(),
        m_draw(3)
    {
        add_ctrl(m_type);
        m_type.text_size(8.0);
        m_type.add_item("Solid lines");
        m_type.add_item("Bezier curves");
        m_type.add_item("Dashed curves");
        m_type.add_item("Poygons AA");
        m_type.add_item("Poygons Bin");
        m_type.cur_item(0);

        add_ctrl(m_width);
        m_width.num_steps(20);
        m_width.range(0.0, 5.0);
        m_width.value(2.0);
        m_width.label("Width=%1.2f");

        m_benchmark.text_size(8.0);
        m_draw_nodes.text_size(8.0);
        m_draft.text_size(8.0);
        m_draw_nodes.status(true);
        m_draw_edges.status(true);
        add_ctrl(m_benchmark);
        add_ctrl(m_draw_nodes);
        add_ctrl(m_draw_edges);
        add_ctrl(m_draft);
        add_ctrl(m_translucent);

        agg::rgba c1(1, 1, 0, 0.25);
        agg::rgba c2(0, 0, 1);

        int i;
        for(i = 0; i < 256; i++)
        {
            m_gradient_colors[i] = c1.gradient(c2, double(i) / 255.0);
        }
    }






    //------------------------------------------------------------------------
    void draw_nodes_draft()
    {
        pixfmt pixf(rbuf_window());
        base_renderer rb(pixf);
        primitives_renderer prim(rb);
        int i;
        for(i = 0; i < m_graph.get_num_nodes(); i++)
        {
            graph::node n = m_graph.get_node(i, width(), height());
            prim.fill_color(m_gradient_colors[147]);
            prim.line_color(m_gradient_colors[255]);
            prim.outlined_ellipse(int(n.x), int(n.y), 10, 10);
            prim.fill_color(m_gradient_colors[50]);
            prim.solid_ellipse(int(n.x), int(n.y), 4, 4);
        }
    }



    //------------------------------------------------------------------------
    void draw_nodes_fine(scanline_rasterizer& ras)
    {
        gradient_span_alloc sa;
        pixfmt pixf(rbuf_window());
        base_renderer rb(pixf);
        int i;
        for(i = 0; i < m_graph.get_num_nodes(); i++)
        {
            graph::node n = m_graph.get_node(i, width(), height());
            agg::ellipse ell(n.x, n.y, 5.0 * m_width.value(), 5.0 * m_width.value());

            double x, y;
            switch(m_draw)
            {
                case 0:
                    ell.rewind(0);
                    while(!agg::is_stop(ell.vertex(&x, &y)));
                    break;

                case 1:
                    ras.reset();
                    ras.add_path(ell);
                    break;

                case 2:
                    ras.reset();
                    ras.add_path(ell);
                    ras.sort();
                    break;

                case 3:
                {
                    gradient_function gf;
                    agg::trans_affine mtx;
                    mtx *= agg::trans_affine_scaling(m_width.value() / 2.0);
                    mtx *= agg::trans_affine_translation(n.x, n.y);
                    mtx.invert();
                    interpolator inter(mtx);
                    gradient_span_gen sg(inter, gf, m_gradient_colors, 0.0, 10.0);
                    gradient_renderer ren(rb, sa, sg);
                    ras.add_path(ell);
                    agg::render_scanlines(ras, m_sl, ren);
                }
                break;
            }
        }
    }





    //------------------------------------------------------------------------
    template<class Source>
    void render_edge_fine(scanline_rasterizer& ras, 
                          solid_renderer& ren_fine,
                          draft_renderer& ren_draft,
                          Source& src)
    {
        double x, y;
        switch(m_draw)
        {
            case 0:
                src.rewind(0);
                while(!agg::is_stop(src.vertex(&x, &y)));
            break;

            case 1:
                ras.reset();
                ras.add_path(src);
            break;

            case 2:
                ras.reset();
                ras.add_path(src);
                ras.sort();
            break;

            case 3:
            {
                int r = rand() & 0x7F;
                int g = rand() & 0x7F;
                int b = rand() & 0x7F;
                int a = 255;
                if(m_translucent.status()) a = 80;
                ras.add_path(src);

                if(m_type.cur_item() < 4)
                {
                    ren_fine.color(agg::srgba8(r, g, b, a));
                    agg::render_scanlines(ras, m_sl, ren_fine);
                }
                else
                {
                    ren_draft.color(agg::srgba8(r, g, b, a));
                    agg::render_scanlines(ras, m_sl, ren_draft);
                }
            }
            break;
        }
    }



    //------------------------------------------------------------------------
    void draw_lines_draft()
    {
        pixfmt pixf(rbuf_window());
        base_renderer rb(pixf);
        primitives_renderer prim(rb);
        outline_rasterizer ras(prim);

        int i;
        for(i = 0; i < m_graph.get_num_edges(); i++)
        {
            graph::edge e  = m_graph.get_edge(i);
            graph::node n1 = m_graph.get_node(e.node1, width(), height());
            graph::node n2 = m_graph.get_node(e.node2, width(), height());
            line l(n1.x, n1.y, n2.x, n2.y);
            stroke_draft<line> s(l, m_width.value());

            int r = rand() & 0x7F;
            int g = rand() & 0x7F;
            int b = rand() & 0x7F;
            int a = 255;
            if(m_translucent.status()) a = 80;
            prim.line_color(agg::srgba8(r, g, b, a));
            ras.add_path(s);
        }
    }


    //------------------------------------------------------------------------
    void draw_curves_draft()
    {
        pixfmt pixf(rbuf_window());
        base_renderer rb(pixf);
        primitives_renderer prim(rb);
        outline_rasterizer ras(prim);

        int i;
        for(i = 0; i < m_graph.get_num_edges(); i++)
        {
            graph::edge e  = m_graph.get_edge(i);
            graph::node n1 = m_graph.get_node(e.node1, width(), height());
            graph::node n2 = m_graph.get_node(e.node2, width(), height());
            curve c(n1.x, n1.y, n2.x, n2.y);
            stroke_draft<curve> s(c, m_width.value());

            int r = rand() & 0x7F;
            int g = rand() & 0x7F;
            int b = rand() & 0x7F;
            int a = 255;
            if(m_translucent.status()) a = 80;
            prim.line_color(agg::srgba8(r, g, b, a));
            ras.add_path(s);
        }
    }


    //------------------------------------------------------------------------
    void draw_dashes_draft()
    {
        pixfmt pixf(rbuf_window());
        base_renderer rb(pixf);
        primitives_renderer prim(rb);
        outline_rasterizer ras(prim);

        int i;
        for(i = 0; i < m_graph.get_num_edges(); i++)
        {
            graph::edge e  = m_graph.get_edge(i);
            graph::node n1 = m_graph.get_node(e.node1, width(), height());
            graph::node n2 = m_graph.get_node(e.node2, width(), height());
            curve c(n1.x, n1.y, n2.x, n2.y);
            dash_stroke_draft<curve> s(c, 6.0, 3.0, m_width.value());

            int r = rand() & 0x7F;
            int g = rand() & 0x7F;
            int b = rand() & 0x7F;
            int a = 255;
            if(m_translucent.status()) a = 80;
            prim.line_color(agg::srgba8(r, g, b, a));
            ras.add_path(s);
        }
    }


    //------------------------------------------------------------------------
    void draw_lines_fine(scanline_rasterizer& ras, 
                         solid_renderer& solid,
                         draft_renderer& draft)
    {
        int i;
        for(i = 0; i < m_graph.get_num_edges(); i++)
        {
            graph::edge b  = m_graph.get_edge(i);
            graph::node n1 = m_graph.get_node(b.node1, width(), height());
            graph::node n2 = m_graph.get_node(b.node2, width(), height());
            line l(n1.x, n1.y, n2.x, n2.y);
            stroke_fine<line> s(l, m_width.value());
            render_edge_fine(ras, solid, draft, s);
        }
    }


    //------------------------------------------------------------------------
    void draw_curves_fine(scanline_rasterizer& ras, 
                          solid_renderer& solid,
                          draft_renderer& draft)

    {
        int i;
        for(i = 0; i < m_graph.get_num_edges(); i++)
        {
            graph::edge b  = m_graph.get_edge(i);
            graph::node n1 = m_graph.get_node(b.node1, width(), height());
            graph::node n2 = m_graph.get_node(b.node2, width(), height());
            curve c(n1.x, n1.y, n2.x, n2.y);
            stroke_fine<curve> s(c, m_width.value());
            render_edge_fine(ras, solid, draft, s);
        }
    }


    //------------------------------------------------------------------------
    void draw_dashes_fine(scanline_rasterizer& ras, 
                          solid_renderer& solid,
                          draft_renderer& draft)
    {
        int i;
        for(i = 0; i < m_graph.get_num_edges(); i++)
        {
            graph::edge b  = m_graph.get_edge(i);
            graph::node n1 = m_graph.get_node(b.node1, width(), height());
            graph::node n2 = m_graph.get_node(b.node2, width(), height());
            curve c(n1.x, n1.y, n2.x, n2.y);
            dash_stroke_fine<curve> s(c, 6.0, 3.0, m_width.value());
            render_edge_fine(ras, solid, draft, s);
        }
    }


    //------------------------------------------------------------------------
    void draw_polygons(scanline_rasterizer& ras, 
                       solid_renderer& solid,
                       draft_renderer& draft)
    {
        int i;
        if(m_type.cur_item() == 4)
        {
            ras.gamma(agg::gamma_threshold(0.5));
        }
        for(i = 0; i < m_graph.get_num_edges(); i++)
        {
            graph::edge b  = m_graph.get_edge(i);
            graph::node n1 = m_graph.get_node(b.node1, width(), height());
            graph::node n2 = m_graph.get_node(b.node2, width(), height());
            curve c(n1.x, n1.y, n2.x, n2.y);
            render_edge_fine(ras, solid, draft, c);
        }
        ras.gamma(agg::gamma_none());
    }



    //------------------------------------------------------------------------
    void draw_scene(scanline_rasterizer& ras, 
                    solid_renderer& solid,
                    draft_renderer& draft)
    {
        ras.gamma(agg::gamma_none());
        srand(100);
        if(m_draw_nodes.status())
        {
            if(m_draft.status())
            {
                draw_nodes_draft();
            }
            else
            {
                draw_nodes_fine(ras);
            }
        }

        if(m_draw_edges.status())
        {
            if(m_draft.status()) 
            {
                switch(m_type.cur_item())
                {
                case 0: draw_lines_draft();    break;
                case 1: draw_curves_draft();   break;
                case 2: draw_dashes_draft();   break;
                }
            }
            else
            {
                switch(m_type.cur_item())
                {
                case 0: draw_lines_fine(ras, solid, draft);  break;
                case 1: draw_curves_fine(ras, solid, draft); break;
                case 2: draw_dashes_fine(ras, solid, draft); break;
                case 3: 
                case 4: draw_polygons(ras, solid, draft);    break;
                }
            }
        }
    }












    //------------------------------------------------------------------------
    virtual void on_draw()
    {
        scanline_rasterizer ras;

        pixfmt pixf(rbuf_window());
        base_renderer rb(pixf);
        solid_renderer solid(rb);
        draft_renderer draft(rb);

        rb.clear(agg::rgba(1, 1, 1));
        draw_scene(ras, solid, draft);

        ras.filling_rule(agg::fill_non_zero);
        agg::render_ctrl(ras, m_sl, rb, m_type);
        agg::render_ctrl(ras, m_sl, rb, m_width);
        agg::render_ctrl(ras, m_sl, rb, m_benchmark);
        agg::render_ctrl(ras, m_sl, rb, m_draw_nodes);
        agg::render_ctrl(ras, m_sl, rb, m_draw_edges);
        agg::render_ctrl(ras, m_sl, rb, m_draft);
        agg::render_ctrl(ras, m_sl, rb, m_translucent);
    }




    virtual void on_ctrl_change()
    {
        if(m_benchmark.status())
        {
            int i;
            on_draw();
            update_window();

            scanline_rasterizer ras;

            pixfmt pixf(rbuf_window());
            base_renderer rb(pixf);
            solid_renderer solid(rb);
            draft_renderer draft(rb);

            char buf[256];
            if(m_draft.status())
            {
                start_timer();
                for(i = 0; i < 10; i++)
                {
                    draw_scene(ras, solid, draft);
                }
                sprintf(buf, "%3.3f milliseconds", elapsed_time());
            }
            else
            {
                double times[5];
                for(m_draw = 0; m_draw < 4; m_draw++)
                {
                    start_timer();
                    for(i = 0; i < 10; i++)
                    {
                        draw_scene(ras, solid, draft);
                    }
                    times[m_draw] = elapsed_time();
                }
                m_draw = 3;

                times[4]  = times[3];
                times[3] -= times[2];
                times[2] -= times[1];
                times[1] -= times[0];
            
                FILE* fd = fopen(full_file_name("benchmark"), "a");
                fprintf(fd, "%10.3f %10.3f %10.3f %10.3f %10.3f\n", 
                            times[0], times[1], times[2], times[3], times[4]);
                fclose(fd);
            

                sprintf(buf, "  pipeline  add_path         sort       render       total\n"
                             "%10.3f %10.3f %10.3f %10.3f %10.3f", 
                        times[0], times[1], times[2], times[3], times[4]);
            }
            message(buf);

            m_benchmark.status(false);
            force_redraw();
        }
    }
};



int agg_main(int argc, char* argv[])
{
    the_application app(pix_format, flip_y);
    app.caption("AGG Example. Line Join");

    if(app.init(600+100, 500+30, agg::window_resize))
    {
        return app.run();
    }
    return 1;
}


