Added gravity.
[universe.git] / plotter.cc
1
2 // Written and (C) by Francois Fleuret
3 // Contact <francois.fleuret@idiap.ch> for comments & bug reports
4
5 #include "plotter.h"
6
7 Plotter::Plotter(int width, int height, int scaling) {
8   _scaling = scaling;
9   _width = width * _scaling;
10   _height = height * _scaling;
11
12   _tag_map = new Tag *[_width * _height];
13   _tag_stack = new Tag[_width * _height];
14
15   _red_imap = new scalar_t[(_width + 1) * (_height + 1)];
16   _green_imap = new scalar_t[(_width + 1) * (_height + 1)];
17   _blue_imap = new scalar_t[(_width + 1) * (_height + 1)];
18
19   reset();
20 }
21
22 Plotter::~Plotter() {
23   delete[] _tag_map;
24   delete[] _tag_stack;
25   delete[] _red_imap;
26   delete[] _green_imap;
27   delete[] _blue_imap;
28 }
29
30 void Plotter::reset() {
31   for(int k = 0; k < _width * _height; k++) {
32     _tag_map[k] = 0;
33   }
34   _tag_stack_top = _tag_stack;
35   _current_polygon = 0;
36 }
37
38 void Plotter::draw_polygon(Polygon *p) {
39   int nb = p->_nb_vertices;
40
41   int ix[nb], iy[nb];
42
43   for(int n = 0; n < nb; n++) {
44     ix[n] = int(p->_x[n] * scalar_t(_scaling) + 0.5);
45     iy[n] = int(p->_y[n] * scalar_t(_scaling) + 0.5);
46   }
47
48   scalar_t red = p->_red;
49   scalar_t green = p->_green;
50   scalar_t blue = p->_blue;
51
52   int direction;
53
54   if(iy[0] > iy[nb-1]) direction = 1;
55   else if(iy[0] < iy[nb-1]) direction = -1;
56   else direction = 0;
57
58   for(int n = 0; n < nb; n++) {
59     int m = (n+1)%nb;
60
61     if(ix[n] >= 0 && ix[n] < _width && iy[n] >= 0 && iy[n] < _height &&
62        ix[m] >= 0 && ix[m] < _width && iy[m] >= 0 && iy[m] < _height) {
63
64       if(iy[m] > iy[n]) { // RIGHT BORDERS
65
66         if(direction < 0) {
67           push_tag(1 + ix[n], iy[n], red, green, blue);
68         }
69
70         for(int y = iy[n] + 1; y <= iy[m]; y++) {
71           push_tag(1 + ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
72                    red, green, blue);
73         }
74
75         direction = 1;
76
77       } else if(iy[m] < iy[n]) { // LEFT BORDERS
78
79         if(direction >= 0) {
80           push_tag(ix[n], iy[n], red, green, blue);
81         }
82
83         for(int y = iy[n] - 1; y >= iy[m]; y--) {
84           push_tag(ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
85                    red, green, blue);
86         }
87
88         direction = -1;
89
90       } else {
91
92         if(direction >= 0) push_tag(ix[n]+1, iy[n], red, green, blue);
93         push_tag(ix[m], iy[m], red, green, blue);
94         direction = 0;
95
96       }
97
98     } else {
99
100       if(iy[m] > iy[n]) { // RIGHT BORDERS
101
102         if(direction < 0) {
103           protected_push_tag(1 + ix[n], iy[n], red, green, blue);
104         }
105
106         for(int y = iy[n] + 1; y <= iy[m]; y++) {
107           protected_push_tag(1 + ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
108                              red, green, blue);
109         }
110
111         direction = 1;
112
113       } else if(iy[m] < iy[n]) { // LEFT BORDERS
114
115         if(direction >= 0) {
116           protected_push_tag(ix[n], iy[n], red, green, blue);
117         }
118
119         for(int y = iy[n] - 1; y >= iy[m]; y--) {
120           protected_push_tag(ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
121                              red, green, blue);
122         }
123
124         direction = -1;
125
126       } else {
127
128         if(direction >= 0) {
129           protected_push_tag(ix[n]+1, iy[n], red, green, blue);
130         }
131
132         protected_push_tag(ix[m], iy[m], red, green, blue);
133
134         direction = 0;
135       }
136     }
137   }
138
139   _current_polygon++;
140 }
141
142 void Plotter::fill() {
143   bool in[_current_polygon];
144   for(int p = 0; p < _current_polygon; p++) in[p] = false;
145
146   scalar_t red[_current_polygon], green[_current_polygon], blue[_current_polygon];
147   Tag **u = _tag_map;
148
149   int lk = 0, k = 0;
150
151   for(int x = 0; x < _width+1; x++) {
152     _red_imap[k] = 0;
153     _green_imap[k] = 0;
154     _blue_imap[k] = 0;
155     k++;
156   }
157
158   int current_index = -1;
159   for(int y = 0; y < _height; y++) {
160     scalar_t sred = 0, sgreen = 0, sblue = 0;
161     _red_imap[k] = 0;
162     _green_imap[k] = 0;
163     _blue_imap[k] = 0;
164     k++; lk++;
165
166     for(int x = 0; x < _width; x++) {
167       for(Tag *t = *u; t; t = t->next) {
168         if(in[t->index]) {
169           in[t->index] = false;
170           if(t->index == current_index) {
171             current_index--;
172             while(current_index >= 0 && !in[current_index]) current_index--;
173           }
174         } else {
175           in[t->index] = true;
176           red[t->index] = t->red;
177           green[t->index] = t->green;
178           blue[t->index] = t->blue;
179           if(t->index > current_index) current_index = t->index;
180         }
181       }
182
183       if(current_index >= 0) {
184         sred += red[current_index];
185         sgreen += green[current_index];
186         sblue += blue[current_index];
187       }
188
189       _red_imap[k] = sred + _red_imap[lk];
190       _green_imap[k] = sgreen + _green_imap[lk];
191       _blue_imap[k] = sblue + _blue_imap[lk];
192
193       k++; lk++;
194       u++;
195     }
196   }
197 }
198
199 void Plotter::save_as_ppm(Universe *universe, const char *filename, int downscale) {
200   reset();
201   for(int p = 0; p < universe->_nb_polygons; p++) {
202     if(universe->_polygons[p]) {
203       draw_polygon(universe->_polygons[p]);
204     }
205   }
206   fill();
207
208   unsigned char *image = new unsigned char[(_width/downscale) * (_height/downscale) * 3];
209
210   int n = 0;
211   for(int y = 0; y < _height / downscale; y++) {
212     for(int x = 0; x < _width / downscale; x++) {
213       image[n++] = int(255 * red_sum(x * downscale, y * downscale, (x + 1) * downscale, (y + 1) * downscale) / scalar_t(downscale * downscale));
214       image[n++] = int(255 * green_sum(x * downscale, y * downscale, (x + 1) * downscale, (y + 1) * downscale) / scalar_t(downscale * downscale));
215       image[n++] = int(255 * blue_sum(x * downscale, y * downscale, (x + 1) * downscale, (y + 1) * downscale) / scalar_t(downscale * downscale));
216     }
217   }
218
219   ofstream out(filename);
220   out << "P6" << endl;
221   out << _width/downscale << " " << _height/downscale << endl;
222   out << 255 << endl;
223   out.write((char *) image, (_width/downscale) * (_height/downscale) * 3);
224   out.flush();
225
226   delete[] image;
227 }