agg/examples/rasterizers2.cpp

553 lines
18 KiB
C++

#include <math.h>
#include <stdio.h>
#include <time.h>
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_rasterizer_outline.h"
#include "agg_conv_transform.h"
#include "agg_conv_stroke.h"
#include "agg_scanline_p.h"
#include "agg_renderer_scanline.h"
#include "agg_renderer_primitives.h"
#include "agg_rasterizer_outline.h"
#include "agg_rasterizer_outline_aa.h"
#include "agg_pattern_filters_rgba.h"
#include "agg_renderer_outline_aa.h"
#include "agg_renderer_outline_image.h"
#include "ctrl/agg_slider_ctrl.h"
#include "ctrl/agg_cbox_ctrl.h"
#include "platform/agg_platform_support.h"
#define AGG_BGR24
//#define AGG_RGB24
//#define AGG_BGRA32
//#define AGG_RGBA32
//#define AGG_ARGB32
//#define AGG_ABGR32
//#define AGG_RGB565
//#define AGG_RGB555
#include "pixel_formats.h"
enum flip_y_e { flip_y = true };
static const agg::int32u pixmap_chain[] =
{
16, 7,
0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xb4c29999, 0xff9a5757, 0xff9a5757, 0xff9a5757, 0xff9a5757, 0xff9a5757, 0xff9a5757, 0xb4c29999, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
0x00ffffff, 0x00ffffff, 0x0cfbf9f9, 0xff9a5757, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xb4c29999, 0x00ffffff, 0x00ffffff, 0x00ffffff,
0x00ffffff, 0x5ae0cccc, 0xffa46767, 0xff660000, 0xff975252, 0x7ed4b8b8, 0x5ae0cccc, 0x5ae0cccc, 0x5ae0cccc, 0x5ae0cccc, 0xa8c6a0a0, 0xff7f2929, 0xff670202, 0x9ecaa6a6, 0x5ae0cccc, 0x00ffffff,
0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xa4c7a2a2, 0x3affff00, 0x3affff00, 0xff975151, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000,
0x00ffffff, 0x5ae0cccc, 0xffa46767, 0xff660000, 0xff954f4f, 0x7ed4b8b8, 0x5ae0cccc, 0x5ae0cccc, 0x5ae0cccc, 0x5ae0cccc, 0xa8c6a0a0, 0xff7f2929, 0xff670202, 0x9ecaa6a6, 0x5ae0cccc, 0x00ffffff,
0x00ffffff, 0x00ffffff, 0x0cfbf9f9, 0xff9a5757, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xff660000, 0xb4c29999, 0x00ffffff, 0x00ffffff, 0x00ffffff,
0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xb4c29999, 0xff9a5757, 0xff9a5757, 0xff9a5757, 0xff9a5757, 0xff9a5757, 0xff9a5757, 0xb4c29999, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff
};
namespace agg
{
class pattern_pixmap_argb32
{
public:
typedef rgba color_type;
pattern_pixmap_argb32(const int32u* pixmap) : m_pixmap(pixmap) {}
unsigned width() const { return m_pixmap[0]; }
unsigned height() const { return m_pixmap[1]; }
rgba pixel(int x, int y) const
{
int32u p = m_pixmap[y * width() + x + 2];
srgba8 c((p >> 16) & 0xFF, (p >> 8) & 0xFF, p & 0xFF, p >> 24);
return rgba(c).premultiply();
}
private:
const int32u* m_pixmap;
};
}
class spiral
{
public:
spiral(double x, double y, double r1, double r2, double step, double start_angle=0) :
m_x(x),
m_y(y),
m_r1(r1),
m_r2(r2),
m_step(step),
m_start_angle(start_angle),
m_angle(start_angle),
m_da(agg::deg2rad(8.0)),
m_dr(m_step / 45.0)
{
}
void rewind(unsigned)
{
m_angle = m_start_angle;
m_curr_r = m_r1;
m_start = true;
}
unsigned vertex(double* x, double* y)
{
if(m_curr_r > m_r2) return agg::path_cmd_stop;
*x = m_x + cos(m_angle) * m_curr_r;
*y = m_y + sin(m_angle) * m_curr_r;
m_curr_r += m_dr;
m_angle += m_da;
if(m_start)
{
m_start = false;
return agg::path_cmd_move_to;
}
return agg::path_cmd_line_to;
}
private:
double m_x;
double m_y;
double m_r1;
double m_r2;
double m_step;
double m_start_angle;
double m_angle;
double m_curr_r;
double m_da;
double m_dr;
bool m_start;
};
struct roundoff
{
void transform(double* x, double* y) const
{
*x = floor(*x);
*y = floor(*y);
}
};
class the_application : public agg::platform_support
{
agg::slider_ctrl<color_type> m_step;
agg::slider_ctrl<color_type> m_width;
agg::cbox_ctrl<color_type> m_test;
agg::cbox_ctrl<color_type> m_rotate;
agg::cbox_ctrl<color_type> m_accurate_joins;
agg::cbox_ctrl<color_type> m_scale_pattern;
double m_start_angle;
public:
typedef agg::renderer_base<pixfmt_pre> renderer_base;
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_aa;
typedef agg::renderer_primitives<renderer_base> renderer_prim;
typedef agg::rasterizer_outline<renderer_prim> rasterizer_outline;
typedef agg::rasterizer_scanline_aa<> rasterizer_scanline;
typedef agg::scanline_p8 scanline;
typedef agg::renderer_outline_aa<renderer_base> renderer_oaa;
typedef agg::pattern_filter_bilinear_rgba<color_type> pattern_filter;
typedef agg::line_image_pattern_pow2<pattern_filter> image_pattern;
typedef agg::renderer_outline_image<renderer_base, image_pattern> renderer_img;
typedef agg::rasterizer_outline_aa<renderer_oaa> rasterizer_outline_aa;
typedef agg::rasterizer_outline_aa<renderer_img> rasterizer_outline_img;
the_application(agg::pix_format_e format, bool flip_y) :
agg::platform_support(format, flip_y),
m_step(10.0, 10.0 + 4.0, 150.0, 10.0 + 8.0 + 4.0, !flip_y),
m_width(150.0 + 10.0, 10.0 + 4.0, 400 - 10.0, 10.0 + 8.0 + 4.0, !flip_y),
m_test(10.0, 10.0 + 4.0 + 16.0, "Test Performance", !flip_y),
m_rotate(130 + 10.0, 10.0 + 4.0 + 16.0, "Rotate", !flip_y),
m_accurate_joins(200 + 10.0, 10.0 + 4.0 + 16.0, "Accurate Joins", !flip_y),
m_scale_pattern(310 + 10.0, 10.0 + 4.0 + 16.0, "Scale Pattern", !flip_y),
m_start_angle(0.0)
{
add_ctrl(m_step);
m_step.range(0.0, 2.0);
m_step.value(0.1);
m_step.label("Step=%1.2f");
m_step.no_transform();
add_ctrl(m_width);
m_width.range(0.0, 14.0);
m_width.value(3.0);
m_width.label("Width=%1.2f");
m_width.no_transform();
add_ctrl(m_test);
m_test.text_size(9.0, 7.0);
m_test.no_transform();
add_ctrl(m_rotate);
m_rotate.text_size(9.0, 7.0);
m_rotate.no_transform();
add_ctrl(m_accurate_joins);
m_accurate_joins.text_size(9.0, 7.0);
m_accurate_joins.no_transform();
add_ctrl(m_scale_pattern);
m_scale_pattern.text_size(9.0, 7.0);
m_scale_pattern.no_transform();
m_scale_pattern.status(true);
}
void draw_aliased_pix_accuracy(rasterizer_outline& ras, renderer_prim& prim)
{
spiral s1(width()/5, height()/4+50, 5, 70, 16, m_start_angle);
roundoff rn;
agg::conv_transform<spiral, roundoff> trans(s1, rn);
prim.line_color(agg::rgba(0.4, 0.3, 0.1));
ras.add_path(trans);
}
void draw_aliased_subpix_accuracy(rasterizer_outline& ras, renderer_prim& prim)
{
spiral s2(width()/2, height()/4+50, 5, 70, 16, m_start_angle);
prim.line_color(agg::rgba(0.4, 0.3, 0.1));
ras.add_path(s2);
}
void draw_anti_aliased_outline(rasterizer_outline_aa& ras, renderer_oaa& ren)
{
spiral s3(width()/5, height() - height()/4 + 20, 5, 70, 16, m_start_angle);
ren.color(agg::rgba(0.4, 0.3, 0.1));
ras.add_path(s3);
}
void draw_anti_aliased_scanline(rasterizer_scanline& ras, scanline& sl, renderer_aa& ren)
{
spiral s4(width()/2, height() - height()/4 + 20, 5, 70, 16, m_start_angle);
agg::conv_stroke<spiral> stroke(s4);
stroke.width(m_width.value());
stroke.line_cap(agg::round_cap);
ren.color(agg::rgba(0.4, 0.3, 0.1));
ras.add_path(stroke);
agg::render_scanlines(ras, sl, ren);
}
void draw_anti_aliased_outline_img(rasterizer_outline_img& ras, renderer_img& ren)
{
spiral s5(width() - width()/5, height() - height()/4 + 20, 5, 70, 16, m_start_angle);
ras.add_path(s5);
}
void text(rasterizer_scanline& ras,
scanline& sl,
renderer_aa& ren,
double x, double y, const char* txt)
{
agg::gsv_text t;
t.size(8);
t.text(txt);
t.start_point(x, y);
agg::conv_stroke<agg::gsv_text> stroke(t);
stroke.width(0.7);
ras.add_path(stroke);
ren.color(agg::rgba(0,0,0));
agg::render_scanlines(ras, sl, ren);
}
virtual void on_draw()
{
pixfmt_pre pf(rbuf_window());
renderer_base ren_base(pf);
renderer_aa ren_aa(ren_base);
renderer_prim ren_prim(ren_base);
rasterizer_scanline ras_aa;
scanline sl;
rasterizer_outline ras_al(ren_prim);
agg::line_profile_aa prof;
prof.width(m_width.value());
renderer_oaa ren_oaa(ren_base, prof);
rasterizer_outline_aa ras_oaa(ren_oaa);
ras_oaa.line_join(m_accurate_joins.status() ?
agg::outline_miter_accurate_join :
agg::outline_round_join);
ras_oaa.round_cap(true);
pattern_filter filter;
agg::pattern_pixmap_argb32 src(pixmap_chain);
agg::line_image_scale<agg::pattern_pixmap_argb32> src_scaled(src, m_width.value());
image_pattern pattern(filter);
if(m_scale_pattern.status())
{
pattern.create(src_scaled);
}
else
{
pattern.create(src);
}
renderer_img ren_img(ren_base, pattern);
if(m_scale_pattern.status())
{
ren_img.scale_x(m_width.value() / src.height());
}
rasterizer_outline_img ras_img(ren_img);
ren_base.clear(agg::rgba(1.0, 1.0, 0.95));
draw_aliased_pix_accuracy(ras_al, ren_prim);
draw_aliased_subpix_accuracy(ras_al, ren_prim);
draw_anti_aliased_outline(ras_oaa, ren_oaa);
draw_anti_aliased_scanline(ras_aa, sl, ren_aa);
draw_anti_aliased_outline_img(ras_img, ren_img);
text(ras_aa, sl, ren_aa, 50, 80, "Bresenham lines,\n\nregular accuracy");
text(ras_aa, sl, ren_aa, width()/2-50, 80, "Bresenham lines,\n\nsubpixel accuracy");
text(ras_aa, sl, ren_aa, 50, height()/2+50, "Anti-aliased lines");
text(ras_aa, sl, ren_aa, width()/2-50, height()/2+50, "Scanline rasterizer");
text(ras_aa, sl, ren_aa, width() - width()/5 - 50, height()/2+50, "Arbitrary Image Pattern");
// The source colors of controls are "plain".
pixfmt pf2(rbuf_window());
agg::renderer_base<pixfmt> ren_base2(pf2);
agg::render_ctrl(ras_aa, sl, ren_base2, m_step);
agg::render_ctrl(ras_aa, sl, ren_base2, m_width);
agg::render_ctrl(ras_aa, sl, ren_base2, m_test);
agg::render_ctrl(ras_aa, sl, ren_base2, m_rotate);
agg::render_ctrl(ras_aa, sl, ren_base2, m_accurate_joins);
agg::render_ctrl(ras_aa, sl, ren_base2, m_scale_pattern);
/*
// An example of using anti-aliased outline rasterizer.
// Uncomment it to see the result
//
// Includes:
//#include "agg_pixfmt_rgb.h" // or another
//#include "agg_renderer_outline_aa.h"
//#include "agg_rasterizer_outline_aa.h"
typedef agg::renderer_base<agg::pixfmt_bgr24> base_ren_type;
typedef agg::renderer_outline_aa<base_ren_type> renderer_type;
typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type;
double width = 5.0;
//-- create with specifying width
//-- min_width=1.0, smoother_width=1.0
//agg::line_profile_aa(width, agg::gamma_none());
//-- create uninitialized and set parameters
agg::line_profile_aa profile;
profile.gamma(agg::gamma_power(1.2)); //optional
profile.min_width(0.75); //optional
profile.smoother_width(3.0); //optional
profile.width(width); //mandatory!
agg::pixfmt_bgr24 pixf(rbuf_window()); //or another
base_ren_type base_ren(pixf);
renderer_type ren(base_ren, profile);
ren.color(agg::srgba8(0,0,0)); //mandatory!
rasterizer_type ras(ren);
ras.round_cap(true); //optional
ras.accurate_join(true); //optional
//-- move_to/line_to interface
ras.move_to_d(100, 100);
ras.line_to_d(150, 200);
ras.render(false); //false means "don't close
//the polygon", i.e. polyline
//-- add_path interface
//-- doesn't require invoking render()
//ras.add_path(some_path);
*/
/*
// An example of using image pattern outline rasterizer
// Uncomment it to see the result
//
// Includes:
//#include "agg_pixfmt_rgb.h" // or another
//#include "agg_pattern_filters_rgba.h" // for all rgba-8-bit color formats
//#include "agg_renderer_outline_image.h"
//#include "agg_rasterizer_outline_aa.h"
agg::pattern_filter_bilinear_rgba8 fltr; // Filtering functor
agg::pattern_pixmap_argb32 patt_src(pixmap_chain); // 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.
// 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_pow2<agg::pattern_filter_bilinear_rgba8> pattern_type;
typedef agg::renderer_base<agg::pixfmt_bgr24> base_ren_type;
typedef agg::renderer_outline_image<base_ren_type, pattern_type> renderer_type;
typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type;
//-- Create with specifying the source
pattern_type patt(fltr, src);
//-- Create uninitialized and set the source
//pattern_type patt(fltr);
//patt.create(src);
agg::pixfmt_bgr24 pixf(rbuf_window()); //or another
base_ren_type base_ren(pixf);
renderer_type ren(base_ren, patt);
//ren.scale_x(1.3); // Optional
rasterizer_type ras(ren);
//-- move_to/line_to interface
ras.move_to_d(100, 150);
ras.line_to_d(0, 0);
ras.line_to_d(300, 200);
//ras.line_to_d(10, 10);
ras.render(false); //false means "don't close
//the polygon", i.e. polyline
//-- add_path interface
//-- doesn't require invoking render()
//ras.add_path(some_path);
*/
}
virtual void on_idle()
{
m_start_angle += agg::deg2rad(m_step.value());
if(m_start_angle > agg::deg2rad(360.0)) m_start_angle -= agg::deg2rad(360.0);
force_redraw();
}
virtual void on_ctrl_change()
{
wait_mode(!m_rotate.status());
if(m_test.status())
{
on_draw();
update_window();
pixfmt_pre pf(rbuf_window());
renderer_base ren_base(pf);
renderer_aa ren_aa(ren_base);
renderer_prim ren_prim(ren_base);
rasterizer_scanline ras_aa;
scanline sl;
rasterizer_outline ras_al(ren_prim);
agg::line_profile_aa prof;
prof.width(m_width.value());
renderer_oaa ren_oaa(ren_base, prof);
rasterizer_outline_aa ras_oaa(ren_oaa);
ras_oaa.line_join(m_accurate_joins.status() ?
agg::outline_miter_accurate_join :
agg::outline_round_join);
ras_oaa.round_cap(true);
pattern_filter filter;
agg::pattern_pixmap_argb32 src(pixmap_chain);
agg::line_image_scale<agg::pattern_pixmap_argb32> src_scaled(src, m_width.value());
image_pattern pattern(filter);
if(m_scale_pattern.status())
{
pattern.create(src_scaled);
}
else
{
pattern.create(src);
}
renderer_img ren_img(ren_base, pattern);
if(m_scale_pattern.status())
{
ren_img.scale_x(src.height() / m_width.value());
}
rasterizer_outline_img ras_img(ren_img);
unsigned i;
start_timer();
for(i = 0; i < 200; i++)
{
draw_aliased_subpix_accuracy(ras_al, ren_prim);
m_start_angle += agg::deg2rad(m_step.value());
}
double t2 = elapsed_time();
start_timer();
for(i = 0; i < 200; i++)
{
draw_anti_aliased_outline(ras_oaa, ren_oaa);
m_start_angle += agg::deg2rad(m_step.value());
}
double t3 = elapsed_time();
start_timer();
for(i = 0; i < 200; i++)
{
draw_anti_aliased_scanline(ras_aa, sl, ren_aa);
m_start_angle += agg::deg2rad(m_step.value());
}
double t4 = elapsed_time();
start_timer();
for(i = 0; i < 200; i++)
{
draw_anti_aliased_outline_img(ras_img, ren_img);
m_start_angle += agg::deg2rad(m_step.value());
}
double t5 = elapsed_time();
m_test.status(false);
force_redraw();
char buf[256];
sprintf(buf, "Aliased=%1.2fms, Anti-Aliased=%1.2fms, Scanline=%1.2fms, Image-Pattern=%1.2fms",
t2, t3, t4, t5);
message(buf);
}
}
};
int agg_main(int argc, char* argv[])
{
the_application app(pix_format, flip_y);
app.caption("AGG Example. Line Join");
if(app.init(500, 450, 0))
{
return app.run();
}
return 1;
}