1 /*
2  * XLife Copyright 2012, 2013 Vladimir Lidovski vol.litwr@gmail.com
3  * $Id: topology.c 216 2013-07-28 18:06:27Z micro $
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of the copyright holders not be used in
10  * advertising or publicity pertaining to distribution of the software without
11  * specific, written prior permission.  The copyright holders make no
12  * representations about the suitability of this software for any purpose.  It
13  * is provided "as is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21  * PERFORMANCE OF THIS SOFTWARE.
22  */
23 
24 #include "defs.h"
25 #include "tile.h"
26 #include "colors.h"
27 
bscale(void)28 static unsigned bscale(void) {
29    if (scale >= 0) return 0;
30    if (scale == -1) return 2;
31    if (scale == -2) return 4;
32    return 8;
33 }
34 
y_max_scale(int dy)35 static unsigned y_max_scale(int dy) {
36    return RYPOS(y_max_limit + dy - bscale()) + (scale < 0);
37 }
38 
x_max_scale(int dx)39 static unsigned x_max_scale(int dx) {
40    return RXPOS(x_max_limit + dx - bscale()) + (scale < 0);
41 }
42 
adjust_topology(int dx,int dy,int s)43 void adjust_topology(int dx, int dy, int s) {
44    unsigned rect0x, rect0w, rect0y, rect0h, rect1x, rect1w, rect1y, rect1h;
45    int lx = x_max_limit - x_min_limit, ly = y_max_limit - y_min_limit,
46       x0 = RXPOS(x_min_limit), y0 = RYPOS(y_min_limit),
47       w0 = x_max_scale(0) - RXPOS(x_min_limit), w1 = w0,
48       h0 = y_max_scale(0) - RYPOS(y_min_limit), h1 = h0,
49       x1 = RXPOS(x_min_limit + dx), y1 = RYPOS(y_min_limit + dy);
50    if (dx == 0 && dy == 0) return;
51    if ((limits&1) == 0) {
52       if (dy == 0) return;
53       x0 = x1 = 0, w0 = w1 = width;
54       h1 = h0 = RSCALE(abs(dy));
55       if (dy > 0)
56           y1 = y_max_scale(0);
57       else
58           y0 = y_max_scale(dy);
59       goto DRAW;
60    }
61    else if ((limits&2) == 0) {
62       if (dx == 0) return;
63       y0 = y1 = 0, h0 = h1 = height;
64       if (dx > 0)
65          x1 = x_max_scale(0);
66       else
67          x0 = x_max_scale(dx);
68       w0 = w1 = RSCALE(abs(dx));
69       goto DRAW;
70    }
71    if (abs(dy) >= ly || abs(dx) >= lx) {
72       if (x0 < 0) w0 += x0, x0 = 0;
73       if (y0 < 0) h0 += y0, y0 = 0;
74       if (x1 < 0) w1 += x1, x1 = 0;
75       if (y1 < 0) h1 += y1, y1 = 0;
76       if (x0 + w0 > width) w0 -= x0 + w0 - width;
77       if (x1 + w1 > width) w1 -= x1 + w1 - width;
78       if (y0 + h0 > height) h0 -= y0 + h0 - height;
79       if (y1 + h1 > height) h1 -= y1 + h1 - height;
80 DRAW:
81       if (s == 0 && h0 > 0 && w0 > 0)
82       XFillRectangle(disp, lifew, *cellgc, x0, y0, w0, h0);
83       else if (s && h1 > 0 && w1 > 0)
84       XFillRectangle(disp, lifew, cellgc[GRID_COLOR], x1, y1, w1, h1);
85       return;
86    }
87 /* the following code is terrible */
88    if (dx > 0) {
89       if (xpos - dx < x_min_limit && XPOS(width) > x_min_limit) {
90          rect0x = max(RXPOS(x_min_limit), 0);
91          if (xpos > x_min_limit)
92             rect0w = RXPOS(x_min_limit + dx);
93          else
94             rect0w = min(RSCALE(dx), RSCALE(XPOS(width) - x_min_limit));
95       }
96       else
97          rect0x = rect0w = 0;
98       if (xpos - dx < x_max_limit && XPOS(width) > x_max_limit - 1) {
99          rect1x = max(x_max_scale(0), 0);
100          if (xpos > x_max_limit)
101             rect1w = x_max_scale(dx);
102          else
103             rect1w = min(RSCALE(dx), width - x_max_scale(0));
104       }
105       else
106          rect1x = rect1w = 0;
107    }
108    else if (dx < 0) {
109       if (xpos < x_max_limit && XPOS(width) - dx > x_max_limit - 1) {
110          rect0x = max(x_max_scale(dx), 0);
111          if (xpos - dx > x_max_limit)
112             rect0w = x_max_scale(0);
113          else
114             rect0w = min(RSCALE(-dx), width - x_max_scale(dx));
115       }
116       else
117          rect0x = rect0w = 0;
118       if (xpos < x_min_limit && XPOS(width) - dx > x_min_limit) {
119          rect1x = max(RXPOS(x_min_limit + dx), 0);
120          if (xpos > x_min_limit + dx)
121             rect1w = RXPOS(x_min_limit);
122          else
123             rect1w = min(RSCALE(-dx), RSCALE(XPOS(width) - x_min_limit - dx));
124       }
125       else
126          rect1x = rect1w = 0;
127    }
128    if (dy > 0) {
129       if (ypos - dy < y_min_limit && YPOS(height) > y_min_limit) {
130          rect0y = max(RYPOS(y_min_limit), 0);
131          if (ypos > y_min_limit)
132             rect0h = RYPOS(y_min_limit + dy);
133          else
134             rect0h = min(RSCALE(dy), RSCALE(YPOS(height) - y_min_limit));
135       }
136       else
137          rect0y = rect0h = 0;
138       if (ypos < y_max_limit + dy && YPOS(height) > y_max_limit - 1) {
139          rect1y = max(y_max_scale(0), 0);
140          if (ypos > y_max_limit)
141             rect1h = y_max_scale(dy);
142          else
143             rect1h = min(RSCALE(dy), height - y_max_scale(0));
144       }
145       else
146          rect1y = rect1h = 0;
147    }
148    else if (dy < 0) {
149       if (ypos < y_max_limit && YPOS(height) - dy > y_max_limit - 1) {
150          rect0y = max(y_max_scale(dy), 0);
151          if (ypos - dy > y_max_limit)
152             rect0h = y_max_scale(0);
153          else
154             rect0h = min(RSCALE(-dy), height - y_max_scale(dy));
155       }
156       else
157          rect0y = rect0h = 0;
158       if (ypos < y_min_limit && YPOS(height) - dy > y_min_limit) {
159          rect1y = max(RYPOS(y_min_limit + dy), 0);
160          if (ypos > y_min_limit + dy)
161             rect1h = RYPOS(y_min_limit);
162          else
163             rect1h = min(RSCALE(-dy), RSCALE(YPOS(height) - y_min_limit - dy));
164       }
165       else
166          rect1y = rect1h = 0;
167    }
168    if (dy) {
169       if (s == 0)
170          XFillRectangle(disp, lifew, cellgc[0], x0, rect0y, w0, rect0h);
171       else
172          XFillRectangle(disp, lifew, cellgc[GRID_COLOR], x1, rect1y, w1, rect1h);
173    }
174    if (dx) {
175       if (s == 0)
176          XFillRectangle(disp, lifew, cellgc[0], rect0x, y0, rect0w, h0);
177       else
178          XFillRectangle(disp, lifew, cellgc[GRID_COLOR], rect1x, y1, rect1w, h1);
179    }
180    if (dx && dy) {
181       if (s == 0)
182          XFillRectangle(disp, lifew, cellgc[0], rect0x, rect0y, rect0w, rect0h);
183       else
184          XFillRectangle(disp, lifew, cellgc[GRID_COLOR], rect1x, rect1y, rect1w,
185                                                                        rect1h);
186    }
187 }
188 
set_torus(coord_t x,coord_t y)189 static int set_torus(coord_t x, coord_t y) {
190     x = (x + 7 >> 3)*8;
191     y = (y + 7 >> 3)*8;
192     limits = x_min_limit = x_max_limit = y_min_limit = y_max_limit = 0;
193     if (x) {
194           x_min_limit = STARTX - (x - x%16)/2;
195           x_max_limit = STARTX + (x + x%16)/2;
196           limits = 1;
197     }
198     if (y) {
199           y_min_limit = STARTY - (y - y%16)/2;
200           y_max_limit = STARTY + (y + y%16)/2;
201           limits |= 2;
202     }
203     return limits;
204 }
205 
clr_tile_links(void)206 static void clr_tile_links(void) {
207    tile *ptr = active.tiles;
208    for (; ptr; ptr = ptr->next)
209       ptr->up = ptr->dn = ptr->lf = ptr-> rt = 0;
210 }
211 
set_topology(char * p)212 int set_topology(char *p) {
213        char s1[20], s2[20], t, c[2];
214        int x, y, dx = 0, dy = 0;
215 
216        clr_tile_links();
217        if (*p == 'Q')
218 l1:
219           return topology = 'Q', set_torus(0, 0);
220        if (*p == 'P' || *p == 'T') {
221           t = *p++;
222           if (*p == 0) return topology = t, 0;
223        }
224        else if ((t = topology) == 'Q')
225           return 12;
226        if (strlen(p) < 2) return 8;
227        if (sscanf(p, "%[0-9+-] %*[,*xX] %[0-9+-]", s1, s2) == 2) {
228           if (sscanf(s1, "%d %[+-] %d", &x, c, &dx) == 3) {
229              if (*c == '-') dx *= -1;
230           }
231           else if (sscanf(s1, "%d", &x) != 1)
232              return 5;
233           if (sscanf(s2, "%d %[+-] %d", &y, c, &dy) == 3) {
234              if (*c == '-') dy *= -1;
235           }
236           else if (sscanf(s2, "%d", &y) != 1) return 6;
237        }
238        else if (sscanf(p, "%*[,*xX] %[0-9+-]", s1) == 1) {
239           if (sscanf(s1, "%d %[+-] %d", &y, c, &dy) == 3) {
240              if (*c == '-') dy *= -1;
241           }
242           else if (sscanf(s1, "%d", &y) != 1)
243              return 5;
244           x = x_max_limit - x_min_limit;
245        }
246        else if (sscanf(p, "%[0-9+-] %*[,*xX]", s1) == 1) {
247           if (sscanf(s1, "%d %[+-] %d", &x, c, &dx) == 3) {
248              if (*c == '-') dx *= -1;
249           }
250           else if (sscanf(s1, "%d", &x) != 1)
251              return 4;
252           y = y_max_limit - y_min_limit;
253        }
254        else
255           return 11;
256        if (x == 0 && y == 0)
257           goto l1;
258        if (set_torus(x, y)) {
259           switch (t) {
260           case 'P':
261             if (dx != 0 || dy != 0) return 7;
262             break;
263           case 'T':
264             if (dx != 0 || dy != 0) {
265                strcpy(inpbuf, "Torus side shift is not supported");
266                return 8;
267             }
268           }
269           topology = t;
270           if (x%8 != 0 || y%8 != 0) {
271                sprintf(inpbuf, "Bounded grid size will be rounded to %dx%d",
272                        x_max_limit - x_min_limit, y_max_limit - y_min_limit);
273                announce_and_wait(GREEN_EVER);
274           }
275        }
276        return 0;
277 }
278 
279 #define conf_y()\
280       if (ypos < y_min_limit) {\
281          y1 = RYPOS(y_min_limit);\
282          if (YPOS(height) > y_max_limit)\
283             y2 = y_max_scale(0) - y1;\
284          else\
285             y2 = height - RYPOS(y_min_limit);\
286       }\
287       else {\
288          y1 = 0;\
289          if (YPOS(height) > y_max_limit)\
290             y2 = y_max_scale(0);\
291          else\
292             y2 = height;\
293       }\
294       XFillRectangle(disp, lifew, cellgc[GRID_COLOR], x1, y1, x2, y2);
295 
296 
drawboundedgrid(void)297 void drawboundedgrid(void) {
298    if (limits & 2) {
299       int x1 = 0, y1, x2, y2;
300       if (ypos < y_min_limit)
301          if (height <= RYPOS(y_min_limit))
302             goto FILLALL;
303          else
304             XFillRectangle(disp, lifew, cellgc[GRID_COLOR], 0, 0, width,
305                                                            RYPOS(y_min_limit));
306       if (YPOS(height) > y_max_limit)
307          if (y_max_limit > ypos)
308             XFillRectangle(disp, lifew, cellgc[GRID_COLOR], 0, y_max_scale(0),
309                                                 width, height - y_max_scale(0));
310          else
311             goto FILLALL;
312       if ((limits & 1) && YPOS(height) > y_min_limit && ypos < y_max_limit) {
313          if (xpos < x_min_limit) {
314             if (XPOS(width) < x_min_limit)
315                x2 = width;
316             else
317                x2 = RXPOS(x_min_limit);
318             conf_y();
319          }
320          if (XPOS(width) + 1 > x_max_limit) {
321             if (xpos > x_max_limit)
322                x2 = width;
323             else {
324                x1 = x_max_scale(0);
325                x2 = width - x_max_scale(0);
326             }
327             conf_y();
328          }
329       }
330    }
331    else if (limits) {
332       if (xpos < x_min_limit)
333          XFillRectangle(disp, lifew, cellgc[GRID_COLOR], 0, 0,
334                                        min(width, RYPOS(x_min_limit)), height);
335       if (XPOS(width) > x_max_limit)
336          if (x_max_limit > xpos)
337             XFillRectangle(disp, lifew, cellgc[GRID_COLOR], x_max_scale(0), 0,
338                                                 width - x_max_scale(0), height);
339          else
340 FILLALL:
341             XFillRectangle(disp, lifew, cellgc[GRID_COLOR], 0, 0, width,
342                                                                        height);
343    }
344 }
345