#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"
#include "agg_renderer_scanline.h"
#include "agg_path_storage.h"
#include "agg_conv_transform.h"
#include "agg_trans_bilinear.h"
#include "agg_trans_perspective.h"
#include "agg_span_interpolator_trans.h"
#include "agg_span_interpolator_linear.h"
#include "agg_pixfmt_rgb24.h"
#include "agg_span_image_filter_rgb24.h"
#include "ctrl/agg_rbox_ctrl.h"
#include "platform/agg_platform_support.h"
#include "interactive_polygon.h"
enum { flip_y = true };
agg::rasterizer_scanline_aa<> g_rasterizer;
agg::scanline_u8 g_scanline;
double g_x1 = 0;
double g_y1 = 0;
double g_x2 = 0;
double g_y2 = 0;
class the_application : public agg::platform_support
{
public:
typedef agg::pixfmt_bgr24 pixfmt;
typedef agg::renderer_base<pixfmt> renderer_base;
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid;
agg::interactive_polygon m_triangle;
the_application(agg::pix_format_e format, bool flip_y) :
agg::platform_support(format, flip_y),
m_triangle(4, 5.0)
{
}
virtual void on_init()
{
g_x1 = 0.0;
g_y1 = 0.0;
g_x2 = rbuf_img(0).width();
g_y2 = rbuf_img(0).height();
double dx = width() / 2.0 - (g_x2 - g_x1) / 2.0;
double dy = height() / 2.0 - (g_y2 - g_y1) / 2.0;
m_triangle.xn(0) = g_x1 + dx;
m_triangle.yn(0) = g_y1 + dy;
m_triangle.xn(1) = g_x2 + dx;
m_triangle.yn(1) = g_y1 + dy;
m_triangle.xn(2) = g_x2 + dx;
m_triangle.yn(2) = g_y2 + dy;
m_triangle.xn(3) = g_x1 + dx;
m_triangle.yn(3) = g_y2 + dy;
}
virtual void on_draw()
{
// Calculate the 4-th point of the parallelogram
m_triangle.xn(3) = m_triangle.xn(0) +
(m_triangle.xn(2) - m_triangle.xn(1));
m_triangle.yn(3) = m_triangle.yn(0) +
(m_triangle.yn(2) - m_triangle.yn(1));
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());
typedef agg::span_allocator<agg::rgba8> span_alloc_type;
span_alloc_type sa;
agg::trans_perspective tr(m_triangle.polygon(),
g_x1, g_y1, g_x2, g_y2);
if(tr.is_valid())
{
//=================== The trick with interpolator.
// ------- Slow variant
// span_interpolator_trans is a general purpose interpolator.
// It calls the Transformer::transform() for each point of the
// scanline, thus, it's slow. But it can be used with any
// kind of transformations, linear or non-linear.
//----------------------------
//typedef agg::span_interpolator_trans<agg::trans_perspective>
// interpolator_type;
// ------- Fast variant
// span_interpolator_linear is an accelerated version of the general
// purpose one, span_interpolator_trans. It calculates
// actual coordinates only for the beginning and the ending points
// of the span. But the transformations must be linear and parallel,
// that is, any straight line must remain straight after applying the
// transformation, and any two parallel lines must remain parallel.
// It's not sutable for perspective transformations in general
// (they are not parallel), but quite OK for this particular case,
// i.e., parallelogram transformations.
//----------------------------
typedef agg::span_interpolator_linear<agg::trans_perspective>
interpolator_type;
//===================
interpolator_type interpolator(tr);
// "hardcoded" bilinear filter
//------------------------------------------
typedef agg::span_image_filter_rgb24_bilinear<agg::order_bgr24,
interpolator_type>
span_gen_type;
typedef agg::renderer_scanline_aa<renderer_base, span_gen_type>
renderer_type;
span_gen_type sg(sa,
rbuf_img(0),
agg::rgba(1, 1, 1, 0),
interpolator);
renderer_type ri(rb, sg);
g_rasterizer.reset();
g_rasterizer.move_to_d(m_triangle.xn(0), m_triangle.yn(0));
g_rasterizer.line_to_d(m_triangle.xn(1), m_triangle.yn(1));
g_rasterizer.line_to_d(m_triangle.xn(2), m_triangle.yn(2));
g_rasterizer.line_to_d(m_triangle.xn(3), m_triangle.yn(3));
agg::render_scanlines(g_rasterizer, g_scanline, ri);
}
//--------------------------
// Render the "quad" tool and controls
g_rasterizer.add_path(m_triangle);
r.color(agg::rgba(0, 0.3, 0.5, 0.6));
agg::render_scanlines(g_rasterizer, g_scanline, r);
//--------------------------
}
virtual void on_mouse_button_down(int x, int y, unsigned flags)
{
if(flags & agg::mouse_left)
{
if(m_triangle.on_mouse_button_down(x, y))
{
force_redraw();
}
}
}
virtual void on_mouse_move(int x, int y, unsigned flags)
{
if(flags & agg::mouse_left)
{
if(m_triangle.on_mouse_move(x, y))
{
force_redraw();
}
}
if((flags & agg::mouse_left) == 0)
{
on_mouse_button_up(x, y, flags);
}
}
virtual void on_mouse_button_up(int x, int y, unsigned flags)
{
if(m_triangle.on_mouse_button_up(x, y))
{
force_redraw();
}
}
};
int agg_main(int argc, char* argv[])
{
the_application app(agg::pix_format_bgr24, flip_y);
app.caption("AGG Example. Image Perspective Transformations");
const char* img_name = "spheres";
if(argc >= 2) img_name = argv[1];
if(!app.load_img(0, img_name))
{
char buf[256];
if(strcmp(img_name, "spheres") == 0)
{
sprintf(buf, "File not found: %s%s. Download http://www.antigrain.com/%s%s\n"
"or copy it from another directory if available.",
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, 600, agg::window_resize))
{
return app.run();
}
return 1;
}
|