http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / braid.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /*-
3  * braid --- random braids around a circle and then changes the color in
4  *           a rotational pattern
5  */
6
7 #if 0
8 static const char sccsid[] = "@(#)braid.c       5.00 2000/11/01 xlockmore";
9 #endif
10
11 /*-
12  * Copyright (c) 1995 by John Neil.
13  *
14  * Permission to use, copy, modify, and distribute this software and its
15  * documentation for any purpose and without fee is hereby granted,
16  * provided that the above copyright notice appear in all copies and that
17  * both that copyright notice and this permission notice appear in
18  * supporting documentation.
19  *
20  * This file is provided AS IS with no warranties of any kind.  The author
21  * shall have no liability with respect to the infringement of copyrights,
22  * trade secrets or any patents by this file or any part thereof.  In no
23  * event will the author be liable for any lost revenue or profits or
24  * other special, indirect and consequential damages.
25  *
26  * Revision History:
27  * 01-Nov-2000: Allocation checks
28  * 10-May-1997: Jamie Zawinski <jwz@jwz.org> compatible with xscreensaver
29  * 01-Sep-1995: color knotted components differently, J. Neil.
30  * 29-Aug-1995: Written.  John Neil <neil@math.idbsu.edu>
31  */
32
33 #ifdef STANDALONE
34 #define MODE_braid
35 #define PROGCLASS "Braid"
36 #define HACK_INIT init_braid
37 #define HACK_DRAW draw_braid
38 #define braid_opts xlockmore_opts
39 #define DEFAULTS "*delay: 1000 \n" \
40  "*count: 15 \n" \
41  "*cycles: 100 \n" \
42  "*size: -7 \n" \
43  "*ncolors: 64 \n"
44 #define UNIFORM_COLORS
45 #include "xlockmore.h"
46 #include "erase.h"
47 #else /* STANDALONE */
48 #include "xlock.h"
49
50 #endif /* STANDALONE */
51
52 #ifdef MODE_braid
53
54 ModeSpecOpt braid_opts =
55 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
56
57 #ifdef USE_MODULES
58 ModStruct   braid_description =
59 {"braid", "init_braid", "draw_braid", "release_braid",
60  "refresh_braid", "init_braid", (char *) NULL, &braid_opts,
61  1000, 15, 100, 1, 64, 1.0, "",
62  "Shows random braids and knots", 0, NULL};
63
64 #endif
65
66 #if defined( COLORROUND ) && defined( COLORCOMP )
67 #undef COLORROUND
68 #undef COLORCOMP
69 #endif
70
71 #if !defined( COLORROUND ) && !defined( COLORCOMP )
72 #if 0
73 /* to color in a circular pattern use COLORROUND */
74 #define COLORROUND
75 #else
76 /* to color by component use COLORCOMP */
77 #define COLORCOMP
78 #endif
79 #endif
80
81 #define MAXLENGTH  50           /* the maximum length of a braid word */
82 #define MINLENGTH  8            /* the minimum length of a braid word */
83 #define MAXSTRANDS  15          /* the maximum number of strands in the braid */
84 #define MINSTRANDS  3           /* the minimum number of strands in the braid */
85 #define SPINRATE  12.0          /* the rate at which the colors spin */
86
87 #define INTRAND(min,max) (NRAND((max+1)-(min))+(min))
88 #define FLOATRAND(min,max) ((min)+((double) LRAND()/((double) MAXRAND))*((max)-(min)))
89
90 typedef struct {
91         int         linewidth;
92         int         braidword[MAXLENGTH];
93         int         components[MAXSTRANDS];
94         int         startcomp[MAXLENGTH][MAXSTRANDS];
95         int         nstrands;
96         int         braidlength;
97         float       startcolor;
98         int         center_x;
99         int         center_y;
100         float       min_radius;
101         float       max_radius;
102         float       top, bottom, left, right;
103         int         age;
104         int         color_direction;
105 } braidtype;
106
107 static braidtype *braids = (braidtype *) NULL;
108
109 static int
110 applyword(braidtype * braid, int string, int position)
111 {
112         int         i, c;
113
114         c = string;
115         for (i = position; i < braid->braidlength; i++) {
116                 if (c == ABS(braid->braidword[i]))
117                         c--;
118                 else if (c == ABS(braid->braidword[i]) - 1)
119                         c++;
120         }
121         for (i = 0; i < position; i++) {
122                 if (c == ABS(braid->braidword[i]))
123                         c--;
124                 else if (c == ABS(braid->braidword[i]) - 1)
125                         c++;
126         }
127         return c;
128 }
129
130 #if 0
131 static int
132 applywordto(braidtype * braid, int string, int position)
133 {
134         int         i, c;
135
136         c = string;
137         for (i = 0; i < position; i++) {
138                 if (c == ABS(braid->braidword[i])) {
139                         c--;
140                 } else if (c == ABS(braid->braidword[i]) - 1) {
141                         c++;
142                 }
143         }
144         return c;
145 }
146 #endif
147
148 static int
149 applywordbackto(braidtype * braid, int string, int position)
150 {
151         int         i, c;
152
153         c = string;
154         for (i = position - 1; i >= 0; i--) {
155                 if (c == ABS(braid->braidword[i])) {
156                         c--;
157                 } else if (c == ABS(braid->braidword[i]) - 1) {
158                         c++;
159                 }
160         }
161         return c;
162 }
163
164 void
165 init_braid(ModeInfo * mi)
166 {
167         braidtype  *braid;
168         int         used[MAXSTRANDS];
169         int         i, count, comp, c;
170         float       min_length;
171
172         if (braids == NULL) {
173                 if ((braids = (braidtype *) calloc(MI_NUM_SCREENS(mi),
174                                                 sizeof (braidtype))) == NULL)
175                         return;
176         }
177         braid = &braids[MI_SCREEN(mi)];
178
179         braid->center_x = MI_WIDTH(mi) / 2;
180         braid->center_y = MI_HEIGHT(mi) / 2;
181         braid->age = 0;
182
183         /* jwz: go in the other direction sometimes. */
184         braid->color_direction = ((LRAND() & 1) ? 1 : -1);
185
186         MI_CLEARWINDOW(mi);
187
188         min_length = (braid->center_x > braid->center_y) ?
189                 braid->center_y : braid->center_x;
190         braid->min_radius = min_length * 0.30;
191         braid->max_radius = min_length * 0.90;
192
193         if (MI_COUNT(mi) < MINSTRANDS)
194                 braid->nstrands = MINSTRANDS;
195         else
196                 braid->nstrands = INTRAND(MINSTRANDS,
197                                        MAX(MIN(MIN(MAXSTRANDS, MI_COUNT(mi)),
198                                                (int) ((braid->max_radius - braid->min_radius) / 5.0)), MINSTRANDS));
199         braid->braidlength = INTRAND(MINLENGTH, MIN(MAXLENGTH, braid->nstrands * 6));
200
201         for (i = 0; i < braid->braidlength; i++) {
202                 braid->braidword[i] =
203                         INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
204                 if (i > 0)
205                         while (braid->braidword[i] == -braid->braidword[i - 1])
206                                 braid->braidword[i] = INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
207         }
208
209         while (braid->braidword[0] == -braid->braidword[braid->braidlength - 1])
210                 braid->braidword[braid->braidlength - 1] =
211                         INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
212
213         do {
214                 (void) memset((char *) used, 0, sizeof (used));
215                 count = 0;
216                 for (i = 0; i < braid->braidlength; i++)
217                         used[ABS(braid->braidword[i])]++;
218                 for (i = 0; i < braid->nstrands; i++)
219                         count += (used[i] > 0) ? 1 : 0;
220                 if (count < braid->nstrands - 1) {
221                         braid->braidword[braid->braidlength] =
222                                 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
223                         while (braid->braidword[braid->braidlength] ==
224                                -braid->braidword[braid->braidlength - 1] &&
225                                braid->braidword[0] == -braid->braidword[braid->braidlength])
226                                 braid->braidword[braid->braidlength] =
227                                         INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
228                         braid->braidlength++;
229                 }
230         } while (count < braid->nstrands - 1 && braid->braidlength < MAXLENGTH);
231
232         braid->startcolor = (MI_NPIXELS(mi) > 2) ?
233                 (float) NRAND(MI_NPIXELS(mi)) : 0.0;
234         /* XSetLineAttributes (display, MI_GC(mi), 2, LineSolid, CapRound,
235            JoinRound); */
236
237         (void) memset((char *) braid->components, 0, sizeof (braid->components));
238         c = 1;
239         comp = 0;
240         braid->components[0] = 1;
241         do {
242                 i = comp;
243                 do {
244                         i = applyword(braid, i, 0);
245                         braid->components[i] = braid->components[comp];
246                 } while (i != comp);
247                 count = 0;
248                 for (i = 0; i < braid->nstrands; i++)
249                         if (braid->components[i] == 0)
250                                 count++;
251                 if (count > 0) {
252                         for (comp = 0; braid->components[comp] != 0; comp++);
253                         braid->components[comp] = ++c;
254                 }
255         } while (count > 0);
256
257         braid->linewidth = MI_SIZE(mi);
258
259         if (braid->linewidth < 0)
260                 braid->linewidth = NRAND(-braid->linewidth) + 1;
261         if (braid->linewidth * braid->linewidth * 8 > MIN(MI_WIDTH(mi), MI_HEIGHT(mi)))
262        braid->linewidth = MIN(1, (int) sqrt((double) MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) / 8));
263         for (i = 0; i < braid->nstrands; i++)
264                 if (!(braid->components[i] & 1))
265                         braid->components[i] *= -1;
266 }
267
268 void
269 draw_braid(ModeInfo * mi)
270 {
271         Display    *display = MI_DISPLAY(mi);
272         Window      window = MI_WINDOW(mi);
273         int         num_points = 500;
274         float       t_inc;
275         float       theta, psi;
276         float       t, r_diff;
277         int         i, s;
278         float       x_1, y_1, x_2, y_2, r1, r2;
279         float       color, color_use = 0.0, color_inc;
280         braidtype  *braid;
281
282         if (braids == NULL)
283                 return;
284         braid = &braids[MI_SCREEN(mi)];
285
286         MI_IS_DRAWN(mi) = True;
287         XSetLineAttributes(display, MI_GC(mi), braid->linewidth,
288                            LineSolid,
289                            (braid->linewidth <= 3 ? CapButt : CapRound),
290                            JoinMiter);
291
292         theta = (2.0 * M_PI) / (float) (braid->braidlength);
293         t_inc = (2.0 * M_PI) / (float) num_points;
294         color_inc = (float) MI_NPIXELS(mi) * braid->color_direction /
295                 (float) num_points;
296         braid->startcolor += SPINRATE * color_inc;
297         if (((int) braid->startcolor) >= MI_NPIXELS(mi))
298                 braid->startcolor = 0.0;
299
300         r_diff = (braid->max_radius - braid->min_radius) / (float) (braid->nstrands);
301
302         color = braid->startcolor;
303         psi = 0.0;
304         for (i = 0; i < braid->braidlength; i++) {
305                 psi += theta;
306                 for (t = 0.0; t < theta; t += t_inc) {
307 #ifdef COLORROUND
308                         color += color_inc;
309                         if (((int) color) >= MI_NPIXELS(mi))
310                                 color = 0.0;
311                         color_use = color;
312 #endif
313                         for (s = 0; s < braid->nstrands; s++) {
314                                 if (ABS(braid->braidword[i]) == s)
315                                         continue;
316                                 if (ABS(braid->braidword[i]) - 1 == s) {
317                                         /* crosSINFg */
318 #ifdef COLORCOMP
319                                         if (MI_NPIXELS(mi) > 2) {
320                                                 color_use = color + SPINRATE *
321                                                         braid->components[applywordbackto(braid, s, i)] +
322                                                         (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
323                                                 while (((int) color_use) >= MI_NPIXELS(mi))
324                                                         color_use -= (float) MI_NPIXELS(mi);
325                                                 while (((int) color_use) < 0)
326                                                         color_use += (float) MI_NPIXELS(mi);
327                                         }
328 #endif
329 #ifdef COLORROUND
330                                         if (MI_NPIXELS(mi) > 2) {
331                                                 color_use += SPINRATE * color_inc;
332                                                 while (((int) color_use) >= MI_NPIXELS(mi))
333                                                         color_use -= (float) MI_NPIXELS(mi);
334                                         }
335 #endif
336                                         r1 = braid->min_radius + r_diff * (float) (s);
337                                         r2 = braid->min_radius + r_diff * (float) (s + 1);
338                                         if (braid->braidword[i] > 0 ||
339                                             (FABSF(t - theta / 2.0) > theta / 7.0)) {
340                                                 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
341                                                         0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
342                                                         COSF(t + psi) + braid->center_x;
343                                                 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
344                                                         0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
345                                                         SINF(t + psi) + braid->center_y;
346                                                 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
347                                                         0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
348                                                         COSF(t + t_inc + psi) + braid->center_x;
349                                                 y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
350                                                         0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
351                                                         SINF(t + t_inc + psi) + braid->center_y;
352                                                 if (MI_NPIXELS(mi) > 2)
353                                                         XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
354                                                 else
355                                                         XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
356
357                                                 XDrawLine(display, window, MI_GC(mi),
358                                                           (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
359                                         }
360 #ifdef COLORCOMP
361                                         if (MI_NPIXELS(mi) > 2) {
362                                                 color_use = color + SPINRATE *
363                                                         braid->components[applywordbackto(braid, s + 1, i)] +
364                                                         (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
365                                                 while (((int) color_use) >= MI_NPIXELS(mi))
366                                                         color_use -= (float) MI_NPIXELS(mi);
367                                                 while (((int) color_use) < 0)
368                                                         color_use += (float) MI_NPIXELS(mi);
369                                         }
370 #endif
371                                         if (braid->braidword[i] < 0 ||
372                                             (FABSF(t - theta / 2.0) > theta / 7.0)) {
373                                                 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
374                                                         0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
375                                                         COSF(t + psi) + braid->center_x;
376                                                 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
377                                                         0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
378                                                         SINF(t + psi) + braid->center_y;
379                                                 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
380                                                         0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
381                                                         COSF(t + t_inc + psi) + braid->center_x;
382                                                 y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
383                                                         0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
384                                                         SINF(t + t_inc + psi) + braid->center_y;
385                                                 if (MI_NPIXELS(mi) > 2)
386                                                         XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
387                                                 else
388                                                         XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
389
390                                                 XDrawLine(display, window, MI_GC(mi),
391                                                           (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
392                                         }
393                                 } else {
394                                         /* no crosSINFg */
395 #ifdef COLORCOMP
396                                         if (MI_NPIXELS(mi) > 2) {
397                                                 color_use = color + SPINRATE *
398                                                         braid->components[applywordbackto(braid, s, i)] +
399                                                         (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
400                                                 while (((int) color_use) >= MI_NPIXELS(mi))
401                                                         color_use -= (float) MI_NPIXELS(mi);
402                                                 while (((int) color_use) < 0)
403                                                         color_use += (float) MI_NPIXELS(mi);
404                                         }
405 #endif
406 #ifdef COLORROUND
407                                         if (MI_NPIXELS(mi) > 2) {
408                                                 color_use += SPINRATE * color_inc;
409                                                 while (((int) color_use) >= MI_NPIXELS(mi))
410                                                         color_use -= (float) MI_NPIXELS(mi);
411                                         }
412 #endif
413                                         r1 = braid->min_radius + r_diff * (float) (s);
414                                         x_1 = r1 * COSF(t + psi) + braid->center_x;
415                                         y_1 = r1 * SINF(t + psi) + braid->center_y;
416                                         x_2 = r1 * COSF(t + t_inc + psi) + braid->center_x;
417                                         y_2 = r1 * SINF(t + t_inc + psi) + braid->center_y;
418                                         if (MI_NPIXELS(mi) > 2)
419                                                 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
420                                         else
421                                                 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
422
423                                         XDrawLine(display, window, MI_GC(mi),
424                                                   (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
425                                 }
426                         }
427                 }
428         }
429         XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinRound);
430
431         if (++braid->age > MI_CYCLES(mi)) {
432 #ifdef STANDALONE
433           erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
434 #endif
435                 init_braid(mi);
436         }
437 }
438
439 void
440 release_braid(ModeInfo * mi)
441 {
442         if (braids != NULL) {
443                 (void) free((void *) braids);
444                 braids = (braidtype *) NULL;
445         }
446 }
447
448 void
449 refresh_braid(ModeInfo * mi)
450 {
451         MI_CLEARWINDOW(mi);
452 }
453
454 #endif /* MODE_braid */