From b7ccc22341ca20668e98bad96c3d10ea77a47cc2 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Sun, 4 Sep 2016 22:25:53 +0200 Subject: [PATCH] Updating. --- Makefile | 4 +- main.cc | 65 +++------------ plotter.cc | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++++ plotter.h | 96 ++++++++++++++++++++++ polygon.cc | 32 +++----- polygon.h | 12 +-- universe.cc | 14 ++-- universe.h | 9 +-- 8 files changed, 361 insertions(+), 98 deletions(-) create mode 100644 plotter.cc create mode 100644 plotter.h diff --git a/Makefile b/Makefile index f4556f8..b5eef5e 100644 --- a/Makefile +++ b/Makefile @@ -42,8 +42,10 @@ TAGS: *.cc *.h main: main.o misc.o \ simple_window.o \ universe.o \ + plotter.o \ polygon.o \ xfig_tracer.o \ + canvas.o canvas_cairo.o \ map.o \ task.o \ retina.o \ @@ -56,7 +58,7 @@ main: main.o misc.o \ $(CXX) $(CXXFLAGS) -shared -Wl,-soname,$@ -o $@ $^ Makefile.depend: *.h *.cc Makefile - $(CC) -M *.cc > Makefile.depend + $(CC) $(CXXFLAGS) -M *.cc > Makefile.depend clean: \rm -f main *.o *.so Makefile.depend diff --git a/main.cc b/main.cc index bbea852..15e97a0 100644 --- a/main.cc +++ b/main.cc @@ -20,56 +20,15 @@ using namespace std; #include "retina.h" #include "manipulator.h" #include "intelligence.h" -#include "xfig_tracer.h" - -#ifdef CAIRO_SUPPORT -#include +#include "canvas_cairo.h" -static cairo_status_t write_cairo_to_file(void *closure, - const unsigned char *data, - unsigned int length) { - fwrite(data, 1, length, (FILE *) closure); - return CAIRO_STATUS_SUCCESS; -} +#include "xfig_tracer.h" void generate_png(Universe *universe, scalar_t scale, FILE *file) { - const int depth = 4; - const int width = int(universe->width() * scale); - const int height = int(universe->height() * scale); - - cairo_surface_t *image; - cairo_t* context_resource; - unsigned char *data; - - data = new unsigned char [width * height * depth]; - - image = cairo_image_surface_create_for_data(data, - CAIRO_FORMAT_RGB24, - width, - height, - width * depth); - - context_resource = cairo_create(image); - - cairo_scale(context_resource, scale, scale); - - cairo_set_source_rgb(context_resource, 1.0, 1.0, 1.0); - - cairo_rectangle(context_resource, 0, 0, - universe->width(), universe->height()); - - cairo_fill(context_resource); - - universe->draw(context_resource); - - cairo_surface_write_to_png_stream(image, write_cairo_to_file, file); - - cairo_destroy(context_resource); - cairo_surface_destroy(image); - - delete[] data; + CanvasCairo canvas(scale, universe->width(), universe->height()); + universe->draw(&canvas); + canvas.write_png(file); } -#endif // To train // ./main --task hit_shape.task 0 --action-mode=random --nb-ticks=5000 --proportion-for-training=0.5 --save-file=dump.mem --no-window @@ -221,7 +180,7 @@ int main(int argc, char **argv) { int window_main_fd = -1; #ifdef CAIRO_SUPPORT - cairo_t *window_main_cairo_cr = 0; + // cairo_t *window_main_cairo_cr = 0; #endif MapConcatener sensory_map(2); @@ -255,7 +214,7 @@ int main(int argc, char **argv) { window_main_fd = window_main->file_descriptor(); window_main->map(); #ifdef CAIRO_SUPPORT - window_main_cairo_cr = window_main->get_cairo_context_resource(); + // window_main_cairo_cr = window_main->get_cairo_context_resource(); #endif cout << "When the main window has the focus, press `q' to quit and click and drag to move" << endl << "objects." << endl; @@ -348,11 +307,13 @@ int main(int argc, char **argv) { window_main->color(1.0, 1.0, 1.0); window_main->fill(); -#ifdef CAIRO_SUPPORT - universe.draw(window_main_cairo_cr); -#else +// #ifdef CAIRO_SUPPORT + // CanvasCairo cc; + // cc._context_resource = window_main_cairo_cr; + // universe.draw(&cc); +// #else universe.draw(window_main); -#endif +// #endif task->draw(window_main); manipulator.draw_on_universe(window_main); diff --git a/plotter.cc b/plotter.cc new file mode 100644 index 0000000..b546753 --- /dev/null +++ b/plotter.cc @@ -0,0 +1,227 @@ + +// Written and (C) by Francois Fleuret +// Contact for comments & bug reports + +#include "plotter.h" + +Plotter::Plotter(int width, int height, int scaling) { + _scaling = scaling; + _width = width * _scaling; + _height = height * _scaling; + + _tag_map = new Tag *[_width * _height]; + _tag_stack = new Tag[_width * _height]; + + _red_imap = new scalar_t[(_width + 1) * (_height + 1)]; + _green_imap = new scalar_t[(_width + 1) * (_height + 1)]; + _blue_imap = new scalar_t[(_width + 1) * (_height + 1)]; + + reset(); +} + +Plotter::~Plotter() { + delete[] _tag_map; + delete[] _tag_stack; + delete[] _red_imap; + delete[] _green_imap; + delete[] _blue_imap; +} + +void Plotter::reset() { + for(int k = 0; k < _width * _height; k++) { + _tag_map[k] = 0; + } + _tag_stack_top = _tag_stack; + _current_polygon = 0; +} + +void Plotter::draw_polygon(Polygon *p) { + int nb = p->_nb_vertices; + + int ix[nb], iy[nb]; + + for(int n = 0; n < nb; n++) { + ix[n] = int(p->_x[n] * scalar_t(_scaling) + 0.5); + iy[n] = int(p->_y[n] * scalar_t(_scaling) + 0.5); + } + + scalar_t red = p->_red; + scalar_t green = p->_green; + scalar_t blue = p->_blue; + + int direction; + + if(iy[0] > iy[nb-1]) direction = 1; + else if(iy[0] < iy[nb-1]) direction = -1; + else direction = 0; + + for(int n = 0; n < nb; n++) { + int m = (n+1)%nb; + + if(ix[n] >= 0 && ix[n] < _width && iy[n] >= 0 && iy[n] < _height && + ix[m] >= 0 && ix[m] < _width && iy[m] >= 0 && iy[m] < _height) { + + if(iy[m] > iy[n]) { // RIGHT BORDERS + + if(direction < 0) { + push_tag(1 + ix[n], iy[n], red, green, blue); + } + + for(int y = iy[n] + 1; y <= iy[m]; y++) { + push_tag(1 + ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y, + red, green, blue); + } + + direction = 1; + + } else if(iy[m] < iy[n]) { // LEFT BORDERS + + if(direction >= 0) { + push_tag(ix[n], iy[n], red, green, blue); + } + + for(int y = iy[n] - 1; y >= iy[m]; y--) { + push_tag(ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y, + red, green, blue); + } + + direction = -1; + + } else { + + if(direction >= 0) push_tag(ix[n]+1, iy[n], red, green, blue); + push_tag(ix[m], iy[m], red, green, blue); + direction = 0; + + } + + } else { + + if(iy[m] > iy[n]) { // RIGHT BORDERS + + if(direction < 0) { + protected_push_tag(1 + ix[n], iy[n], red, green, blue); + } + + for(int y = iy[n] + 1; y <= iy[m]; y++) { + protected_push_tag(1 + ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y, + red, green, blue); + } + + direction = 1; + + } else if(iy[m] < iy[n]) { // LEFT BORDERS + + if(direction >= 0) { + protected_push_tag(ix[n], iy[n], red, green, blue); + } + + for(int y = iy[n] - 1; y >= iy[m]; y--) { + protected_push_tag(ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y, + red, green, blue); + } + + direction = -1; + + } else { + + if(direction >= 0) { + protected_push_tag(ix[n]+1, iy[n], red, green, blue); + } + + protected_push_tag(ix[m], iy[m], red, green, blue); + + direction = 0; + } + } + } + + _current_polygon++; +} + +void Plotter::fill() { + bool in[_current_polygon]; + for(int p = 0; p < _current_polygon; p++) in[p] = false; + + scalar_t red[_current_polygon], green[_current_polygon], blue[_current_polygon]; + Tag **u = _tag_map; + + int lk = 0, k = 0; + + for(int x = 0; x < _width+1; x++) { + _red_imap[k] = 0; + _green_imap[k] = 0; + _blue_imap[k] = 0; + k++; + } + + int current_index = -1; + for(int y = 0; y < _height; y++) { + scalar_t sred = 0, sgreen = 0, sblue = 0; + _red_imap[k] = 0; + _green_imap[k] = 0; + _blue_imap[k] = 0; + k++; lk++; + + for(int x = 0; x < _width; x++) { + for(Tag *t = *u; t; t = t->next) { + if(in[t->index]) { + in[t->index] = false; + if(t->index == current_index) { + current_index--; + while(current_index >= 0 && !in[current_index]) current_index--; + } + } else { + in[t->index] = true; + red[t->index] = t->red; + green[t->index] = t->green; + blue[t->index] = t->blue; + if(t->index > current_index) current_index = t->index; + } + } + + if(current_index >= 0) { + sred += red[current_index]; + sgreen += green[current_index]; + sblue += blue[current_index]; + } + + _red_imap[k] = sred + _red_imap[lk]; + _green_imap[k] = sgreen + _green_imap[lk]; + _blue_imap[k] = sblue + _blue_imap[lk]; + + k++; lk++; + u++; + } + } +} + +void Plotter::save_as_ppm(Universe *universe, const char *filename) { + reset(); + for(int p = 0; p < universe->_nb_polygons; p++) { + if(universe->_polygons[p]) { + draw_polygon(universe->_polygons[p]); + } + } + fill(); + + unsigned char *image = new unsigned char[_width * _height * 3]; + + int n = 0; + for(int y = 0; y < _height / _scaling; y++) { + for(int x = 0; x < _width / _scaling; x++) { + image[n++] = red_sum(x * _scaling, y * _scaling, (x + 1) * _scaling, (y + 1) * _scaling) / scalar_t(_scaling * _scaling); + image[n++] = green_sum(x * _scaling, y * _scaling, (x + 1) * _scaling, (y + 1) * _scaling) / scalar_t(_scaling * _scaling); + image[n++] = blue_sum(x * _scaling, y * _scaling, (x + 1) * _scaling, (y + 1) * _scaling) / scalar_t(_scaling * _scaling); + } + } + + ofstream out(filename); + out << "P6" << endl; + out << _width << " " << _height << endl; + out << 255 << endl; + out.write((char *) image, _width * _height * 3); + out.flush(); + + delete[] image; +} diff --git a/plotter.h b/plotter.h new file mode 100644 index 0000000..d93490d --- /dev/null +++ b/plotter.h @@ -0,0 +1,96 @@ + +// Written and (C) by Francois Fleuret +// Contact for comments & bug reports + +#ifndef PLOTTER_H +#define PLOTTER_H + +#include +#include + +using namespace std; + +#include "misc.h" +#include "universe.h" + +class Plotter { + int _width, _height; + + class Tag { + public: + int index; + scalar_t red, green, blue; + Tag *next; + }; + + Tag **_tag_map; + + // We have our own stack of tags to avoid numerous news and deletes + Tag *_tag_stack, *_tag_stack_top; + scalar_t *_red_imap, *_green_imap, *_blue_imap; + int _current_polygon; + int _scaling; + + inline void protected_push_tag(int x, int y, scalar_t r, scalar_t g, scalar_t b) { + if(y >= 0 && y < _height) { + + if(x < 0) { x = 0; } + else if(x >= _width) { x = _width - 1; } + + int t = y * _width + x; + + _tag_stack_top->next = _tag_map[t]; + _tag_stack_top->index = _current_polygon; + _tag_stack_top->red = r; + _tag_stack_top->green = g; + _tag_stack_top->blue = b; + _tag_map[t] = _tag_stack_top; + _tag_stack_top++; + } + } + + inline void push_tag(int x, int y, scalar_t r, scalar_t g, scalar_t b) { + int t = y * _width + x; + _tag_stack_top->next = _tag_map[t]; + _tag_stack_top->index = _current_polygon; + _tag_stack_top->red = r; + _tag_stack_top->green = g; + _tag_stack_top->blue = b; + _tag_map[t] = _tag_stack_top; + _tag_stack_top++; + } + + inline scalar_t red_sum(int xmin, int ymin, int xmax, int ymax) { + return _red_imap[xmax + (_width + 1) * ymax] + + _red_imap[xmin + (_width + 1) * ymin] + - _red_imap[xmax + (_width + 1) * ymin] + - _red_imap[xmin + (_width + 1) * ymax]; + } + + inline scalar_t green_sum(int xmin, int ymin, int xmax, int ymax) { + return _green_imap[xmax + (_width + 1) * ymax] + + _green_imap[xmin + (_width + 1) * ymin] + - _green_imap[xmax + (_width + 1) * ymin] + - _green_imap[xmin + (_width + 1) * ymax]; + } + + inline scalar_t blue_sum(int xmin, int ymin, int xmax, int ymax) { + return _blue_imap[xmax + (_width + 1) * ymax] + + _blue_imap[xmin + (_width + 1) * ymin] + - _blue_imap[xmax + (_width + 1) * ymin] + - _blue_imap[xmin + (_width + 1) * ymax]; + } + + void reset(); + + void draw_polygon(Polygon *p); + void fill(); +public: + + Plotter(int width, int height, int scaling); + ~Plotter(); + + void save_as_ppm(Universe *universe, const char *filename); +}; + +#endif diff --git a/polygon.cc b/polygon.cc index e121e2c..4068919 100644 --- a/polygon.cc +++ b/polygon.cc @@ -81,31 +81,15 @@ void Polygon::draw_contours(SimpleWindow *window) { } #endif -#ifdef CAIRO_SUPPORT -void Polygon::draw(cairo_t* context_resource) { - cairo_set_line_width(context_resource, 1.0); - cairo_set_source_rgb (context_resource, _red, _green, _blue); - cairo_move_to(context_resource, _x[0], _y[0]); - for(int n = 0; n < _nb_vertices; n++) { - cairo_line_to(context_resource, _x[n], _y[n]); - } - cairo_close_path(context_resource); - cairo_stroke_preserve(context_resource); - cairo_fill(context_resource); +void Polygon::draw(Canvas *canvas) { + canvas->set_drawing_color(_red, _green, _blue); + canvas->draw_polygon(1, _nb_vertices, _x, _y); } -void Polygon::draw_contours(cairo_t* context_resource) { - cairo_set_line_width(context_resource, 1.0); - cairo_set_source_rgb (context_resource, 0.0, 0.0, 0.0); - // cairo_set_source_rgb (context_resource, 1.0, 1.0, 1.0); - cairo_move_to(context_resource, _x[0], _y[0]); - for(int n = 0; n < _nb_vertices; n++) { - cairo_line_to(context_resource, _x[n], _y[n]); - } - cairo_close_path(context_resource); - cairo_stroke(context_resource); +void Polygon::draw_contours(Canvas *canvas) { + canvas->set_drawing_color(0.0, 0.0, 0.0); + canvas->draw_polygon(0, _nb_vertices, _x, _y); } -#endif void Polygon::set_vertex(int k, scalar_t x, scalar_t y) { _relative_x[k] = x; @@ -209,7 +193,9 @@ void Polygon::initialize(int nb_polygons) { _nb_polygons = nb_polygons; - a = _relative_x[_nb_vertices - 1] * _relative_y[0] - _relative_x[0] * _relative_y[_nb_vertices - 1]; + a = _relative_x[_nb_vertices - 1] * _relative_y[0] + - _relative_x[0] * _relative_y[_nb_vertices - 1]; + for(int n = 0; n < _nb_vertices - 1; n++) a += _relative_x[n] * _relative_y[n+1] - _relative_x[n+1] * _relative_y[n]; a *= 0.5; diff --git a/polygon.h b/polygon.h index 48e6d3b..5a000be 100644 --- a/polygon.h +++ b/polygon.h @@ -6,16 +6,14 @@ #define POLYGON_H #include "misc.h" +#include "canvas.h" + #include "xfig_tracer.h" #ifdef X11_SUPPORT #include "simple_window.h" #endif -#ifdef CAIRO_SUPPORT -#include -#endif - class Polygon { struct Triangle { int a, b, c; @@ -81,10 +79,8 @@ public: void draw_contours(SimpleWindow *window); #endif -#ifdef CAIRO_SUPPORT - void draw(cairo_t* context_resource); - void draw_contours(cairo_t* context_resource); -#endif + void draw(Canvas *canvas); + void draw_contours(Canvas *canvas); void set_vertex(int k, scalar_t x, scalar_t y); void set_position(scalar_t center_x, scalar_t center_y, scalar_t theta); diff --git a/universe.cc b/universe.cc index 92b7a1b..55e1a6d 100644 --- a/universe.cc +++ b/universe.cc @@ -7,8 +7,10 @@ #include "universe.h" Universe::Universe(int nb_max_polygons, - scalar_t width, scalar_t height) : _width(width), _height(height), - _nb_max_polygons(nb_max_polygons), _nb_polygons(0) { + scalar_t width, scalar_t height) : _width(width), + _height(height), + _nb_max_polygons(nb_max_polygons), + _nb_polygons(0) { _polygons = new Polygon *[_nb_max_polygons]; for(int n = 0; n < _nb_max_polygons; n++) _polygons[n] = 0; } @@ -145,21 +147,19 @@ void Universe::draw(SimpleWindow *window) { } #endif -#ifdef CAIRO_SUPPORT -void Universe::draw(cairo_t *context_resource) { +void Universe::draw(Canvas *canvas) { for(int n = 0; n < _nb_polygons; n++) { if(_polygons[n]) { - _polygons[n]->draw(context_resource); + _polygons[n]->draw(canvas); } } for(int n = 0; n < _nb_polygons; n++) { if(_polygons[n]) { - _polygons[n]->draw_contours(context_resource); + _polygons[n]->draw_contours(canvas); } } } -#endif void Universe::apply_collision_forces(scalar_t dt) { const int nb_axis = 2; diff --git a/universe.h b/universe.h index a9f55d7..b164d0b 100644 --- a/universe.h +++ b/universe.h @@ -9,16 +9,13 @@ #include #include "misc.h" +#include "canvas.h" #include "polygon.h" #ifdef X11_SUPPORT #include "simple_window.h" #endif -#ifdef CAIRO_SUPPORT -#include -#endif - using namespace std; class Universe { @@ -53,9 +50,7 @@ public: void draw(SimpleWindow *window); #endif -#ifdef CAIRO_SUPPORT - void draw(cairo_t *context_resource); -#endif + void draw(Canvas *canvas); }; #endif -- 2.20.1