agg/examples/compositing.cpp

375 lines
13 KiB
C++

#include <stdio.h>
#include <cassert>
#include "agg_rendering_buffer.h"
#include "agg_renderer_base.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"
#include "agg_renderer_scanline.h"
#include "agg_rounded_rect.h"
#include "agg_pixfmt_rgba.h"
#include "agg_span_allocator.h"
#include "agg_span_gradient.h"
#include "agg_gsv_text.h"
#include "agg_span_interpolator_linear.h"
#include "platform/agg_platform_support.h"
#include "ctrl/agg_slider_ctrl.h"
#include "ctrl/agg_rbox_ctrl.h"
//#define AGG_BGRA32
#define AGG_BGRA128
#include "pixel_formats.h"
enum flip_y_e { flip_y = true };
typedef color_type color;
typedef component_order order;
typedef agg::rendering_buffer rbuf_type;
typedef agg::blender_rgba<color, order> prim_blender_type;
typedef agg::pixfmt_alpha_blend_rgba<prim_blender_type, rbuf_type> prim_pixfmt_type;
typedef agg::renderer_base<prim_pixfmt_type> prim_ren_base_type;
void force_comp_op_link()
{
// For unknown reason Digital Mars C++ doesn't want to link these
// functions if they are not specified explicitly.
color_type::value_type p[4] = {0};
//agg::comp_op_rgba_invert_rgb <color, order>::blend_pix(p,0,0,0,0,0);
//agg::comp_op_rgba_invert <color, order>::blend_pix(p,0,0,0,0,0);
//agg::comp_op_rgba_contrast <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_darken <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_lighten <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_color_dodge<color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_color_burn <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_hard_light <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_soft_light <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_difference <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_exclusion <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_src_atop <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_dst_atop <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_xor <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_plus <color, order>::blend_pix(p,0,0,0,0,0);
//agg::comp_op_rgba_minus <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_multiply <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_screen <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_overlay <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_src <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_dst <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_src_over <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_dst_over <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_src_in <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_dst_in <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_src_out <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_dst_out <color, order>::blend_pix(p,0,0,0,0,0);
agg::comp_op_rgba_clear <color, order>::blend_pix(p,0,0,0,0,0);
}
agg::trans_affine gradient_affine(double x1, double y1, double x2, double y2,
double gradient_d2 = 100.0)
{
agg::trans_affine mtx;
double dx = x2 - x1;
double dy = y2 - y1;
mtx.reset();
mtx *= agg::trans_affine_scaling(sqrt(dx * dx + dy * dy) / gradient_d2);
mtx *= agg::trans_affine_rotation(atan2(dy, dx));
mtx *= agg::trans_affine_translation(x1, y1);
mtx.invert();
return mtx;
}
template<class RenBase>
void circle(RenBase& rbase, color c1, color c2,
double x1, double y1, double x2, double y2,
double shadow_alpha)
{
typedef RenBase renderer_base_type;
typedef agg::gradient_x gradient_func_type;
typedef agg::gradient_linear_color<color> color_func_type;
typedef agg::span_interpolator_linear<> interpolator_type;
typedef agg::span_allocator<color> span_allocator_type;
typedef agg::span_gradient<color,
interpolator_type,
gradient_func_type,
color_func_type> span_gradient_type;
gradient_func_type gradient_func; // The gradient function
agg::trans_affine gradient_mtx = gradient_affine(x1, y1, x2, y2, 100);
interpolator_type span_interpolator(gradient_mtx); // Span interpolator
span_allocator_type span_allocator; // Span Allocator
color_func_type color_func(c1, c2);
span_gradient_type span_gradient(span_interpolator,
gradient_func,
color_func,
0, 100);
agg::rasterizer_scanline_aa<> ras;
agg::scanline_u8 sl;
double r = agg::calc_distance(x1, y1, x2, y2) / 2;
agg::ellipse ell((x1+x2)/2+5, (y1+y2)/2-3, r, r, 100);
ras.add_path(ell);
agg::render_scanlines_aa_solid(ras, sl, rbase,
agg::rgba(0.6, 0.6, 0.6, 0.7*shadow_alpha));
ell.init((x1+x2)/2, (y1+y2)/2, r, r, 100);
ras.add_path(ell);
agg::render_scanlines_aa(ras, sl, rbase, span_allocator, span_gradient);
}
template<class RenBase>
void src_shape(RenBase& rbase, color c1, color c2,
double x1, double y1, double x2, double y2)
{
typedef RenBase renderer_base_type;
typedef agg::gradient_x gradient_func_type;
typedef agg::gradient_linear_color<color> color_func_type;
typedef agg::span_interpolator_linear<> interpolator_type;
typedef agg::span_allocator<color> span_allocator_type;
typedef agg::span_gradient<color,
interpolator_type,
gradient_func_type,
color_func_type> span_gradient_type;
gradient_func_type gradient_func; // The gradient function
agg::trans_affine gradient_mtx = gradient_affine(x1, y1, x2, y2, 100);
interpolator_type span_interpolator(gradient_mtx); // Span interpolator
span_allocator_type span_allocator; // Span Allocator
color_func_type color_func(c1, c2);
span_gradient_type span_gradient(span_interpolator,
gradient_func,
color_func,
0, 100);
agg::rasterizer_scanline_aa<> ras;
agg::scanline_u8 sl;
agg::rounded_rect shape(x1, y1, x2, y2, 40);
// agg::ellipse shape((x1+x2)/2, (y1+y2)/2, fabs(x2-x1)/2, fabs(y2-y1)/2, 100);
ras.add_path(shape);
agg::render_scanlines_aa(ras, sl, rbase, span_allocator, span_gradient);
}
class the_application : public agg::platform_support
{
agg::slider_ctrl<color> m_alpha_src;
agg::slider_ctrl<color> m_alpha_dst;
agg::rbox_ctrl<color_type> m_comp_op;
public:
the_application(agg::pix_format_e format, bool flip_y) :
agg::platform_support(format, flip_y),
m_alpha_src(5, 5, 400, 11, !flip_y),
m_alpha_dst(5, 5+15, 400, 11+15, !flip_y),
m_comp_op(420, 5.0, 420+170.0, 340.0, !flip_y)
{
m_alpha_src.label("Src Alpha=%.2f");
m_alpha_src.value(0.75);
add_ctrl(m_alpha_src);
m_alpha_dst.label("Dst Alpha=%.2f");
m_alpha_dst.value(1.0);
add_ctrl(m_alpha_dst);
m_comp_op.text_size(6.8);
m_comp_op.add_item("clear");
m_comp_op.add_item("src");
m_comp_op.add_item("dst");
m_comp_op.add_item("src-over");
m_comp_op.add_item("dst-over");
m_comp_op.add_item("src-in");
m_comp_op.add_item("dst-in");
m_comp_op.add_item("src-out");
m_comp_op.add_item("dst-out");
m_comp_op.add_item("src-atop");
m_comp_op.add_item("dst-atop");
m_comp_op.add_item("xor");
m_comp_op.add_item("plus");
//m_comp_op.add_item("minus");
m_comp_op.add_item("multiply");
m_comp_op.add_item("screen");
m_comp_op.add_item("overlay");
m_comp_op.add_item("darken");
m_comp_op.add_item("lighten");
m_comp_op.add_item("color-dodge");
m_comp_op.add_item("color-burn");
m_comp_op.add_item("hard-light");
m_comp_op.add_item("soft-light");
m_comp_op.add_item("difference");
m_comp_op.add_item("exclusion");
//m_comp_op.add_item("contrast");
//m_comp_op.add_item("invert");
//m_comp_op.add_item("invert-rgb");
m_comp_op.cur_item(3);
add_ctrl(m_comp_op);
}
virtual ~the_application()
{
}
virtual void on_init()
{
}
void render_scene(rbuf_type& rbuf, prim_pixfmt_type& pixf)
{
typedef agg::comp_op_adaptor_rgba<color, order> blender_type;
typedef agg::pixfmt_custom_blend_rgba<blender_type, rbuf_type> pixfmt_type;
typedef agg::renderer_base<pixfmt_type> renderer_type;
pixfmt_type ren_pixf(rbuf);
renderer_type renderer(ren_pixf);
agg::renderer_base<prim_pixfmt_type> rb(pixf);
rb.blend_from(prim_pixfmt_type(rbuf_img(1)),
0, 250, 180,
agg::cover_type(m_alpha_dst.value() * agg::cover_full));
circle(rb,
agg::srgba8(0xFD, 0xF0, 0x6F, unsigned(m_alpha_dst.value() * 255)),
agg::srgba8(0xFE, 0x9F, 0x34, unsigned(m_alpha_dst.value() * 255)),
70*3, 100+24*3, 37*3, 100+79*3,
m_alpha_dst.value());
ren_pixf.comp_op(m_comp_op.cur_item());
src_shape(renderer,
agg::srgba8(0x7F, 0xC1, 0xFF, unsigned(m_alpha_src.value() * 255)),
agg::srgba8(0x05, 0x00, 0x5F, unsigned(m_alpha_src.value() * 255)),
300+50, 100+24*3, 107+50, 100+79*3);
/*
src_shape(renderer,
agg::srgba8(0xFF, 0xFF, 0xFF, unsigned(m_alpha_src.value() * 255)),
agg::srgba8(0xFF, 0xFF, 0xFF, unsigned(m_alpha_src.value() * 255)),
300+50, 100+24*3, 107+50, 100+79*3);
*/
}
virtual void on_draw()
{
prim_pixfmt_type pixf(rbuf_window());
prim_ren_base_type rb(pixf);
rb.clear(agg::srgba8(255, 255, 255));
unsigned y;
for(y = 0; y < rb.height(); y += 8)
{
unsigned x;
for(x = ((y >> 3) & 1) << 3; x < rb.width(); x += 16)
{
rb.copy_bar(x, y, x+7, y+7, agg::srgba8(0xdf, 0xdf, 0xdf));
}
}
create_img(0, rbuf_window().width(), rbuf_window().height()); // agg_platform_support functionality
prim_pixfmt_type pixf2(rbuf_img(0));
prim_ren_base_type rb2(pixf2);
rb2.clear(agg::srgba8(0,0,0,0));
//rb2.clear(agg::srgba8(255,255,255,255));
typedef agg::blender_rgba_pre<color, order> blender_type_pre;
typedef agg::pixfmt_alpha_blend_rgba<blender_type_pre, rbuf_type> pixfmt_pre;
typedef agg::renderer_base<pixfmt_pre> ren_base_pre;
pixfmt_pre pixf_pre(rbuf_window());
ren_base_pre rb_pre(pixf_pre);
start_timer();
render_scene(rbuf_img(0), pixf2);
double tm = elapsed_time();
rb_pre.blend_from(pixf2);
agg::rasterizer_scanline_aa<> ras;
agg::scanline_u8 sl;
agg::renderer_scanline_aa_solid<prim_ren_base_type> ren(rb);
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, 35.0);
t.text(buf);
ras.add_path(pt);
ren.color(agg::rgba(0,0,0));
agg::render_scanlines(ras, sl, ren);
agg::render_ctrl_rs(ras, sl, ren, m_alpha_src);
agg::render_ctrl_rs(ras, sl, ren, m_alpha_dst);
agg::render_ctrl_rs(ras, sl, ren, m_comp_op);
}
virtual void on_mouse_button_down(int x, int y, unsigned flags)
{
}
virtual void on_mouse_move(int x, int y, unsigned flags)
{
}
virtual void on_mouse_button_up(int x, int y, unsigned flags)
{
}
};
int agg_main(int argc, char* argv[])
{
force_comp_op_link();
the_application app(pix_format, flip_y);
app.caption("AGG Example. Compositing Modes");
const char* img_name = "compositing";
if(argc >= 2) img_name = argv[1];
if(!app.load_img(1, img_name))
{
char buf[256];
if(strcmp(img_name, "compositing") == 0)
{
sprintf(buf, "File not found: %s%s. Download http://www.antigrain.com/%s%s\n"
"or copy it from the ../art directory.",
img_name, app.img_ext(), img_name, app.img_ext());
}
else
{
sprintf(buf, "File not found: %s%s", img_name, app.img_ext());
}
app.message(buf);
return 1;
}
if(app.init(600, 400, agg::window_resize))
{
return app.run();
}
return 1;
}