Update.
[flatland.git] / canvas_cairo.cc
1
2 /*
3
4    flatland is a simple 2d physical simulator
5
6    Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
7    Written by Francois Fleuret <francois.fleuret@idiap.ch>
8
9    This file is part of flatland
10
11    flatland is free software: you can redistribute it and/or modify it
12    under the terms of the GNU General Public License version 3 as
13    published by the Free Software Foundation.
14
15    flatland is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with flatland.  If not, see <http://www.gnu.org/licenses/>.
22
23 */
24
25 #include "canvas_cairo.h"
26
27 #include <cmath>
28
29 #define MAX(x, y) ((x >= y) ? (x) : (y))
30
31 CanvasCairo::CanvasCairo(scalar_t scale, int nb_rows, int nb_cols, CanvasCairo **ca) {
32   _actual_width = 0;
33   _actual_height = 0;
34
35   for(int i = 0; i < nb_rows; i++) {
36     int row_height = 0, row_width = 0;
37     for(int j = 0; j < nb_cols; j++) {
38       CanvasCairo *this_ca = ca[i * nb_cols + j];
39       row_height = MAX(row_height, this_ca->_actual_height);
40       row_width += this_ca->_actual_width;
41     }
42     _actual_width = MAX(_actual_width, row_width);
43     _actual_height += row_height;
44   }
45
46   _data = new unsigned char [_actual_width * _actual_height * _depth];
47
48   int x0, y0 = 0;
49   for(int i = 0; i < nb_rows; i++) {
50     x0 = 0;
51     int row_height = 0;
52     for(int j = 0; j < nb_cols; j++) {
53       CanvasCairo *this_ca = ca[i * nb_cols + j];
54       for(int y = 0; y < this_ca->_actual_height; y++) {
55         for(int x = 0; x < this_ca->_actual_width; x++) {
56           for(int d = 0; d < _depth; d++) {
57             _data[(x0 + x + _actual_width * (y0 + y))* _depth + d] =
58               this_ca->_data[(x + this_ca->_actual_width * y)* _depth + d];
59
60           }
61         }
62       }
63       row_height = MAX(row_height, this_ca->_actual_height);
64       x0 += this_ca->_actual_width;
65     }
66     y0 += row_height;
67   }
68
69   _image = cairo_image_surface_create_for_data(_data,
70                                                CAIRO_FORMAT_RGB24,
71                                                _actual_width,
72                                                _actual_height,
73                                                _actual_width * _depth);
74
75   _context_resource = cairo_create(_image);
76
77   cairo_scale(_context_resource, scale, scale);
78
79   clear();
80   // cairo_set_source_rgb(_context_resource, 1.0, 1.0, 1.0);
81   // cairo_set_line_width (_context_resource, 1.0);
82 }
83
84 CanvasCairo::CanvasCairo(scalar_t scale, int width, int height) {
85   _actual_width = int(width * scale);
86   _actual_height = int(height * scale);
87   _scale = scale;
88
89   _data = new unsigned char [_actual_width * _actual_height * _depth];
90
91   _image = cairo_image_surface_create_for_data(_data,
92                                                CAIRO_FORMAT_RGB24,
93                                                _actual_width,
94                                                _actual_height,
95                                                _actual_width * _depth);
96
97   _context_resource = cairo_create(_image);
98
99   cairo_scale(_context_resource, scale, scale);
100
101   cairo_set_line_width (_context_resource, 1.0);
102
103   clear();
104   // cairo_set_source_rgb(_context_resource, 1.0, 1.0, 1.0);
105   // cairo_rectangle(_context_resource, 0, 0, width, height);
106   // cairo_fill(_context_resource);
107 }
108
109 CanvasCairo::~CanvasCairo() {
110   cairo_destroy(_context_resource);
111   cairo_surface_destroy(_image);
112   delete[] _data;
113 }
114
115 void CanvasCairo::clear() {
116   cairo_set_source_rgb(_context_resource, 1.0, 1.0, 1.0);
117   cairo_rectangle(_context_resource, 0, 0, _actual_width / _scale, _actual_height / _scale);
118   cairo_fill(_context_resource);
119 }
120
121 void CanvasCairo::set_line_width(scalar_t w) {
122   cairo_set_line_width (_context_resource, w);
123 }
124
125 void CanvasCairo::set_drawing_color(scalar_t r, scalar_t g, scalar_t b) {
126   cairo_set_source_rgb(_context_resource, r, g, b);
127 }
128
129 void CanvasCairo::draw_polygon(int filled, int nb, scalar_t *x, scalar_t *y) {
130   cairo_move_to(_context_resource, x[0], y[0]);
131   for(int n = 0; n < nb; n++) {
132     cairo_line_to(_context_resource, x[n], y[n]);
133   }
134   cairo_close_path(_context_resource);
135
136   if(filled) {
137     cairo_stroke_preserve(_context_resource);
138     cairo_fill(_context_resource);
139   } else {
140     cairo_stroke(_context_resource);
141   }
142 }
143
144 static cairo_status_t write_cairo_to_file(void *closure,
145                                           const unsigned char *data,
146                                           unsigned int length) {
147   fwrite(data, 1, length, (FILE *) closure);
148   return CAIRO_STATUS_SUCCESS;
149 }
150
151 void CanvasCairo::write_png(FILE *file) {
152   cairo_surface_write_to_png_stream(_image, write_cairo_to_file, file);
153 }