2 ////////////////////////////////////////////////////////////////////////////////
3 // This program is free software; you can redistribute it and/or //
4 // modify it under the terms of the GNU General Public License //
5 // version 2 as published by the Free Software Foundation. //
7 // This program is distributed in the hope that it will be useful, but //
8 // WITHOUT ANY WARRANTY; without even the implied warranty of //
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU //
10 // General Public License for more details. //
12 // Written and (C) by François Fleuret //
13 // Contact <francois.fleuret@epfl.ch> for comments & bug reports //
14 ////////////////////////////////////////////////////////////////////////////////
18 const int ring_width[] = { 128, 64, 32, 16, 8, 4, 1, 1, 1, 1};
20 // const int ring_width[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
22 Retina::Retina(Universe *universe) : _universe(universe),
23 _tag_map(new Tag *[_width * _height]),
24 _tag_stack(new Tag[_width * _height]),
25 _tag_stack_top(_tag_stack),
26 _red_imap(new scalar_t[(_width + 1) * (_height + 1)]),
27 _green_imap(new scalar_t[(_width + 1) * (_height + 1)]),
28 _blue_imap(new scalar_t[(_width + 1) * (_height + 1)]) {
33 for(int k = 0; k < int(sizeof(ring_width)/sizeof(int)); k++) {
34 np += 4 * (w / ring_width[k] - 1);
35 w -= 2 * ring_width[k];
50 void Retina::reset() {
51 for(int k = 0; k < _width * _height; k++) _tag_map[k] = 0;
52 _tag_stack_top = _tag_stack;
56 void Retina::draw_polygon(Polygon *p, scalar_t delta_x, scalar_t delta_y) {
57 int nb = p->_nb_vertices;
61 for(int n = 0; n < nb; n++) {
62 ix[n] = int(p->_x[n] + delta_x);
63 iy[n] = int(p->_y[n] + delta_y);
66 scalar_t red = p->_red;
67 scalar_t green = p->_green;
68 scalar_t blue = p->_blue;
71 if(iy[0] > iy[nb-1]) direction = 1;
72 else if(iy[0] < iy[nb-1]) direction = -1;
75 for(int n = 0; n < nb; n++) {
78 if(ix[n] >= 0 && ix[n] < _width && iy[n] >= 0 && iy[n] < _height &&
79 ix[m] >= 0 && ix[m] < _width && iy[m] >= 0 && iy[m] < _height) {
81 if(iy[m] > iy[n]) { // RIGHT BORDERS
83 if(direction < 0) push_tag(1 + ix[n], iy[n], red, green, blue);
84 for(int y = iy[n] + 1; y <= iy[m]; y++)
85 push_tag(1 + ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
89 } else if(iy[m] < iy[n]) { // LEFT BORDERS
91 if(direction >= 0) push_tag(ix[n], iy[n], red, green, blue);
92 for(int y = iy[n] - 1; y >= iy[m]; y--)
93 push_tag(ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
99 if(direction >= 0) push_tag(ix[n]+1, iy[n], red, green, blue);
100 push_tag(ix[m], iy[m], red, green, blue);
107 if(iy[m] > iy[n]) { // RIGHT BORDERS
109 if(direction < 0) protected_push_tag(1 + ix[n], iy[n], red, green, blue);
110 for(int y = iy[n] + 1; y <= iy[m]; y++)
111 protected_push_tag(1 + ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
115 } else if(iy[m] < iy[n]) { // LEFT BORDERS
117 if(direction >= 0) protected_push_tag(ix[n], iy[n], red, green, blue);
118 for(int y = iy[n] - 1; y >= iy[m]; y--)
119 protected_push_tag(ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
125 if(direction >= 0) protected_push_tag(ix[n]+1, iy[n], red, green, blue);
126 protected_push_tag(ix[m], iy[m], red, green, blue);
136 void Retina::fill() {
137 bool in[_current_polygon];
138 for(int p = 0; p < _current_polygon; p++) in[p] = false;
140 scalar_t red[_current_polygon], green[_current_polygon], blue[_current_polygon];
145 for(int x = 0; x < _width+1; x++) {
152 int current_index = -1;
153 for(int y = 0; y < _height; y++) {
154 scalar_t sred = 0, sgreen = 0, sblue = 0;
160 for(int x = 0; x < _width; x++) {
161 for(Tag *t = *u; t; t = t->next) {
163 in[t->index] = false;
164 if(t->index == current_index) {
166 while(current_index >= 0 && !in[current_index]) current_index--;
170 red[t->index] = t->red;
171 green[t->index] = t->green;
172 blue[t->index] = t->blue;
173 if(t->index > current_index) current_index = t->index;
177 if(current_index >= 0) {
178 sred += red[current_index];
179 sgreen += green[current_index];
180 sblue += blue[current_index];
183 _red_imap[k] = sred + _red_imap[lk];
184 _green_imap[k] = sgreen + _green_imap[lk];
185 _blue_imap[k] = sblue + _blue_imap[lk];
193 void Retina::raw_rectangle(unsigned char *image, int xmin, int ymin, int w, int h,
194 scalar_t red, scalar_t green, scalar_t blue) {
195 for(int y = ymin; y < ymin + h; y++) for(int x = xmin; x < xmin + w; x++) {
196 image[(y * _width + x) * 3 + 0] = (unsigned char) (255 * red);
197 image[(y * _width + x) * 3 + 1] = (unsigned char) (255 * green);
198 image[(y * _width + x) * 3 + 2] = (unsigned char) (255 * blue);
202 void Retina::save_as_ppm(char *filename) {
203 unsigned char *image = new unsigned char[_width * _height * 3];
209 for(int k = 0; k < int(sizeof(ring_width)/sizeof(int)); k++) {
210 int s = ring_width[k];
211 int z0 = (_width - w)/2;
215 for(int x = z0; x < z2; x += s) {
216 raw_rectangle(image, x, z0, s, s, parameters[n + 0], parameters[n + 1], parameters[n + 2]);
218 raw_rectangle(image, z2, x, s, s, parameters[n + 0], parameters[n + 1], parameters[n + 2]);
220 raw_rectangle(image, x + s, z2, s, s, parameters[n + 0], parameters[n + 1], parameters[n + 2]);
222 raw_rectangle(image, z0, x + s, s, s, parameters[n + 0], parameters[n + 1], parameters[n + 2]);
228 ofstream out(filename);
230 out << _width << " " << _height << endl;
232 out.write((char *) image, _width * _height * 3);
237 void Retina::update_map() {
240 for(int p = 0; p < _universe->_nb_polygons; p++) if(_universe->_polygons[p])
241 draw_polygon(_universe->_polygons[p], scalar_t(_width)/2 - _eye_x, scalar_t(_height)/2 - _eye_y);
247 for(int k = 0; k < int(sizeof(ring_width)/sizeof(int)); k++) {
249 int s = ring_width[k];
250 int z0 = (_width - w)/2;
255 for(int x = z0; x < z2; x += s) {
256 parameters[n++] = red_sum(x, z0, x + s + 0, z1 + 0) / scalar_t(s * s);
257 parameters[n++] = green_sum(x, z0, x + s + 0, z1 + 0) / scalar_t(s * s);
258 parameters[n++] = blue_sum(x, z0, x + s + 0, z1 + 0) / scalar_t(s * s);
260 parameters[n++] = red_sum(z2, x, z3 + 0, x + s + 0) / scalar_t(s * s);
261 parameters[n++] = green_sum(z2, x, z3 + 0, x + s + 0) / scalar_t(s * s);
262 parameters[n++] = blue_sum(z2, x, z3 + 0, x + s + 0) / scalar_t(s * s);
264 parameters[n++] = red_sum(x + s, z2, x + 2 * s + 0, z3 + 0) / scalar_t(s * s);
265 parameters[n++] = green_sum(x + s, z2, x + 2 * s + 0, z3 + 0) / scalar_t(s * s);
266 parameters[n++] = blue_sum(x + s, z2, x + 2 * s + 0, z3 + 0) / scalar_t(s * s);
268 parameters[n++] = red_sum(z0, x + s, z1 + 0, x + 2 * s + 0) / scalar_t(s * s);
269 parameters[n++] = green_sum(z0, x + s, z1 + 0, x + 2 * s + 0) / scalar_t(s * s);
270 parameters[n++] = blue_sum(z0, x + s, z1 + 0, x + 2 * s + 0) / scalar_t(s * s);
277 cerr << "Error in the retina ring sizes!" << endl;
284 void Retina::draw_on_universe(SimpleWindow *window) {
285 window->color(1.0, 1.0, 1.0);
286 int xc = int(_eye_x), yc = int(_eye_y);
287 window->draw_line(xc - _width/2, yc - _height/2, xc + _width/2, yc - _height/2);
288 window->draw_line(xc + _width/2, yc - _height/2, xc + _width/2, yc + _height/2);
289 window->draw_line(xc + _width/2, yc + _height/2, xc - _width/2, yc + _height/2);
290 window->draw_line(xc - _width/2, yc + _height/2, xc - _width/2, yc - _height/2);
293 void Retina::draw_parameters(int x0, int y0, SimpleWindow *window) {
297 for(int k = 0; k < int(sizeof(ring_width)/sizeof(int)); k++) {
298 int s = ring_width[k];
299 int z0 = (_width - w)/2;
303 for(int x = z0; x < z2; x += s) {
304 window->color(parameters[n + 0], parameters[n + 1], parameters[n + 2]);
305 window->fill_rectangle(x0 + x, y0 + z0, s, s);
307 window->color(parameters[n + 0], parameters[n + 1], parameters[n + 2]);
308 window->fill_rectangle(x0 + z2, y0 + x, s, s);
310 window->color(parameters[n + 0], parameters[n + 1], parameters[n + 2]);
311 window->fill_rectangle(x0 + x + s, y0 + z2, s, s);
313 window->color(parameters[n + 0], parameters[n + 1], parameters[n + 2]);
314 window->fill_rectangle(x0 + z0, y0 + x + s, s, s);