|
|
538bb7 |
#include <iostream></iostream>
|
|
|
538bb7 |
|
|
|
538bb7 |
#include <gdkmm pixbuf.h=""></gdkmm>
|
|
|
538bb7 |
#include <gtkmm hvbox.h=""></gtkmm>
|
|
|
538bb7 |
#include <gtkmm image.h=""></gtkmm>
|
|
|
538bb7 |
|
|
|
3a6f9b |
#include "log.h"
|
|
|
3a6f9b |
#include "perspective.h"
|
|
|
4dc49c |
|
|
|
3a6f9b |
#include "mainwindow.h"
|
|
|
4dc49c |
|
|
|
4dc49c |
|
|
|
d08c86 |
const bool checks = false;
|
|
|
d08c86 |
const bool checks_on_generator = true;
|
|
|
43cb04 |
const bool paint_outside_bounds = true;
|
|
|
57974f |
|
|
|
57974f |
|
|
|
538bb7 |
MainWindow::MainWindow():
|
|
|
4dc49c |
src_rect_p0 (new View::Point( Vector2(-1, -1) )),
|
|
|
4dc49c |
src_rect_p1 (new View::Point( Vector2( 1, 1) )),
|
|
|
4dc49c |
dst_rect_p0 (new View::Point( Vector2(-1, -1) )),
|
|
|
4dc49c |
dst_rect_px (new View::Point( Vector2( 1, -1) )),
|
|
|
4dc49c |
dst_rect_py (new View::Point( Vector2(-1, 1) )),
|
|
|
4dc49c |
dst_rect_p1 (new View::Point( Vector2( 1, 1) )),
|
|
|
4dc49c |
dst_bounds_p0 (new View::Point( Vector2(-2, -2) )),
|
|
|
4dc49c |
dst_bounds_p1 (new View::Point( Vector2( 2, 2) ))
|
|
|
538bb7 |
{
|
|
|
a1942e |
std::cout << "generator seed: " << generator.seed() << std::endl;
|
|
|
a1942e |
set_default_size(750, 500);
|
|
|
538bb7 |
|
|
|
538bb7 |
Gtk::HBox *hbox = manage(new Gtk::HBox());
|
|
|
538bb7 |
hbox->set_homogeneous(true);
|
|
|
538bb7 |
|
|
|
a1942e |
src_view.transform.scale(50, 50);
|
|
|
4dc49c |
src_view.points.push_back(src_rect_p0);
|
|
|
4dc49c |
src_view.points.push_back(src_rect_p1);
|
|
|
538bb7 |
src_view.signal_point_motion.connect(
|
|
|
538bb7 |
sigc::mem_fun(*this, &MainWindow::on_point_motion) );
|
|
|
538bb7 |
src_view.signal_point_changed.connect(
|
|
|
538bb7 |
sigc::mem_fun(*this, &MainWindow::on_point_changed) );
|
|
|
a1942e |
src_view.signal_transform_changed.connect(
|
|
|
a1942e |
sigc::bind(
|
|
|
a1942e |
sigc::mem_fun(*this, &MainWindow::on_view_transform_changed),
|
|
|
a1942e |
&src_view ));
|
|
|
538bb7 |
src_view.signal_draw_view.connect(
|
|
|
538bb7 |
sigc::mem_fun(*this, &MainWindow::on_draw_src_view) );
|
|
|
538bb7 |
hbox->add(src_view);
|
|
|
538bb7 |
|
|
|
a1942e |
dst_view.transform.scale(50, 50);
|
|
|
4dc49c |
dst_view.points.push_back(dst_rect_p0);
|
|
|
4dc49c |
dst_view.points.push_back(dst_rect_px);
|
|
|
4dc49c |
dst_view.points.push_back(dst_rect_py);
|
|
|
4dc49c |
dst_view.points.push_back(dst_rect_p1);
|
|
|
4dc49c |
dst_view.points.push_back(dst_bounds_p0);
|
|
|
4dc49c |
dst_view.points.push_back(dst_bounds_p1);
|
|
|
538bb7 |
dst_view.signal_point_motion.connect(
|
|
|
538bb7 |
sigc::mem_fun(*this, &MainWindow::on_point_motion) );
|
|
|
538bb7 |
dst_view.signal_point_changed.connect(
|
|
|
538bb7 |
sigc::mem_fun(*this, &MainWindow::on_point_changed) );
|
|
|
a1942e |
src_view.signal_transform_changed.connect(
|
|
|
a1942e |
sigc::bind(
|
|
|
a1942e |
sigc::mem_fun(*this, &MainWindow::on_view_transform_changed),
|
|
|
a1942e |
&dst_view ));
|
|
|
538bb7 |
dst_view.signal_draw_view.connect(
|
|
|
538bb7 |
sigc::mem_fun(*this, &MainWindow::on_draw_dst_view) );
|
|
|
538bb7 |
hbox->add(dst_view);
|
|
|
538bb7 |
|
|
|
a1942e |
//hbox->add(*manage(generator_demo()));
|
|
|
538bb7 |
|
|
|
538bb7 |
add(*hbox);
|
|
|
538bb7 |
show_all();
|
|
|
a1942e |
|
|
|
3a6f9b |
update_src_surface();
|
|
|
3a6f9b |
update_dst_surface();
|
|
|
538bb7 |
}
|
|
|
538bb7 |
|
|
|
538bb7 |
Gtk::Widget*
|
|
|
538bb7 |
MainWindow::generator_demo() {
|
|
|
538bb7 |
std::cout << "generator demo: generate" << std::endl;
|
|
|
538bb7 |
DataSurface surface(256, 256);
|
|
|
4dc49c |
generator.generate(surface, Pair2(Vector2(0, 0), Vector2(16, 16)));
|
|
|
538bb7 |
|
|
|
538bb7 |
std::cout << "generator demo: convert" << std::endl;
|
|
|
538bb7 |
Glib::RefPtr<gdk::pixbuf> pixbuf = Gdk::Pixbuf::create(</gdk::pixbuf>
|
|
|
538bb7 |
Gdk::COLORSPACE_RGB, true, 8, surface.width(), surface.height() );
|
|
|
538bb7 |
guint8 *pixel = pixbuf->get_pixels();
|
|
|
538bb7 |
for(int r = 0; r < surface.height(); ++r) {
|
|
|
538bb7 |
Color *row = surface[r];
|
|
|
538bb7 |
for(int c = 0; c < surface.width(); ++c) {
|
|
|
538bb7 |
const Color &color = row[c];
|
|
|
538bb7 |
*(pixel++) = (guint8)(color.r*255.9);
|
|
|
538bb7 |
*(pixel++) = (guint8)(color.g*255.9);
|
|
|
538bb7 |
*(pixel++) = (guint8)(color.b*255.9);
|
|
|
538bb7 |
*(pixel++) = (guint8)(color.a*255.9);
|
|
|
538bb7 |
}
|
|
|
538bb7 |
}
|
|
|
538bb7 |
|
|
|
538bb7 |
return new Gtk::Image(pixbuf);
|
|
|
538bb7 |
}
|
|
|
538bb7 |
|
|
|
538bb7 |
void
|
|
|
3a6f9b |
MainWindow::update_src_surface() {
|
|
|
3a6f9b |
std::cout << "update_src_surface() - begin" << std::endl;
|
|
|
3a6f9b |
|
|
|
5f2fc2 |
Matrix4 transform = src_view.transform_from_pixels();
|
|
|
a1942e |
int w = src_view.get_width();
|
|
|
a1942e |
int h = src_view.get_height();
|
|
|
a1942e |
|
|
|
4dc49c |
Pair2 rect(
|
|
|
4dc49c |
(transform * Vector4(0, 0, 0, 1)).vec2(),
|
|
|
4dc49c |
(transform * Vector4(w, h, 0, 1)).vec2() );
|
|
|
a1942e |
|
|
|
a1942e |
if (w <= 0 || h <= 0) {
|
|
|
3a6f9b |
src_surface.clear();
|
|
|
3a6f9b |
} else {
|
|
|
a1942e |
DataSurface surface(w, h);
|
|
|
57974f |
if (checks) generator.generate_checks(surface, rect);
|
|
|
d08c86 |
else generator.generate(surface, rect, checks_on_generator);
|
|
|
3a6f9b |
src_surface = surface.to_cairo_surface();
|
|
|
4dc49c |
}
|
|
|
3a6f9b |
|
|
|
3a6f9b |
std::cout << "update_src_surface() - end" << std::endl;
|
|
|
4dc49c |
}
|
|
|
4dc49c |
|
|
|
4dc49c |
void
|
|
|
3a6f9b |
MainWindow::update_dst_surface() {
|
|
|
3a6f9b |
std::cout << "update_dst_surface() - begin" << std::endl;
|
|
|
3a6f9b |
|
|
|
3a6f9b |
dst_surface.clear();
|
|
|
00b5ca |
|
|
|
00b5ca |
// full dst_bounds
|
|
|
00b5ca |
const IntPair2 full_dst_bounds_pixels(
|
|
|
00b5ca |
IntVector2(0, 0),
|
|
|
00b5ca |
IntVector2(src_view.get_width(), src_view.get_height()) );
|
|
|
00b5ca |
|
|
|
3a6f9b |
// src matrix
|
|
|
3a6f9b |
const Pair2 src_bounds(
|
|
|
4dc49c |
src_rect_p0->position,
|
|
|
3a6f9b |
src_rect_p1->position );
|
|
|
3a6f9b |
const Vector2 src_dist = src_bounds.distance();
|
|
|
3a6f9b |
if (fabs(src_dist.x) < real_precision || fabs(src_dist.y) < real_precision)
|
|
|
3a6f9b |
return;
|
|
|
3a6f9b |
|
|
|
3a6f9b |
Real kx = 1/src_dist.x;
|
|
|
5f2fc2 |
Real ky = 1/src_dist.y;
|
|
|
3a6f9b |
Real x0 = -src_bounds.p0.x*kx;
|
|
|
5f2fc2 |
Real y0 = -src_bounds.p0.y*ky;
|
|
|
3a6f9b |
Matrix3 src_matrix(
|
|
|
3a6f9b |
Vector3(kx, 0, 0),
|
|
|
3a6f9b |
Vector3( 0, ky, 0),
|
|
|
5f2fc2 |
Vector3(x0, y0, 1) );
|
|
|
3a6f9b |
|
|
|
3a6f9b |
// dst matrix
|
|
|
3a6f9b |
const Matrix dst_transform = dst_view.transform_to_pixels();
|
|
|
3a6f9b |
const Vector2 dst_rect_p0_pixels(dst_transform * Vector4(dst_rect_p0->position, 0.0, 1.0));
|
|
|
3a6f9b |
const Vector2 dst_rect_px_pixels(dst_transform * Vector4(dst_rect_px->position, 0.0, 1.0));
|
|
|
3a6f9b |
const Vector2 dst_rect_py_pixels(dst_transform * Vector4(dst_rect_py->position, 0.0, 1.0));
|
|
|
3a6f9b |
const Vector2 dst_rect_p1_pixels(dst_transform * Vector4(dst_rect_p1->position, 0.0, 1.0));
|
|
|
3a6f9b |
Matrix3 dst_matrix = Perspective::make_matrix(
|
|
|
4dc49c |
dst_rect_p0_pixels,
|
|
|
4dc49c |
dst_rect_px_pixels,
|
|
|
4dc49c |
dst_rect_py_pixels,
|
|
|
4dc49c |
dst_rect_p1_pixels );
|
|
|
4dc49c |
|
|
|
3a6f9b |
// final perspective matrix
|
|
|
3a6f9b |
Matrix3 matrix = dst_matrix * src_matrix;
|
|
|
3a6f9b |
|
|
|
3a6f9b |
// dst bounds
|
|
|
3a6f9b |
const Pair2 dst_bounds_pixels_float(
|
|
|
3a6f9b |
(dst_transform * Vector4(dst_bounds_p0->position, 0.0, 1.0)).vec2(),
|
|
|
3a6f9b |
(dst_transform * Vector4(dst_bounds_p1->position, 0.0, 1.0)).vec2() );
|
|
|
3a6f9b |
const IntPair2 dst_bounds_pixels(
|
|
|
3a6f9b |
IntVector2( (int)floor(dst_bounds_pixels_float.p0.x + real_precision),
|
|
|
3a6f9b |
(int)floor(dst_bounds_pixels_float.p0.y + real_precision) ),
|
|
|
3a6f9b |
IntVector2( (int)ceil (dst_bounds_pixels_float.p1.x - real_precision),
|
|
|
3a6f9b |
(int)ceil (dst_bounds_pixels_float.p1.y - real_precision) ));
|
|
|
3a6f9b |
if (dst_bounds_pixels.empty())
|
|
|
3a6f9b |
return;
|
|
|
4dc49c |
|
|
|
3a6f9b |
std::cout << Log::tab() << "dst_bounds_pixels: " << Log::to_string(dst_bounds_pixels) << std::endl;
|
|
|
3a6f9b |
std::cout << Log::tab() << "matrix:" << std::endl
|
|
|
3a6f9b |
<< Log::to_string(matrix, 10, Log::tab(2));
|
|
|
3a6f9b |
|
|
|
3a6f9b |
// make layers
|
|
|
3a6f9b |
Perspective::LayerList layers;
|
|
|
3a6f9b |
Perspective::create_layers(
|
|
|
3a6f9b |
layers,
|
|
|
3a6f9b |
matrix,
|
|
|
5f2fc2 |
dst_bounds_pixels,
|
|
|
5f2fc2 |
2.0 );
|
|
|
4dc49c |
|
|
|
3a6f9b |
std::cout << Log::tab() << "created layers:" << std::endl;
|
|
|
3a6f9b |
Perspective::print_layers(layers, Log::tab(2));
|
|
|
3a6f9b |
std::cout << Log::tab() << "---------------" << std::endl;
|
|
|
57974f |
|
|
|
43cb04 |
//std::cout << Log::tab() << "optimal step: "
|
|
|
43cb04 |
// << Perspective::find_optimal_step(matrix, dst_bounds_pixels) << std::endl;
|
|
|
4dc49c |
|
|
|
00b5ca |
// override dst_bounds
|
|
|
57974f |
if (paint_outside_bounds)
|
|
|
57974f |
for(Perspective::LayerList::iterator i = layers.begin(); i != layers.end(); ++i)
|
|
|
57974f |
i->dst_bounds = full_dst_bounds_pixels;
|
|
|
00b5ca |
|
|
|
3a6f9b |
// make surface
|
|
|
00b5ca |
DataSurface surface(full_dst_bounds_pixels.p1.x, full_dst_bounds_pixels.p1.y);
|
|
|
3a6f9b |
for(Perspective::LayerList::const_iterator i = layers.begin(); i != layers.end(); ++i) {
|
|
|
3a6f9b |
DataSurface layer_surface(i->src_size.x, i->src_size.y);
|
|
|
57974f |
if (checks) generator.generate_checks(layer_surface, i->src_bounds);
|
|
|
d08c86 |
else generator.generate(layer_surface, i->src_bounds, checks_on_generator);
|
|
|
3a6f9b |
layer_surface.mult_alpha();
|
|
|
3a6f9b |
Perspective::add_premulted(*i, layer_surface, surface);
|
|
|
a1942e |
}
|
|
|
43cb04 |
for(Perspective::LayerList::const_iterator i = layers.begin(); i != layers.end(); ++i)
|
|
|
43cb04 |
Perspective::paint_cross(surface, i->center);
|
|
|
3a6f9b |
dst_surface = surface.to_cairo_surface(true);
|
|
|
3a6f9b |
|
|
|
3a6f9b |
std::cout << "update_dst_surface() - end" << std::endl;
|
|
|
a1942e |
}
|
|
|
a1942e |
|
|
|
a1942e |
void
|
|
|
538bb7 |
MainWindow::on_point_motion(const View::PointPtr &/*point*/) {
|
|
|
538bb7 |
queue_draw();
|
|
|
538bb7 |
}
|
|
|
538bb7 |
|
|
|
538bb7 |
void
|
|
|
538bb7 |
MainWindow::on_point_changed(const View::PointPtr &/*point*/) {
|
|
|
3a6f9b |
update_dst_surface();
|
|
|
538bb7 |
}
|
|
|
538bb7 |
|
|
|
538bb7 |
void
|
|
|
a1942e |
MainWindow::on_view_transform_changed(View *view) {
|
|
|
a1942e |
if (view == &src_view) {
|
|
|
3a6f9b |
update_src_surface();
|
|
|
a1942e |
view->queue_draw();
|
|
|
a1942e |
}
|
|
|
a1942e |
}
|
|
|
a1942e |
|
|
|
a1942e |
void
|
|
|
538bb7 |
MainWindow::on_draw_src_view(const Cairo::RefPtr<cairo::context> &context) {</cairo::context>
|
|
|
538bb7 |
const Real ps = src_view.get_pixel_size();
|
|
|
538bb7 |
|
|
|
538bb7 |
context->save();
|
|
|
a1942e |
|
|
|
3a6f9b |
if ( !src_surface
|
|
|
3a6f9b |
|| src_view.get_width() != src_surface->get_width()
|
|
|
3a6f9b |
|| src_view.get_height() != src_surface->get_height() )
|
|
|
3a6f9b |
update_src_surface();
|
|
|
3a6f9b |
if (src_surface) {
|
|
|
a1942e |
context->save();
|
|
|
4dc49c |
context->transform( src_view.transform_from_pixels().to_cairo() );
|
|
|
3a6f9b |
context->set_source(src_surface, 0, 0);
|
|
|
a1942e |
context->paint();
|
|
|
a1942e |
context->restore();
|
|
|
a1942e |
}
|
|
|
538bb7 |
|
|
|
4dc49c |
context->move_to(src_rect_p0->position.x, src_rect_p0->position.y);
|
|
|
4dc49c |
context->line_to(src_rect_p0->position.x, src_rect_p1->position.y);
|
|
|
4dc49c |
context->line_to(src_rect_p1->position.x, src_rect_p1->position.y);
|
|
|
4dc49c |
context->line_to(src_rect_p1->position.x, src_rect_p0->position.y);
|
|
|
538bb7 |
context->close_path();
|
|
|
538bb7 |
context->set_line_width(ps);
|
|
|
538bb7 |
context->set_source_rgba(1, 1, 0, 0.5);
|
|
|
538bb7 |
context->stroke();
|
|
|
538bb7 |
|
|
|
538bb7 |
context->restore();
|
|
|
538bb7 |
}
|
|
|
538bb7 |
|
|
|
538bb7 |
void
|
|
|
538bb7 |
MainWindow::on_draw_dst_view(const Cairo::RefPtr<cairo::context> &context) {</cairo::context>
|
|
|
5f2fc2 |
const Real ps = dst_view.get_pixel_size();
|
|
|
538bb7 |
|
|
|
538bb7 |
context->save();
|
|
|
3a6f9b |
if (dst_surface) {
|
|
|
4dc49c |
context->save();
|
|
|
3a6f9b |
context->transform( dst_view.transform_from_pixels().to_cairo() );
|
|
|
3a6f9b |
context->set_source(dst_surface, 0, 0);
|
|
|
4dc49c |
context->paint();
|
|
|
4dc49c |
context->restore();
|
|
|
4dc49c |
}
|
|
|
538bb7 |
|
|
|
4dc49c |
context->move_to(dst_rect_p0->position.x, dst_rect_p0->position.y);
|
|
|
4dc49c |
context->line_to(dst_rect_px->position.x, dst_rect_px->position.y);
|
|
|
4dc49c |
context->line_to(dst_rect_p1->position.x, dst_rect_p1->position.y);
|
|
|
4dc49c |
context->line_to(dst_rect_py->position.x, dst_rect_py->position.y);
|
|
|
538bb7 |
context->close_path();
|
|
|
538bb7 |
context->set_line_width(ps);
|
|
|
538bb7 |
context->set_source_rgba(1, 1, 0, 0.5);
|
|
|
538bb7 |
context->stroke();
|
|
|
538bb7 |
|
|
|
4dc49c |
context->move_to(dst_bounds_p0->position.x, dst_bounds_p0->position.y);
|
|
|
4dc49c |
context->line_to(dst_bounds_p0->position.x, dst_bounds_p1->position.y);
|
|
|
4dc49c |
context->line_to(dst_bounds_p1->position.x, dst_bounds_p1->position.y);
|
|
|
4dc49c |
context->line_to(dst_bounds_p1->position.x, dst_bounds_p0->position.y);
|
|
|
538bb7 |
context->close_path();
|
|
|
538bb7 |
context->set_line_width(ps);
|
|
|
538bb7 |
context->set_source_rgba(1, 0, 0, 0.5);
|
|
|
538bb7 |
context->stroke();
|
|
|
538bb7 |
|
|
|
538bb7 |
context->restore();
|
|
|
538bb7 |
}
|