From 538bb7b470ed2b21c3163e88c7976a8ccf62d938 Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Jan 17 2019 15:36:09 +0000 Subject: perspective: main window --- diff --git a/c++/perspective/src/SConstruct b/c++/perspective/src/SConstruct index 5951876..d1acec6 100644 --- a/c++/perspective/src/SConstruct +++ b/c++/perspective/src/SConstruct @@ -19,6 +19,7 @@ target = 'perspective' sources = [ 'generator.cpp', 'main.cpp', + 'mainwindow.cpp', 'matrix.cpp', 'surface.cpp', 'view.cpp' ] diff --git a/c++/perspective/src/common.h b/c++/perspective/src/common.h index b4c1580..6a6aff2 100644 --- a/c++/perspective/src/common.h +++ b/c++/perspective/src/common.h @@ -65,6 +65,6 @@ inline int clz(const ULongInt &x) inline Real flip_clamp(Real x) { x -= floor(0.5*x)*2.0; return 1.0 - fabs(1.0 - x); -} +}; #endif diff --git a/c++/perspective/src/main.cpp b/c++/perspective/src/main.cpp index 88102e2..29db451 100644 --- a/c++/perspective/src/main.cpp +++ b/c++/perspective/src/main.cpp @@ -1,64 +1,22 @@ #include -#include -#include +#include -#include "view.h" -#include "surface.h" -#include "generator.h" +#include "mainwindow.h" int main(int argc, char **argv) { std::cout << "Lab: prototype of perspective transformation" << std::endl; + Glib::RefPtr application = Gtk::Application::create( argc, argv, "org.morevnaproject.lab.perspective"); - - std::cout << "generate" << std::endl; - Generator generator; - DataSurface surface(256, 256); - generator.generate(surface, Vector2(0, 0), Vector2(16, 16)); - - std::cout << "convert" << std::endl; - Glib::RefPtr pixbuf = Gdk::Pixbuf::create( - Gdk::COLORSPACE_RGB, true, 8, surface.width(), surface.height() ); - guint8 *pixel = pixbuf->get_pixels(); - for(int r = 0; r < surface.height(); ++r) { - Color *row = surface[r]; - for(int c = 0; c < surface.width(); ++c) { - const Color &color = row[c]; - *(pixel++) = (guint8)(color.r*255.9); - *(pixel++) = (guint8)(color.g*255.9); - *(pixel++) = (guint8)(color.b*255.9); - *(pixel++) = (guint8)(color.a*255.9); - } - } std::cout << "create window" << std::endl; - Gtk::Window window; - window.set_default_size(200, 200); - Gtk::HBox hbox; - hbox.set_homogeneous(true); - - View a; - a.own_points.push_back( View::PointPtr( new View::Point() ) ); - a.own_points.push_back( View::PointPtr( new View::Point() ) ); - a.own_points.push_back( View::PointPtr( new View::Point() ) ); - hbox.add(a); - - View b; - b.own_points.push_back( View::PointPtr( new View::Point() ) ); - b.own_points.push_back( View::PointPtr( new View::Point() ) ); - b.own_points.push_back( View::PointPtr( new View::Point() ) ); - hbox.add(b); - - Gtk::Image image(pixbuf); - hbox.add(image); - - window.add(hbox); - window.show_all(); + MainWindow window; std::cout << "run" << std::endl; int result = application->run(window); std::cout << "finished with code " << result << std::endl; + return result; } diff --git a/c++/perspective/src/mainwindow.cpp b/c++/perspective/src/mainwindow.cpp new file mode 100644 index 0000000..ab4ce70 --- /dev/null +++ b/c++/perspective/src/mainwindow.cpp @@ -0,0 +1,136 @@ +#include +#include + +#include +#include +#include + +#include "generator.h" +#include "surface.h" + +#include "mainwindow.h" + + +MainWindow::MainWindow(): + src_rect0 (new View::Point( Vector2(-10, -10) )), + src_rect1 (new View::Point( Vector2( 10, 10) )), + dst_rect0 (new View::Point( Vector2(-10, -10) )), + dst_rect1 (new View::Point( Vector2( 10, -10) )), + dst_rect2 (new View::Point( Vector2( 10, 10) )), + dst_rect3 (new View::Point( Vector2(-10, 10) )), + dst_bounds0 (new View::Point( Vector2(-20, -20) )), + dst_bounds1 (new View::Point( Vector2( 20, 20) )) +{ + set_default_size(200, 200); + + Gtk::HBox *hbox = manage(new Gtk::HBox()); + hbox->set_homogeneous(true); + + src_view.points.push_back(src_rect0); + src_view.points.push_back(src_rect1); + src_view.signal_point_motion.connect( + sigc::mem_fun(*this, &MainWindow::on_point_motion) ); + src_view.signal_point_changed.connect( + sigc::mem_fun(*this, &MainWindow::on_point_changed) ); + src_view.signal_draw_view.connect( + sigc::mem_fun(*this, &MainWindow::on_draw_src_view) ); + hbox->add(src_view); + + dst_view.points.push_back(dst_rect0); + dst_view.points.push_back(dst_rect1); + dst_view.points.push_back(dst_rect2); + dst_view.points.push_back(dst_rect3); + dst_view.points.push_back(dst_bounds0); + dst_view.points.push_back(dst_bounds1); + dst_view.signal_point_motion.connect( + sigc::mem_fun(*this, &MainWindow::on_point_motion) ); + dst_view.signal_point_changed.connect( + sigc::mem_fun(*this, &MainWindow::on_point_changed) ); + dst_view.signal_draw_view.connect( + sigc::mem_fun(*this, &MainWindow::on_draw_dst_view) ); + hbox->add(dst_view); + + hbox->add(*manage(generator_demo())); + + add(*hbox); + show_all(); +} + +Gtk::Widget* +MainWindow::generator_demo() { + std::cout << "generator demo: generate" << std::endl; + Generator generator; + DataSurface surface(256, 256); + generator.generate(surface, Vector2(0, 0), Vector2(16, 16)); + + std::cout << "generator demo: convert" << std::endl; + Glib::RefPtr pixbuf = Gdk::Pixbuf::create( + Gdk::COLORSPACE_RGB, true, 8, surface.width(), surface.height() ); + guint8 *pixel = pixbuf->get_pixels(); + for(int r = 0; r < surface.height(); ++r) { + Color *row = surface[r]; + for(int c = 0; c < surface.width(); ++c) { + const Color &color = row[c]; + *(pixel++) = (guint8)(color.r*255.9); + *(pixel++) = (guint8)(color.g*255.9); + *(pixel++) = (guint8)(color.b*255.9); + *(pixel++) = (guint8)(color.a*255.9); + } + } + + return new Gtk::Image(pixbuf); +} + +void +MainWindow::on_point_motion(const View::PointPtr &/*point*/) { + queue_draw(); +} + +void +MainWindow::on_point_changed(const View::PointPtr &/*point*/) { +} + +void +MainWindow::on_draw_src_view(const Cairo::RefPtr &context) { + const Real ps = src_view.get_pixel_size(); + + context->save(); + + context->move_to(src_rect0->position.x, src_rect0->position.y); + context->line_to(src_rect0->position.x, src_rect1->position.y); + context->line_to(src_rect1->position.x, src_rect1->position.y); + context->line_to(src_rect1->position.x, src_rect0->position.y); + context->close_path(); + context->set_line_width(ps); + context->set_source_rgba(1, 1, 0, 0.5); + context->stroke(); + + context->restore(); +} + +void +MainWindow::on_draw_dst_view(const Cairo::RefPtr &context) { + const Real ps = src_view.get_pixel_size(); + + context->save(); + + context->move_to(dst_rect0->position.x, dst_rect0->position.y); + context->line_to(dst_rect1->position.x, dst_rect1->position.y); + context->line_to(dst_rect2->position.x, dst_rect2->position.y); + context->line_to(dst_rect3->position.x, dst_rect3->position.y); + context->close_path(); + context->set_line_width(ps); + context->set_source_rgba(1, 1, 0, 0.5); + context->stroke(); + + context->move_to(dst_bounds0->position.x, dst_bounds0->position.y); + context->line_to(dst_bounds0->position.x, dst_bounds1->position.y); + context->line_to(dst_bounds1->position.x, dst_bounds1->position.y); + context->line_to(dst_bounds1->position.x, dst_bounds0->position.y); + context->close_path(); + context->set_line_width(ps); + context->set_source_rgba(1, 0, 0, 0.5); + context->stroke(); + + context->restore(); +} diff --git a/c++/perspective/src/mainwindow.h b/c++/perspective/src/mainwindow.h new file mode 100644 index 0000000..9664943 --- /dev/null +++ b/c++/perspective/src/mainwindow.h @@ -0,0 +1,32 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + + +#include + +#include "view.h" + + +class MainWindow: public Gtk::Window { +public: + View src_view; + View dst_view; + + View::PointPtr + src_rect0, src_rect1, + dst_rect0, dst_rect1, dst_rect2, dst_rect3, + dst_bounds0, dst_bounds1; + + MainWindow(); + + Gtk::Widget* generator_demo(); + + void on_point_motion(const View::PointPtr &point); + void on_point_changed(const View::PointPtr &point); + void on_draw_src_view(const Cairo::RefPtr &context); + void on_draw_dst_view(const Cairo::RefPtr &context); +}; + + +#endif + diff --git a/c++/perspective/src/view.cpp b/c++/perspective/src/view.cpp index d2d3127..f8b90ff 100644 --- a/c++/perspective/src/view.cpp +++ b/c++/perspective/src/view.cpp @@ -8,23 +8,18 @@ View::Point::draw( const Cairo::RefPtr& context, View &view ) { - const Real scale = 1.0/sqrt(fabs(view.transform.m00*view.transform.m11)); + const Real ps = view.get_pixel_size(); context->save(); - context->arc(position.x, position.y, radius*scale, 0.0, 2.0*M_PI); + context->arc(position.x, position.y, radius*ps, 0.0, 2.0*M_PI); context->set_source_rgba(color.r, color.g, color.b, color.a); context->fill_preserve(); context->set_source_rgba(0.0, 0.0, 0.0, color.a); - context->set_line_width(selected ? 2.0*scale : scale); + context->set_line_width(selected ? 2.0*ps : ps); context->stroke(); context->restore(); } -void -View::Layer::draw(const Cairo::RefPtr&, View&) - { } - - View::View(): dragging() { @@ -36,6 +31,10 @@ View::View(): View::~View() { } +Real +View::get_pixel_size() + { return 1.0/sqrt(fabs(transform.m00 * transform.m11)); } + bool View::on_draw(const Cairo::RefPtr& context) { context->save(); @@ -58,11 +57,8 @@ View::on_draw(const Cairo::RefPtr& context) { context->translate(0.5*get_width(), 0.5*get_height()); context->transform(Cairo::Matrix(transform.m00, transform.m10, transform.m01, transform.m11, transform.m30, transform.m31)); - for(LayerList::const_iterator i = layers.begin(); i != layers.end(); ++i) - (*i)->draw(context, *this); - for(PointList::const_iterator i = foreign_points.begin(); i != foreign_points.end(); ++i) - (*i)->draw(context, *this); - for(PointList::const_iterator i = own_points.begin(); i != own_points.end(); ++i) + signal_draw_view(context); + for(PointList::const_iterator i = points.begin(); i != points.end(); ++i) (*i)->draw(context, *this); context->restore(); return true; @@ -74,12 +70,12 @@ View::on_motion_notify_event(GdkEventMotion *event) { if (dragging) { if (selected_point) { selected_point->position = Vector2(transform.invert()*Vector4(position + selected_point_offset)); - selected_point->motion(); + point_motion(selected_point); queue_draw(); } } else { PointPtr point; - for(PointList::iterator i = own_points.begin(); i != own_points.end(); ++i) { + for(PointList::iterator i = points.begin(); i != points.end(); ++i) { (*i)->selected = false; Vector2 point_position = Vector2(transform * Vector4((*i)->position)); Vector2 offset = point_position - position; @@ -107,7 +103,8 @@ bool View::on_button_release_event(GdkEventButton *event) { if (event->button == 1) { dragging = false; - if (selected_point) selected_point->changed(); + if (selected_point) + point_changed(selected_point); } return true; } diff --git a/c++/perspective/src/view.h b/c++/perspective/src/view.h index f529475..cefd251 100644 --- a/c++/perspective/src/view.h +++ b/c++/perspective/src/view.h @@ -16,41 +16,33 @@ public: class Point: public Shared { public: Vector2 position; - Real radius; Color color; + Real radius; bool selected; - Point(): radius(5.0), color(1, 1, 0, 1), selected() { } + inline explicit Point( + const Vector2 &position = Vector2(), + const Color &color = Color(1, 1, 0, 1), + Real radius = 5.0, + bool selected = false + ): + position(position), + color(color), + radius(radius), + selected(selected) + { } - sigc::signal signal_motion; - sigc::signal signal_changed; - - void motion() { signal_motion(); } - void changed() { motion(); signal_changed(); } - virtual void draw( const Cairo::RefPtr& context, View &view ); }; - class Layer: public Shared { - public: - virtual void draw( - const Cairo::RefPtr& context, - View &view ); - }; - typedef RefPtr PointPtr; - typedef RefPtr LayerPtr; typedef std::vector PointList; - typedef std::vector LayerList; public: Matrix transform; - - LayerList layers; - PointList own_points; - PointList foreign_points; + PointList points; private: bool dragging; @@ -60,7 +52,18 @@ private: public: View(); virtual ~View(); + + sigc::signal&> signal_draw_view; + sigc::signal signal_point_motion; + sigc::signal signal_point_changed; + void point_motion(const PointPtr &point) + { signal_point_motion(point); } + void point_changed(const PointPtr &point) + { point_motion(point); signal_point_changed(point); } + + Real get_pixel_size(); + protected: bool on_draw(const Cairo::RefPtr& context) override; bool on_motion_notify_event(GdkEventMotion *event) override;