2 // Written and (C) by Francois Fleuret
3 // Contact <francois.fleuret@idiap.ch> for comments & bug reports
7 const int ring_width[] = { 128, 64, 32, 16, 8, 4, 1, 1, 1, 1};
9 // 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 };
11 Retina::Retina(Universe *universe) : _universe(universe),
12 _tag_map(new Tag *[_width * _height]),
13 _tag_stack(new Tag[_width * _height]),
14 _tag_stack_top(_tag_stack),
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)]) {
22 for(int k = 0; k < int(sizeof(ring_width)/sizeof(int)); k++) {
23 np += 4 * (w / ring_width[k] - 1);
24 w -= 2 * ring_width[k];
39 void Retina::reset() {
40 for(int k = 0; k < _width * _height; k++) _tag_map[k] = 0;
41 _tag_stack_top = _tag_stack;
45 void Retina::draw_polygon(Polygon *p, scalar_t delta_x, scalar_t delta_y) {
46 int nb = p->_nb_vertices;
50 for(int n = 0; n < nb; n++) {
51 ix[n] = int(p->_x[n] + delta_x);
52 iy[n] = int(p->_y[n] + delta_y);
55 scalar_t red = p->_red;
56 scalar_t green = p->_green;
57 scalar_t blue = p->_blue;
60 if(iy[0] > iy[nb-1]) direction = 1;
61 else if(iy[0] < iy[nb-1]) direction = -1;
64 for(int n = 0; n < nb; n++) {
67 if(ix[n] >= 0 && ix[n] < _width && iy[n] >= 0 && iy[n] < _height &&
68 ix[m] >= 0 && ix[m] < _width && iy[m] >= 0 && iy[m] < _height) {
70 if(iy[m] > iy[n]) { // RIGHT BORDERS
72 if(direction < 0) push_tag(1 + ix[n], iy[n], red, green, blue);
73 for(int y = iy[n] + 1; y <= iy[m]; y++)
74 push_tag(1 + ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
78 } else if(iy[m] < iy[n]) { // LEFT BORDERS
80 if(direction >= 0) push_tag(ix[n], iy[n], red, green, blue);
81 for(int y = iy[n] - 1; y >= iy[m]; y--)
82 push_tag(ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
88 if(direction >= 0) push_tag(ix[n]+1, iy[n], red, green, blue);
89 push_tag(ix[m], iy[m], red, green, blue);
96 if(iy[m] > iy[n]) { // RIGHT BORDERS
98 if(direction < 0) protected_push_tag(1 + ix[n], iy[n], red, green, blue);
99 for(int y = iy[n] + 1; y <= iy[m]; y++)
100 protected_push_tag(1 + ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
104 } else if(iy[m] < iy[n]) { // LEFT BORDERS
106 if(direction >= 0) protected_push_tag(ix[n], iy[n], red, green, blue);
107 for(int y = iy[n] - 1; y >= iy[m]; y--)
108 protected_push_tag(ix[n] + ((ix[m] - ix[n]) * (y - iy[n]))/(iy[m] - iy[n]), y,
114 if(direction >= 0) protected_push_tag(ix[n]+1, iy[n], red, green, blue);
115 protected_push_tag(ix[m], iy[m], red, green, blue);
125 void Retina::fill() {
126 bool in[_current_polygon];
127 for(int p = 0; p < _current_polygon; p++) in[p] = false;
129 scalar_t red[_current_polygon], green[_current_polygon], blue[_current_polygon];
134 for(int x = 0; x < _width+1; x++) {
141 int current_index = -1;
142 for(int y = 0; y < _height; y++) {
143 scalar_t sred = 0, sgreen = 0, sblue = 0;
149 for(int x = 0; x < _width; x++) {
150 for(Tag *t = *u; t; t = t->next) {
152 in[t->index] = false;
153 if(t->index == current_index) {
155 while(current_index >= 0 && !in[current_index]) current_index--;
159 red[t->index] = t->red;
160 green[t->index] = t->green;
161 blue[t->index] = t->blue;
162 if(t->index > current_index) current_index = t->index;
166 if(current_index >= 0) {
167 sred += red[current_index];
168 sgreen += green[current_index];
169 sblue += blue[current_index];
172 _red_imap[k] = sred + _red_imap[lk];
173 _green_imap[k] = sgreen + _green_imap[lk];
174 _blue_imap[k] = sblue + _blue_imap[lk];
182 void Retina::raw_rectangle(unsigned char *image, int xmin, int ymin, int w, int h,
183 scalar_t red, scalar_t green, scalar_t blue) {
184 for(int y = ymin; y < ymin + h; y++) for(int x = xmin; x < xmin + w; x++) {
185 image[(y * _width + x) * 3 + 0] = (unsigned char) (255 * red);
186 image[(y * _width + x) * 3 + 1] = (unsigned char) (255 * green);
187 image[(y * _width + x) * 3 + 2] = (unsigned char) (255 * blue);
191 void Retina::save_as_ppm(const char *filename) {
192 unsigned char *image = new unsigned char[_width * _height * 3];
198 for(int k = 0; k < int(sizeof(ring_width)/sizeof(int)); k++) {
199 int s = ring_width[k];
200 int z0 = (_width - w)/2;
204 for(int x = z0; x < z2; x += s) {
205 raw_rectangle(image, x, z0, s, s, parameters[n + 0], parameters[n + 1], parameters[n + 2]);
207 raw_rectangle(image, z2, x, s, s, parameters[n + 0], parameters[n + 1], parameters[n + 2]);
209 raw_rectangle(image, x + s, z2, s, s, parameters[n + 0], parameters[n + 1], parameters[n + 2]);
211 raw_rectangle(image, z0, x + s, s, s, parameters[n + 0], parameters[n + 1], parameters[n + 2]);
217 ofstream out(filename);
219 out << _width << " " << _height << endl;
221 out.write((char *) image, _width * _height * 3);
226 void Retina::update_map() {
229 for(int p = 0; p < _universe->_nb_polygons; p++) if(_universe->_polygons[p])
230 draw_polygon(_universe->_polygons[p], scalar_t(_width)/2 - _eye_x, scalar_t(_height)/2 - _eye_y);
236 for(int k = 0; k < int(sizeof(ring_width)/sizeof(int)); k++) {
238 int s = ring_width[k];
239 int z0 = (_width - w)/2;
244 for(int x = z0; x < z2; x += s) {
245 parameters[n++] = red_sum(x, z0, x + s + 0, z1 + 0) / scalar_t(s * s);
246 parameters[n++] = green_sum(x, z0, x + s + 0, z1 + 0) / scalar_t(s * s);
247 parameters[n++] = blue_sum(x, z0, x + s + 0, z1 + 0) / scalar_t(s * s);
249 parameters[n++] = red_sum(z2, x, z3 + 0, x + s + 0) / scalar_t(s * s);
250 parameters[n++] = green_sum(z2, x, z3 + 0, x + s + 0) / scalar_t(s * s);
251 parameters[n++] = blue_sum(z2, x, z3 + 0, x + s + 0) / scalar_t(s * s);
253 parameters[n++] = red_sum(x + s, z2, x + 2 * s + 0, z3 + 0) / scalar_t(s * s);
254 parameters[n++] = green_sum(x + s, z2, x + 2 * s + 0, z3 + 0) / scalar_t(s * s);
255 parameters[n++] = blue_sum(x + s, z2, x + 2 * s + 0, z3 + 0) / scalar_t(s * s);
257 parameters[n++] = red_sum(z0, x + s, z1 + 0, x + 2 * s + 0) / scalar_t(s * s);
258 parameters[n++] = green_sum(z0, x + s, z1 + 0, x + 2 * s + 0) / scalar_t(s * s);
259 parameters[n++] = blue_sum(z0, x + s, z1 + 0, x + 2 * s + 0) / scalar_t(s * s);
266 cerr << "Error in the retina ring sizes!" << endl;
273 void Retina::draw_on_universe(SimpleWindow *window) {
274 window->color(1.0, 1.0, 1.0);
275 int xc = int(_eye_x), yc = int(_eye_y);
276 window->draw_line(xc - _width/2, yc - _height/2, xc + _width/2, yc - _height/2);
277 window->draw_line(xc + _width/2, yc - _height/2, xc + _width/2, yc + _height/2);
278 window->draw_line(xc + _width/2, yc + _height/2, xc - _width/2, yc + _height/2);
279 window->draw_line(xc - _width/2, yc + _height/2, xc - _width/2, yc - _height/2);
282 void Retina::draw_parameters(int x0, int y0, SimpleWindow *window) {
286 for(int k = 0; k < int(sizeof(ring_width)/sizeof(int)); k++) {
287 int s = ring_width[k];
288 int z0 = (_width - w)/2;
292 for(int x = z0; x < z2; x += s) {
293 window->color(parameters[n + 0], parameters[n + 1], parameters[n + 2]);
294 window->fill_rectangle(x0 + x, y0 + z0, s, s);
296 window->color(parameters[n + 0], parameters[n + 1], parameters[n + 2]);
297 window->fill_rectangle(x0 + z2, y0 + x, s, s);
299 window->color(parameters[n + 0], parameters[n + 1], parameters[n + 2]);
300 window->fill_rectangle(x0 + x + s, y0 + z2, s, s);
302 window->color(parameters[n + 0], parameters[n + 1], parameters[n + 2]);
303 window->fill_rectangle(x0 + z0, y0 + x + s, s, s);