1 | /* piecewise, 21jan2003 |
---|
2 | * Geoffrey Irving <irving@caltech.edu> |
---|
3 | * |
---|
4 | * Permission to use, copy, modify, distribute, and sell this software and its |
---|
5 | * documentation for any purpose is hereby granted without fee, provided that |
---|
6 | * the above copyright notice appear in all copies and that both that |
---|
7 | * copyright notice and this permission notice appear in supporting |
---|
8 | * documentation. No representations are made about the suitability of this |
---|
9 | * software for any purpose. It is provided "as is" without express or |
---|
10 | * implied warranty. |
---|
11 | */ |
---|
12 | |
---|
13 | #include <stdarg.h> |
---|
14 | #include <math.h> |
---|
15 | #include "screenhack.h" |
---|
16 | |
---|
17 | #ifdef HAVE_DOUBLE_BUFFER_EXTENSION |
---|
18 | # include "xdbe.h" |
---|
19 | #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ |
---|
20 | |
---|
21 | #define X_PI (180 * 64) |
---|
22 | |
---|
23 | /******** splaying code */ |
---|
24 | |
---|
25 | typedef struct _tree { |
---|
26 | struct _tree *l, *r; /* left and right children */ |
---|
27 | /* extra stuff would go here */ |
---|
28 | } tree; |
---|
29 | |
---|
30 | typedef int (*cut)(tree*); /* cut x is <, =, or > 0 given a <, =, or > x for some a */ |
---|
31 | |
---|
32 | /* Top-down splay routine. Reference: |
---|
33 | * "Self-adjusting Binary Search Trees", Sleator and Tarjan, |
---|
34 | * JACM Volume 32, No 3, July 1985, pp 652-686. |
---|
35 | * See page 668 for specific splay transformations */ |
---|
36 | |
---|
37 | tree *splay(cut c, tree *t) { |
---|
38 | int v, vv; |
---|
39 | tree *l, *r; |
---|
40 | tree **lr, **rl; |
---|
41 | tree *x, *y, *z; |
---|
42 | |
---|
43 | if (!t) |
---|
44 | return 0; |
---|
45 | |
---|
46 | /* initialization */ |
---|
47 | x = t; |
---|
48 | l = r = 0; |
---|
49 | lr = &l; |
---|
50 | rl = &r; |
---|
51 | |
---|
52 | /* top-down splaying loop */ |
---|
53 | for (;;) { |
---|
54 | v = c(x); |
---|
55 | if (v == 0) |
---|
56 | break; /*** success ***/ |
---|
57 | else if (v < 0) { |
---|
58 | y = x->l; |
---|
59 | if (!y) |
---|
60 | break; /*** trivial ***/ |
---|
61 | else { |
---|
62 | vv = c(y); |
---|
63 | if (vv == 0) { |
---|
64 | *rl = x; /*** zig ***/ |
---|
65 | rl = &x->l; |
---|
66 | x = y; |
---|
67 | break; |
---|
68 | } |
---|
69 | else if (vv < 0) { |
---|
70 | z = y->l; |
---|
71 | if (!z) { |
---|
72 | *rl = x; /*** zig ***/ |
---|
73 | rl = &x->l; |
---|
74 | x = y; |
---|
75 | break; |
---|
76 | } |
---|
77 | else { |
---|
78 | x->l = y->r; /*** zig-zig ***/ |
---|
79 | y->r = x; |
---|
80 | *rl = y; |
---|
81 | rl = &y->l; |
---|
82 | x = z; |
---|
83 | } |
---|
84 | } |
---|
85 | else { /* vv > 0 */ |
---|
86 | z = y->r; |
---|
87 | if (!z) { |
---|
88 | *rl = x; /*** zig ***/ |
---|
89 | rl = &x->l; |
---|
90 | x = y; |
---|
91 | break; |
---|
92 | } |
---|
93 | else { /*** zig-zag ***/ |
---|
94 | *lr = y; |
---|
95 | lr = &y->r; |
---|
96 | *rl = x; |
---|
97 | rl = &x->l; |
---|
98 | x = z; |
---|
99 | } |
---|
100 | } |
---|
101 | } |
---|
102 | } |
---|
103 | else { /* v > 0 */ |
---|
104 | y = x->r; |
---|
105 | if (!y) |
---|
106 | break; /*** trivial ***/ |
---|
107 | else { |
---|
108 | vv = c(y); |
---|
109 | if (vv == 0) { |
---|
110 | *lr = x; /*** zig ***/ |
---|
111 | lr = &x->r; |
---|
112 | x = y; |
---|
113 | break; |
---|
114 | } |
---|
115 | else if (vv > 0) { |
---|
116 | z = y->r; |
---|
117 | if (!z) { |
---|
118 | *lr = x; /*** zig ***/ |
---|
119 | lr = &x->r; |
---|
120 | x = y; |
---|
121 | break; |
---|
122 | } |
---|
123 | else { |
---|
124 | x->r = y->l; /*** zig-zig ***/ |
---|
125 | y->l = x; |
---|
126 | *lr = y; |
---|
127 | lr = &y->r; |
---|
128 | x = z; |
---|
129 | } |
---|
130 | } |
---|
131 | else { /* vv < 0 */ |
---|
132 | z = y->l; |
---|
133 | if (!z) { |
---|
134 | *lr = x; /*** zig ***/ |
---|
135 | lr = &x->r; |
---|
136 | x = y; |
---|
137 | break; |
---|
138 | } |
---|
139 | else { /*** zig-zag ***/ |
---|
140 | *rl = y; |
---|
141 | rl = &y->l; |
---|
142 | *lr = x; |
---|
143 | lr = &x->r; |
---|
144 | x = z; |
---|
145 | } |
---|
146 | } |
---|
147 | } |
---|
148 | } |
---|
149 | } |
---|
150 | |
---|
151 | /* completion */ |
---|
152 | *lr = x->l; |
---|
153 | x->l = l; |
---|
154 | *rl = x->r; |
---|
155 | x->r = r; |
---|
156 | return x; |
---|
157 | } |
---|
158 | |
---|
159 | tree *splay_min(tree *t) { |
---|
160 | tree *r, **rl; |
---|
161 | tree *x, *y, *z; |
---|
162 | |
---|
163 | if (!t) |
---|
164 | return 0; |
---|
165 | |
---|
166 | x = t; |
---|
167 | r = 0; |
---|
168 | rl = &r; |
---|
169 | |
---|
170 | for (;;) { |
---|
171 | y = x->l; |
---|
172 | if (!y) |
---|
173 | break; /*** trivial ***/ |
---|
174 | else { |
---|
175 | z = y->l; |
---|
176 | if (!z) { |
---|
177 | *rl = x; /*** zig ***/ |
---|
178 | rl = &x->l; |
---|
179 | x = y; |
---|
180 | break; |
---|
181 | } |
---|
182 | else { |
---|
183 | x->l = y->r; /*** zig-zig ***/ |
---|
184 | y->r = x; |
---|
185 | *rl = y; |
---|
186 | rl = &y->l; |
---|
187 | x = z; |
---|
188 | } |
---|
189 | } |
---|
190 | } |
---|
191 | |
---|
192 | x->l = 0; |
---|
193 | *rl = x->r; |
---|
194 | x->r = r; |
---|
195 | return x; |
---|
196 | } |
---|
197 | |
---|
198 | tree *splay_max(tree *t) { |
---|
199 | tree *l, **lr; |
---|
200 | tree *x, *y, *z; |
---|
201 | |
---|
202 | if (!t) |
---|
203 | return 0; |
---|
204 | |
---|
205 | x = t; |
---|
206 | l = 0; |
---|
207 | lr = &l; |
---|
208 | |
---|
209 | for (;;) { |
---|
210 | y = x->r; |
---|
211 | if (!y) |
---|
212 | break; /*** trivial ***/ |
---|
213 | else { |
---|
214 | z = y->r; |
---|
215 | if (!z) { |
---|
216 | *lr = x; /*** zig ***/ |
---|
217 | lr = &x->r; |
---|
218 | x = y; |
---|
219 | break; |
---|
220 | } |
---|
221 | else { |
---|
222 | x->r = y->l; /*** zig-zig ***/ |
---|
223 | y->l = x; |
---|
224 | *lr = y; |
---|
225 | lr = &y->r; |
---|
226 | x = z; |
---|
227 | } |
---|
228 | } |
---|
229 | } |
---|
230 | |
---|
231 | *lr = x->l; |
---|
232 | x->l = l; |
---|
233 | x->r = 0; |
---|
234 | return x; |
---|
235 | } |
---|
236 | |
---|
237 | /******** circles and fringe */ |
---|
238 | |
---|
239 | struct _fringe; |
---|
240 | |
---|
241 | typedef struct _circle { |
---|
242 | int r; /* radius */ |
---|
243 | double x, y; /* position */ |
---|
244 | double dx, dy; /* velocity */ |
---|
245 | |
---|
246 | int visible; /* default visibility */ |
---|
247 | struct _fringe *lo, *hi; /* lo and hi fringes */ |
---|
248 | |
---|
249 | int ni; /* number of intersections */ |
---|
250 | int *i; /* sorted intersection list */ |
---|
251 | } circle; |
---|
252 | |
---|
253 | typedef struct _fringe { |
---|
254 | struct _fringe *l, *r; /* left and right children for splay trees */ |
---|
255 | |
---|
256 | circle *c; /* associated circle */ |
---|
257 | int side; /* 0 for lo, 1 for hi */ |
---|
258 | |
---|
259 | int mni; /* size of intersection array */ |
---|
260 | int ni; /* number of intersections */ |
---|
261 | int *i; /* sorted intersection list */ |
---|
262 | } fringe; |
---|
263 | |
---|
264 | inline double fringe_x(fringe *f, double y) { |
---|
265 | double dy, d; |
---|
266 | dy = f->c->y - y; |
---|
267 | d = sqrt(f->c->r * f->c->r - dy * dy); |
---|
268 | return f->side ? f->c->x + d : f->c->x - d; |
---|
269 | } |
---|
270 | |
---|
271 | inline void fringe_add_intersection(fringe *f, double x, double y) { |
---|
272 | f->ni++; |
---|
273 | if (f->mni < f->ni) { |
---|
274 | f->mni += 2; |
---|
275 | f->i = realloc(f->i, sizeof(int) * f->mni); |
---|
276 | } |
---|
277 | f->i[f->ni-1] = rint(atan2(y - f->c->y, x - f->c->x) * X_PI / M_PI); |
---|
278 | } |
---|
279 | |
---|
280 | circle *init_circles(int n, int w, int h) { |
---|
281 | int i, r0, dr, speed; |
---|
282 | double v, a; |
---|
283 | double minradius, maxradius; |
---|
284 | fringe *s = malloc(sizeof(fringe) * n * 2); /* never freed */ |
---|
285 | circle *c = malloc(sizeof(circle) * n); |
---|
286 | |
---|
287 | speed = get_integer_resource("speed", "Speed"); |
---|
288 | minradius = get_float_resource("minradius", "Float"); |
---|
289 | maxradius = get_float_resource("maxradius", "Float"); |
---|
290 | if (maxradius < minradius) |
---|
291 | maxradius = minradius; |
---|
292 | |
---|
293 | r0 = ceil(minradius * h); |
---|
294 | dr = floor(maxradius * h) - r0 + 1; |
---|
295 | |
---|
296 | for (i=0;i<n;i++) { |
---|
297 | c[i].r = r0 + random() % dr; |
---|
298 | c[i].x = c[i].r + frand(w - 1 - 2 * c[i].r); |
---|
299 | c[i].y = c[i].r + frand(h - 1 - 2 * c[i].r); |
---|
300 | c[i].visible = random() & 1; |
---|
301 | |
---|
302 | c[i].ni = 0; |
---|
303 | c[i].i = 0; |
---|
304 | |
---|
305 | a = frand(2 * M_PI); |
---|
306 | v = (1 + frand(0.5)) * speed / 10.0; |
---|
307 | c[i].dx = v * cos(a); |
---|
308 | c[i].dy = v * sin(a); |
---|
309 | |
---|
310 | c[i].lo = s+i+i; |
---|
311 | c[i].hi = s+i+i+1; |
---|
312 | c[i].lo->c = c[i].hi->c = c+i; |
---|
313 | c[i].lo->side = 0; |
---|
314 | c[i].hi->side = 1; |
---|
315 | c[i].lo->mni = c[i].lo->ni = c[i].hi->mni = c[i].hi->ni = 0; |
---|
316 | c[i].lo->i = c[i].hi->i = 0; |
---|
317 | } |
---|
318 | |
---|
319 | return c; |
---|
320 | } |
---|
321 | |
---|
322 | /* this is a hack, but I guess that's what I writing anyways */ |
---|
323 | void tweak_circle(circle *c) { |
---|
324 | c->x += frand(2) - 1; |
---|
325 | c->y += frand(1) + 0.1; |
---|
326 | } |
---|
327 | |
---|
328 | void move_circle(circle *c, int w, int h) { |
---|
329 | c->x += c->dx; |
---|
330 | if (c->x < c->r) { |
---|
331 | c->x = c->r; |
---|
332 | c->dx = -c->dx; |
---|
333 | } |
---|
334 | else if (c->x >= w - c->r) { |
---|
335 | c->x = w - 1 - c->r; |
---|
336 | c->dx = -c->dx; |
---|
337 | } |
---|
338 | c->y += c->dy; |
---|
339 | if (c->y < c->r) { |
---|
340 | c->y = c->r; |
---|
341 | c->dy = -c->dy; |
---|
342 | } |
---|
343 | else if (c->y >= h - c->r) { |
---|
344 | c->y = h - 1 - c->r; |
---|
345 | c->dy = -c->dy; |
---|
346 | } |
---|
347 | } |
---|
348 | |
---|
349 | /******** event queue */ |
---|
350 | |
---|
351 | #define START 0 |
---|
352 | #define CROSS 1 |
---|
353 | #define FINISH 2 |
---|
354 | |
---|
355 | typedef struct _event { |
---|
356 | struct _event *l, *r; /* left and right children for splay tree */ |
---|
357 | |
---|
358 | int kind; /* type of event */ |
---|
359 | double x, y; /* position */ |
---|
360 | fringe *lo, *hi; /* fringes */ |
---|
361 | } event; |
---|
362 | |
---|
363 | static double event_cut_y; |
---|
364 | |
---|
365 | int event_cut(event *e) { |
---|
366 | return event_cut_y == e->y ? 0 : event_cut_y < e->y ? -1 : 1; |
---|
367 | } |
---|
368 | |
---|
369 | void event_insert(event **eq, event *e) { |
---|
370 | if (!*eq) { |
---|
371 | e->l = e->r = 0; |
---|
372 | *eq = e; |
---|
373 | } |
---|
374 | |
---|
375 | event_cut_y = e->y; |
---|
376 | *eq = (event*)splay((cut)event_cut, (tree*)*eq); |
---|
377 | |
---|
378 | if (e->y == (*eq)->y) { |
---|
379 | if (!((e->lo == (*eq)->lo && e->hi == (*eq)->hi) || (e->lo == (*eq)->hi && e->hi == (*eq)->lo))) { |
---|
380 | e->l = (*eq)->l; |
---|
381 | e->r = 0; /* doing this instead of dying might be dangerous */ |
---|
382 | (*eq)->l = e; |
---|
383 | } |
---|
384 | } |
---|
385 | else if (e->y < (*eq)->y) { |
---|
386 | e->l = (*eq)->l; |
---|
387 | e->r = *eq; |
---|
388 | (*eq)->l = 0; |
---|
389 | *eq = e; |
---|
390 | } |
---|
391 | else { |
---|
392 | e->l = *eq; |
---|
393 | e->r = (*eq)->r; |
---|
394 | (*eq)->r = 0; |
---|
395 | *eq = e; |
---|
396 | } |
---|
397 | } |
---|
398 | |
---|
399 | void circle_start_event(event **eq, circle *c) { |
---|
400 | event *s; |
---|
401 | s = malloc(sizeof(event)); |
---|
402 | s->kind = START; |
---|
403 | s->x = c->x; |
---|
404 | s->y = c->y - c->r; |
---|
405 | s->lo = c->lo; |
---|
406 | s->hi = c->hi; |
---|
407 | event_insert(eq, s); |
---|
408 | } |
---|
409 | |
---|
410 | void circle_finish_event(event **eq, circle *c) { |
---|
411 | event *f; |
---|
412 | f = malloc(sizeof(event)); |
---|
413 | f->kind = FINISH; |
---|
414 | f->x = c->x; |
---|
415 | f->y = c->y + c->r; |
---|
416 | f->lo = c->lo; |
---|
417 | f->hi = c->hi; |
---|
418 | event_insert(eq, f); |
---|
419 | } |
---|
420 | |
---|
421 | event *event_next(event **eq) { |
---|
422 | event *e; |
---|
423 | if (!*eq) |
---|
424 | return 0; |
---|
425 | else { |
---|
426 | e = (event*)splay_min((tree*)*eq); |
---|
427 | *eq = e->r; |
---|
428 | return e; |
---|
429 | } |
---|
430 | } |
---|
431 | |
---|
432 | void event_shred(event *e) { |
---|
433 | if (e) { |
---|
434 | event_shred(e->l); |
---|
435 | event_shred(e->r); |
---|
436 | free(e); |
---|
437 | } |
---|
438 | } |
---|
439 | |
---|
440 | /******** fringe intersection */ |
---|
441 | |
---|
442 | inline int check_fringe_intersection(double ye, fringe *lo, fringe *hi, double x, double y) { |
---|
443 | return ye <= y && ((x < lo->c->x) ^ lo->side) && ((x < hi->c->x) ^ hi->side); |
---|
444 | } |
---|
445 | |
---|
446 | void fringe_intersect(event **eq, double y, fringe *lo, fringe *hi) { |
---|
447 | event *e; |
---|
448 | double dx, dy, sd, rs, rd, d, sx, sy, rp, sqd; |
---|
449 | double x1, y1, x2, y2; |
---|
450 | |
---|
451 | if (lo->c == hi->c) |
---|
452 | return; |
---|
453 | |
---|
454 | dx = hi->c->x - lo->c->x; |
---|
455 | dy = hi->c->y - lo->c->y; |
---|
456 | sd = dx * dx + dy * dy; |
---|
457 | |
---|
458 | if (sd == 0) |
---|
459 | return; |
---|
460 | |
---|
461 | rs = hi->c->r + lo->c->r; |
---|
462 | rd = hi->c->r - lo->c->r; |
---|
463 | d = (rd * rd - sd) * (sd - rs * rs); |
---|
464 | |
---|
465 | if (d <= 0) |
---|
466 | return; |
---|
467 | |
---|
468 | sd = 0.5 / sd; |
---|
469 | rp = rs * rd; |
---|
470 | sqd = sqrt(d); |
---|
471 | sx = (lo->c->x + hi->c->x) / 2; |
---|
472 | sy = (lo->c->y + hi->c->y) / 2; |
---|
473 | x1 = sx + sd * (dy * sqd - dx * rp); |
---|
474 | y1 = sy - sd * (dx * sqd + dy * rp); |
---|
475 | x2 = sx - sd * (dy * sqd + dx * rp); |
---|
476 | y2 = sy + sd * (dx * sqd - dy * rp); |
---|
477 | |
---|
478 | #define CHECK(xi, yi) (y <= yi && ((xi < lo->c->x) ^ lo->side) && ((xi < hi->c->x) ^ hi->side)) |
---|
479 | |
---|
480 | #define ADD_CROSS(xi, yi, ilo, ihi) { \ |
---|
481 | e = malloc(sizeof(event)); \ |
---|
482 | e->kind = CROSS; \ |
---|
483 | e->x = xi; e->y = yi; \ |
---|
484 | e->lo = ilo; e->hi = ihi; \ |
---|
485 | event_insert(eq, e); \ |
---|
486 | } |
---|
487 | |
---|
488 | if (CHECK(x1, y1)) { |
---|
489 | if (CHECK(x2, y2)) { |
---|
490 | if (y1 < y2) { |
---|
491 | ADD_CROSS(x1, y1, lo, hi); |
---|
492 | ADD_CROSS(x2, y2, hi, lo); |
---|
493 | } |
---|
494 | else { |
---|
495 | ADD_CROSS(x1, y1, hi, lo); |
---|
496 | ADD_CROSS(x2, y2, lo, hi); |
---|
497 | } |
---|
498 | } |
---|
499 | else |
---|
500 | ADD_CROSS(x1, y1, lo, hi); |
---|
501 | } |
---|
502 | else if (CHECK(x2, y2)) |
---|
503 | ADD_CROSS(x2, y2, lo, hi); |
---|
504 | |
---|
505 | return; |
---|
506 | } |
---|
507 | |
---|
508 | /******** fringe trees and event handling */ |
---|
509 | |
---|
510 | #define PANIC ((fringe*)1) /* by alignment, no fringe should every be 1 */ |
---|
511 | |
---|
512 | fringe *check_lo(event **eq, double y, fringe *f, fringe *hi) { |
---|
513 | if (f) { |
---|
514 | f = (fringe*)splay_max((tree*)f); |
---|
515 | fringe_intersect(eq, y, f, hi); |
---|
516 | } |
---|
517 | return f; |
---|
518 | } |
---|
519 | |
---|
520 | fringe *check_hi(event **eq, double y, fringe *lo, fringe *f) { |
---|
521 | if (f) { |
---|
522 | f = (fringe*)splay_min((tree*)f); |
---|
523 | fringe_intersect(eq, y, lo, f); |
---|
524 | } |
---|
525 | return f; |
---|
526 | } |
---|
527 | |
---|
528 | double fringe_start_cut_x; |
---|
529 | double fringe_start_cut_y; |
---|
530 | |
---|
531 | int fringe_start_cut(fringe *f) { |
---|
532 | double x = fringe_x(f, fringe_start_cut_y); |
---|
533 | return fringe_start_cut_x == x ? 0 : fringe_start_cut_x < x ? -1 : 1; |
---|
534 | } |
---|
535 | |
---|
536 | fringe *fringe_start(event **eq, fringe *f, double x, double y, fringe *lo, fringe *hi) { |
---|
537 | double sx; |
---|
538 | |
---|
539 | if (!f) { |
---|
540 | circle_finish_event(eq, lo->c); |
---|
541 | lo->l = 0; |
---|
542 | lo->r = hi; |
---|
543 | hi->l = hi->r = 0; |
---|
544 | return lo; |
---|
545 | } |
---|
546 | |
---|
547 | fringe_start_cut_x = x; |
---|
548 | fringe_start_cut_y = y; |
---|
549 | f = (fringe*)splay((cut)fringe_start_cut, (tree*)f); |
---|
550 | |
---|
551 | sx = fringe_x(f, y); |
---|
552 | if (x == sx) { /* time to cheat my way out of handling degeneracies */ |
---|
553 | tweak_circle(lo->c); |
---|
554 | circle_start_event(eq, lo->c); |
---|
555 | return f; |
---|
556 | } |
---|
557 | else if (x < sx) { |
---|
558 | circle_finish_event(eq, lo->c); |
---|
559 | f->l = check_lo(eq, y, f->l, lo); |
---|
560 | fringe_intersect(eq, y, hi, f); |
---|
561 | lo->l = f->l; |
---|
562 | lo->r = f; |
---|
563 | f->l = hi; |
---|
564 | hi->l = hi->r = 0; |
---|
565 | return lo; |
---|
566 | } |
---|
567 | else { |
---|
568 | circle_finish_event(eq, lo->c); |
---|
569 | fringe_intersect(eq, y, f, lo); |
---|
570 | f->r = check_hi(eq, y, hi, f->r); |
---|
571 | hi->r = f->r; |
---|
572 | hi->l = f; |
---|
573 | f->r = lo; |
---|
574 | lo->l = lo->r = 0; |
---|
575 | return hi; |
---|
576 | } |
---|
577 | } |
---|
578 | |
---|
579 | double fringe_double_cut_x; |
---|
580 | double fringe_double_cut_y; |
---|
581 | fringe *fringe_double_cut_lo; |
---|
582 | fringe *fringe_double_cut_hi; |
---|
583 | |
---|
584 | int fringe_double_cut(fringe *f) { |
---|
585 | double x; |
---|
586 | if (f == fringe_double_cut_lo || f == fringe_double_cut_hi) |
---|
587 | return 0; |
---|
588 | x = fringe_x(f, fringe_double_cut_y); |
---|
589 | return fringe_double_cut_x == x ? 0 : fringe_double_cut_x < x ? -1 : 1; |
---|
590 | } |
---|
591 | |
---|
592 | int fringe_double_splay(fringe *f, double x, double y, fringe *lo, fringe *hi) { |
---|
593 | fringe_double_cut_x = x; |
---|
594 | fringe_double_cut_y = y; |
---|
595 | fringe_double_cut_lo = lo; |
---|
596 | fringe_double_cut_hi = hi; |
---|
597 | f = (fringe*)splay((cut)fringe_double_cut, (tree*)f); |
---|
598 | |
---|
599 | if (f == lo) |
---|
600 | return (f->r = (fringe*)splay_min((tree*)f->r)) == hi; |
---|
601 | else if (f == hi) |
---|
602 | return (f->l = (fringe*)splay_max((tree*)f->l)) == lo; |
---|
603 | else |
---|
604 | return 0; |
---|
605 | } |
---|
606 | |
---|
607 | fringe *fringe_cross(event **eq, fringe *f, double x, double y, fringe *lo, fringe *hi) { |
---|
608 | fringe *l, *r; |
---|
609 | if (!fringe_double_splay(f, x, y, lo, hi)) |
---|
610 | return PANIC; |
---|
611 | l = check_lo(eq, y, lo->l, hi); |
---|
612 | r = check_hi(eq, y, lo, hi->r); |
---|
613 | lo->l = hi; |
---|
614 | lo->r = r; |
---|
615 | hi->l = l; |
---|
616 | hi->r = 0; |
---|
617 | return lo; |
---|
618 | } |
---|
619 | |
---|
620 | fringe *fringe_finish(event **eq, fringe *f, double x, double y, fringe *lo, fringe *hi) { |
---|
621 | if (!fringe_double_splay(f, x, y, lo, hi)) |
---|
622 | return PANIC; |
---|
623 | else if (!lo->l) |
---|
624 | return hi->r; |
---|
625 | else if (!hi->r) |
---|
626 | return lo->l; |
---|
627 | else { |
---|
628 | lo->l = (fringe*)splay_max((tree*)lo->l); |
---|
629 | hi->r = (fringe*)splay_min((tree*)hi->r); |
---|
630 | fringe_intersect(eq, y, lo->l, hi->r); |
---|
631 | lo->l->r = hi->r; |
---|
632 | hi->r->l = 0; |
---|
633 | return lo->l; |
---|
634 | } |
---|
635 | } |
---|
636 | |
---|
637 | /******** plane sweep */ |
---|
638 | |
---|
639 | void sweep(int n, circle *c) { |
---|
640 | int i; |
---|
641 | event *eq, *e; |
---|
642 | fringe *f; |
---|
643 | |
---|
644 | RESTART: |
---|
645 | #define CHECK_PANIC() \ |
---|
646 | if (f == PANIC) { \ |
---|
647 | free(e); \ |
---|
648 | event_shred(eq); \ |
---|
649 | for (i=0;i<n;i++) { \ |
---|
650 | tweak_circle(c+i); \ |
---|
651 | c[i].lo->ni = c[i].hi->ni = 0; \ |
---|
652 | } \ |
---|
653 | goto RESTART; \ |
---|
654 | } |
---|
655 | |
---|
656 | eq = 0; |
---|
657 | for (i=0;i<n;i++) |
---|
658 | circle_start_event(&eq, c+i); |
---|
659 | f = 0; |
---|
660 | |
---|
661 | while ((e = event_next(&eq))) { |
---|
662 | switch (e->kind) { |
---|
663 | case START: |
---|
664 | f = fringe_start(&eq, f, e->x, e->y, e->lo, e->hi); |
---|
665 | break; |
---|
666 | case CROSS: |
---|
667 | f = fringe_cross(&eq, f, e->x, e->y, e->lo, e->hi); |
---|
668 | CHECK_PANIC(); |
---|
669 | fringe_add_intersection(e->lo, e->x, e->y); |
---|
670 | fringe_add_intersection(e->hi, e->x, e->y); |
---|
671 | break; |
---|
672 | case FINISH: |
---|
673 | f = fringe_finish(&eq, f, e->x, e->y, e->lo, e->hi); |
---|
674 | CHECK_PANIC(); |
---|
675 | break; |
---|
676 | } |
---|
677 | free(e); |
---|
678 | } |
---|
679 | } |
---|
680 | |
---|
681 | /******** circle drawing */ |
---|
682 | |
---|
683 | void adjust_circle_visibility(circle *c) { |
---|
684 | int i, j, n, a; |
---|
685 | int *in; |
---|
686 | n = c->lo->ni + c->hi->ni; |
---|
687 | in = malloc(sizeof(int) * n); |
---|
688 | for (i=0;i<c->hi->ni;i++) |
---|
689 | in[i] = c->hi->i[i]; |
---|
690 | for (i=c->lo->ni-1;i>=0;i--) |
---|
691 | in[n-i-1] = c->lo->i[i] > 0 ? c->lo->i[i] : c->lo->i[i] + 2 * X_PI; |
---|
692 | c->lo->ni = c->hi->ni = 0; |
---|
693 | |
---|
694 | i = j = 0; |
---|
695 | a = 0; |
---|
696 | while (i < n && j < c->ni) /* whee */ |
---|
697 | a = (in[i] < c->i[j] ? in[i++] : c->i[j++]) - a; |
---|
698 | while (i < n) |
---|
699 | a = in[i++] - a; |
---|
700 | while (j < c->ni) |
---|
701 | a = c->i[j++] - a; |
---|
702 | |
---|
703 | if (a > X_PI) |
---|
704 | c->visible = !c->visible; |
---|
705 | free(c->i); |
---|
706 | c->ni = n; |
---|
707 | c->i = in; |
---|
708 | } |
---|
709 | |
---|
710 | #define ARC_BUFFER_SIZE 256 |
---|
711 | int arc_buffer_count = 0; |
---|
712 | XArc arc_buffer[ARC_BUFFER_SIZE]; |
---|
713 | |
---|
714 | void flush_arc_buffer(Display *dpy, Drawable w, GC gc) { |
---|
715 | if (arc_buffer_count) { |
---|
716 | XDrawArcs(dpy, w, gc, arc_buffer, arc_buffer_count); |
---|
717 | arc_buffer_count = 0; |
---|
718 | } |
---|
719 | } |
---|
720 | |
---|
721 | void draw_circle(Display *dpy, Drawable w, GC gc, circle *c) { |
---|
722 | int i, xi, yi, di; |
---|
723 | adjust_circle_visibility(c); |
---|
724 | |
---|
725 | xi = rint(c->x - c->r); |
---|
726 | yi = rint(c->y - c->r); |
---|
727 | di = c->r << 1; |
---|
728 | |
---|
729 | #define ARC(p, a1, a2) { \ |
---|
730 | if (((p) & 1) ^ c->visible) { \ |
---|
731 | arc_buffer[arc_buffer_count].x = xi; \ |
---|
732 | arc_buffer[arc_buffer_count].y = yi; \ |
---|
733 | arc_buffer[arc_buffer_count].width = di; \ |
---|
734 | arc_buffer[arc_buffer_count].height = di; \ |
---|
735 | arc_buffer[arc_buffer_count].angle1 = -(a1); \ |
---|
736 | arc_buffer[arc_buffer_count].angle2 = (a1) - (a2); \ |
---|
737 | arc_buffer_count++; \ |
---|
738 | if (arc_buffer_count == ARC_BUFFER_SIZE) \ |
---|
739 | flush_arc_buffer(dpy, w, gc); \ |
---|
740 | } \ |
---|
741 | } |
---|
742 | |
---|
743 | if (!c->ni) |
---|
744 | ARC(0, 0, 2 * X_PI) |
---|
745 | else |
---|
746 | ARC(0, c->i[c->ni-1], c->i[0] + 2 * X_PI) |
---|
747 | for (i=1;i<c->ni;i++) |
---|
748 | ARC(i, c->i[i-1], c->i[i]) |
---|
749 | } |
---|
750 | |
---|
751 | /******** toplevel */ |
---|
752 | |
---|
753 | char *progclass = "Piecewise"; |
---|
754 | |
---|
755 | char *defaults [] = { |
---|
756 | ".background: black", |
---|
757 | ".foreground: white", |
---|
758 | "*delay: 5000", |
---|
759 | "*speed: 15", |
---|
760 | "*ncolors: 256", |
---|
761 | ".colorspeed: 10", |
---|
762 | |
---|
763 | ".count: 32", |
---|
764 | ".minradius: 0.05", |
---|
765 | ".maxradius: 0.2", |
---|
766 | |
---|
767 | "*doubleBuffer: True", |
---|
768 | #ifdef HAVE_DOUBLE_BUFFER_EXTENSION |
---|
769 | "*useDBE: True", |
---|
770 | #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ |
---|
771 | 0 |
---|
772 | }; |
---|
773 | |
---|
774 | XrmOptionDescRec options [] = { |
---|
775 | { "-delay", ".delay", XrmoptionSepArg, 0 }, |
---|
776 | { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, |
---|
777 | { "-speed", ".speed", XrmoptionSepArg, 0 }, |
---|
778 | { "-colorspeed", ".colorspeed", XrmoptionSepArg, 0 }, |
---|
779 | |
---|
780 | { "-count", ".count", XrmoptionSepArg, 0 }, |
---|
781 | { "-minradius", ".minradius", XrmoptionSepArg, 0 }, |
---|
782 | { "-maxradius", ".maxradius", XrmoptionSepArg, 0 }, |
---|
783 | |
---|
784 | { "-db", ".doubleBuffer", XrmoptionNoArg, "True" }, |
---|
785 | { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" }, |
---|
786 | { 0, 0, 0, 0 } |
---|
787 | }; |
---|
788 | |
---|
789 | void screenhack(Display *dpy, Window window) { |
---|
790 | int i; |
---|
791 | Bool dbuf; |
---|
792 | XColor *colors; |
---|
793 | XGCValues gcv; |
---|
794 | GC erase_gc, draw_gc; |
---|
795 | XWindowAttributes xgwa; |
---|
796 | Pixmap b = 0, ba = 0, bb = 0; /* double-buffering pixmap */ |
---|
797 | |
---|
798 | #ifdef HAVE_DOUBLE_BUFFER_EXTENSION |
---|
799 | XdbeBackBuffer backb = 0; |
---|
800 | #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ |
---|
801 | |
---|
802 | int count, delay, ncolors, colorspeed, color_index, flags, iterations; |
---|
803 | int color_iterations; |
---|
804 | circle *circles; |
---|
805 | |
---|
806 | count = get_integer_resource("count", "Integer"); |
---|
807 | delay = get_integer_resource("delay", "Integer"); |
---|
808 | ncolors = get_integer_resource("ncolors", "Integer"); |
---|
809 | colorspeed = get_integer_resource("colorspeed", "Integer"); |
---|
810 | dbuf = get_boolean_resource("doubleBuffer", "Boolean"); |
---|
811 | |
---|
812 | color_iterations = colorspeed ? 100 / colorspeed : 100000; |
---|
813 | if (!color_iterations) |
---|
814 | color_iterations = 1; |
---|
815 | |
---|
816 | XGetWindowAttributes(dpy, window, &xgwa); |
---|
817 | colors = calloc(sizeof(XColor), ncolors); |
---|
818 | |
---|
819 | if (get_boolean_resource("mono", "Boolean")) { |
---|
820 | MONO: |
---|
821 | ncolors = 1; |
---|
822 | colors[0].pixel = get_pixel_resource("foreground", "Foreground", dpy, xgwa.colormap); |
---|
823 | } |
---|
824 | else { |
---|
825 | make_color_loop(dpy, xgwa.colormap, 0, 1, 1, 120, 1, 1, 240, 1, 1, colors, &ncolors, True, False); |
---|
826 | if (ncolors < 2) |
---|
827 | goto MONO; |
---|
828 | } |
---|
829 | |
---|
830 | if (dbuf) { |
---|
831 | #ifdef HAVE_DOUBLE_BUFFER_EXTENSION |
---|
832 | b = backb = xdbe_get_backbuffer(dpy, window, XdbeUndefined); |
---|
833 | #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ |
---|
834 | |
---|
835 | if (!b) { |
---|
836 | ba = XCreatePixmap(dpy, window, xgwa.width, xgwa.height,xgwa.depth); |
---|
837 | bb = XCreatePixmap(dpy, window, xgwa.width, xgwa.height,xgwa.depth); |
---|
838 | b = ba; |
---|
839 | } |
---|
840 | } |
---|
841 | else |
---|
842 | b = window; |
---|
843 | |
---|
844 | /* erasure gc */ |
---|
845 | gcv.foreground = get_pixel_resource("background", "Background", dpy, xgwa.colormap); |
---|
846 | erase_gc = XCreateGC (dpy, b, GCForeground, &gcv); |
---|
847 | |
---|
848 | /* drawing gc */ |
---|
849 | flags = GCForeground; |
---|
850 | color_index = random() % ncolors; |
---|
851 | gcv.foreground = colors[color_index].pixel; |
---|
852 | draw_gc = XCreateGC(dpy, b, flags, &gcv); |
---|
853 | |
---|
854 | /* initialize circles */ |
---|
855 | circles = init_circles(count, xgwa.width, xgwa.height); |
---|
856 | |
---|
857 | iterations = 0; |
---|
858 | for (;;) { |
---|
859 | XFillRectangle (dpy, b, erase_gc, 0, 0, xgwa.width, xgwa.height); |
---|
860 | |
---|
861 | sweep(count, circles); |
---|
862 | for (i=0;i<count;i++) { |
---|
863 | draw_circle(dpy, b, draw_gc, circles+i); |
---|
864 | move_circle(circles+i, xgwa.width, xgwa.height); |
---|
865 | } |
---|
866 | flush_arc_buffer(dpy, b, draw_gc); |
---|
867 | |
---|
868 | if (++iterations % color_iterations == 0) { |
---|
869 | color_index = (color_index + 1) % ncolors; |
---|
870 | XSetForeground(dpy, draw_gc, colors[color_index].pixel); |
---|
871 | } |
---|
872 | |
---|
873 | #ifdef HAVE_DOUBLE_BUFFER_EXTENSION |
---|
874 | if (backb) { |
---|
875 | XdbeSwapInfo info[1]; |
---|
876 | info[0].swap_window = window; |
---|
877 | info[0].swap_action = XdbeUndefined; |
---|
878 | XdbeSwapBuffers (dpy, info, 1); |
---|
879 | } |
---|
880 | else |
---|
881 | #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ |
---|
882 | if (dbuf) { |
---|
883 | XCopyArea (dpy, b, window, erase_gc, 0, 0, xgwa.width, xgwa.height, 0, 0); |
---|
884 | b = (b == ba ? bb : ba); |
---|
885 | } |
---|
886 | |
---|
887 | XSync(dpy, False); |
---|
888 | screenhack_handle_events(dpy); |
---|
889 | if (delay) |
---|
890 | usleep(delay); |
---|
891 | } |
---|
892 | } |
---|