source: trunk/third/xscreensaver/hacks/braid.c @ 20148

Revision 20148, 13.5 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
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
8static 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
54ModeSpecOpt braid_opts =
55{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
56
57#ifdef USE_MODULES
58ModStruct   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
90typedef 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
107static braidtype *braids = (braidtype *) NULL;
108
109static int
110applyword(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
131static int
132applywordto(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
148static int
149applywordbackto(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
164void
165init_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
268void
269draw_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
439void
440release_braid(ModeInfo * mi)
441{
442        if (braids != NULL) {
443                (void) free((void *) braids);
444                braids = (braidtype *) NULL;
445        }
446}
447
448void
449refresh_braid(ModeInfo * mi)
450{
451        MI_CLEARWINDOW(mi);
452}
453
454#endif /* MODE_braid */
Note: See TracBrowser for help on using the repository browser.