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