1 /* -*- Mode: C; tab-width: 4 -*-
2 * braid --- draws random color-cyling rotating braids around a circle.
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)braid.c 4.00 97/01/01 xlockmore";
9 * Copyright (c) 1995 by John Neil.
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
24 * 10-May-97: jwz@jwz.org: turned into a standalone program.
25 * 01-Sep-95: color knotted components differently, J. Neil.
26 * 29-Aug-95: Written. John Neil <neil@math.idbsu.edu>
30 # define PROGCLASS "Braid"
31 # define HACK_INIT init_braid
32 # define HACK_DRAW draw_braid
33 # define braid_opts xlockmore_opts
34 # define DEFAULTS "*count: 15 \n" \
39 # define UNIFORM_COLORS
40 # include "xlockmore.h" /* from the xscreensaver distribution */
42 #else /* !STANDALONE */
43 # include "xlock.h" /* from the xlockmore distribution */
44 #endif /* !STANDALONE */
46 ModeSpecOpt braid_opts = {
47 0, NULL, 0, NULL, NULL };
50 #if defined( COLORROUND ) && defined( COLORCOMP )
55 #if !defined( COLORROUND ) && !defined( COLORCOMP )
57 /* to color in a circular pattern use COLORROUND */
60 /* to color by component use COLORCOMP */
65 #define MAXLENGTH 50 /* the maximum length of a braid word */
66 #define MINLENGTH 8 /* the minimum length of a braid word */
67 #define MAXSTRANDS 15 /* the maximum number of strands in the braid */
68 #define MINSTRANDS 3 /* the minimum number of strands in the braid */
69 #define SPINRATE 12.0 /* the rate at which the colors spin */
71 #define INTRAND(min,max) (NRAND((max+1)-(min))+(min))
72 #define FLOATRAND(min,max) ((min)+((double) LRAND()/((double) MAXRAND))*((max)-(min)))
75 int braidword[MAXLENGTH];
76 int components[MAXSTRANDS];
77 int startcomp[MAXLENGTH][MAXSTRANDS];
85 float top, bottom, left, right;
90 static braidtype *braids = NULL;
93 applyword(braidtype * braid, int string, int position)
98 for (i = position; i < braid->braidlength; i++) {
99 if (c == ABS(braid->braidword[i]))
101 else if (c == ABS(braid->braidword[i]) - 1)
104 for (i = 0; i < position; i++) {
105 if (c == ABS(braid->braidword[i]))
107 else if (c == ABS(braid->braidword[i]) - 1)
115 applywordto(braidtype * braid, int string, int position)
120 for (i = 0; i < position; i++) {
121 if (c == ABS(braid->braidword[i])) {
123 } else if (c == ABS(braid->braidword[i]) - 1) {
132 applywordbackto(braidtype * braid, int string, int position)
137 for (i = position - 1; i >= 0; i--) {
138 if (c == ABS(braid->braidword[i])) {
140 } else if (c == ABS(braid->braidword[i]) - 1) {
148 init_braid(ModeInfo * mi)
150 Display *display = MI_DISPLAY(mi);
152 int used[MAXSTRANDS];
153 int i, count, comp, c;
156 if (braids == NULL) {
157 if ((braids = (braidtype *) calloc(MI_NUM_SCREENS(mi),
158 sizeof (braidtype))) == NULL)
161 braid = &braids[MI_SCREEN(mi)];
163 braid->center_x = MI_WIN_WIDTH(mi) / 2;
164 braid->center_y = MI_WIN_HEIGHT(mi) / 2;
167 /* jwz: go in the other direction sometimes. */
168 braid->color_direction = ((LRAND() & 1) ? 1 : -1);
169 XClearWindow(display, MI_WINDOW(mi));
171 min_length = (braid->center_x > braid->center_y) ?
172 braid->center_y : braid->center_x;
173 braid->min_radius = min_length * 0.30;
174 braid->max_radius = min_length * 0.90;
176 if (MI_BATCHCOUNT(mi) < MINSTRANDS)
177 braid->nstrands = MINSTRANDS;
179 braid->nstrands = INTRAND(MINSTRANDS,
180 MAX(MIN(MIN(MAXSTRANDS, MI_BATCHCOUNT(mi)),
181 (int) ((braid->max_radius - braid->min_radius) / 5.0)), MINSTRANDS));
182 braid->braidlength = INTRAND(MINLENGTH, MIN(MAXLENGTH, braid->nstrands * 6));
184 for (i = 0; i < braid->braidlength; i++) {
185 braid->braidword[i] =
186 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
188 while (braid->braidword[i] == -braid->braidword[i - 1])
189 braid->braidword[i] = INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
192 while (braid->braidword[0] == -braid->braidword[braid->braidlength - 1])
193 braid->braidword[braid->braidlength - 1] =
194 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
197 (void) memset((char *) used, 0, sizeof (used));
199 for (i = 0; i < braid->braidlength; i++)
200 used[ABS(braid->braidword[i])]++;
201 for (i = 0; i < braid->nstrands; i++)
202 count += (used[i] > 0) ? 1 : 0;
203 if (count < braid->nstrands - 1) {
204 braid->braidword[braid->braidlength] =
205 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
206 while (braid->braidword[braid->braidlength] ==
207 -braid->braidword[braid->braidlength - 1] &&
208 braid->braidword[0] == -braid->braidword[braid->braidlength])
209 braid->braidword[braid->braidlength] =
210 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
211 braid->braidlength++;
213 } while (count < braid->nstrands - 1 && braid->braidlength < MAXLENGTH);
215 braid->startcolor = (MI_NPIXELS(mi) > 2) ?
216 (float) NRAND(MI_NPIXELS(mi)) : 0.0;
217 /* XSetLineAttributes (display, MI_GC(mi), 2, LineSolid, CapRound,
220 (void) memset((char *) braid->components, 0, sizeof (braid->components));
223 braid->components[0] = 1;
227 i = applyword(braid, i, 0);
228 braid->components[i] = braid->components[comp];
231 for (i = 0; i < braid->nstrands; i++)
232 if (braid->components[i] == 0)
235 for (comp = 0; braid->components[comp] != 0; comp++);
236 braid->components[comp] = ++c;
241 int line_width = MI_SIZE(mi);
245 line_width = NRAND(-line_width)+1;
248 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), line_width,
250 (line_width <= 3 ? CapButt : CapRound),
255 for (i = 0; i < braid->nstrands; i++)
256 if (!(braid->components[i] & 1))
257 braid->components[i] *= -1;
261 draw_braid(ModeInfo * mi)
263 Display *display = MI_DISPLAY(mi);
264 Window window = MI_WINDOW(mi);
265 braidtype *braid = &braids[MI_SCREEN(mi)];
266 float num_points, t_inc;
270 float x_1, y_1, x_2, y_2, r1, r2;
271 float color, color_use = 0.0, color_inc;
274 theta = (2.0 * M_PI) / (float) (braid->braidlength);
275 t_inc = (2.0 * M_PI) / num_points;
276 color_inc = (float) MI_NPIXELS(mi) / num_points;
277 color_inc *= braid->color_direction;
279 braid->startcolor += SPINRATE * color_inc;
280 if (braid->startcolor >= MI_NPIXELS(mi))
281 braid->startcolor = 0.0;
283 r_diff = (braid->max_radius - braid->min_radius) / (float) (braid->nstrands);
285 color = braid->startcolor;
287 for (i = 0; i < braid->braidlength; i++) {
289 for (t = 0.0; t < theta; t += t_inc) {
292 if (color >= (float) (MI_NPIXELS(mi)))
296 for (s = 0; s < braid->nstrands; s++) {
297 if (ABS(braid->braidword[i]) == s)
299 if (ABS(braid->braidword[i]) - 1 == s) {
302 if (MI_NPIXELS(mi) > 2) {
303 color_use = color + SPINRATE *
304 braid->components[applywordbackto(braid, s, i)] +
305 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
306 while (color_use >= (float) MI_NPIXELS(mi))
307 color_use -= (float) MI_NPIXELS(mi);
308 while (color_use < 0.0)
309 color_use += (float) MI_NPIXELS(mi);
313 if (MI_NPIXELS(mi) > 2) {
314 color_use += SPINRATE * color_inc;
315 while (color_use >= (float) (MI_NPIXELS(mi)))
316 color_use -= (float) MI_NPIXELS(mi);
319 r1 = braid->min_radius + r_diff * (float) (s);
320 r2 = braid->min_radius + r_diff * (float) (s + 1);
321 if (braid->braidword[i] > 0 ||
322 (FABSF(t - theta / 2.0) > theta / 7.0)) {
323 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
324 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
325 COSF(t + psi) + braid->center_x;
326 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
327 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
328 SINF(t + psi) + braid->center_y;
329 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
330 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
331 COSF(t + t_inc + psi) + braid->center_x;
332 y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
333 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
334 SINF(t + t_inc + psi) + braid->center_y;
335 if (MI_NPIXELS(mi) > 2)
336 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
338 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
340 XDrawLine(display, window, MI_GC(mi),
341 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
344 if (MI_NPIXELS(mi) > 2) {
345 color_use = color + SPINRATE *
346 braid->components[applywordbackto(braid, s + 1, i)] +
347 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
348 while (color_use >= (float) MI_NPIXELS(mi))
349 color_use -= (float) MI_NPIXELS(mi);
350 while (color_use < 0.0)
351 color_use += (float) MI_NPIXELS(mi);
354 if (braid->braidword[i] < 0 ||
355 (FABSF(t - theta / 2.0) > theta / 7.0)) {
356 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
357 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
358 COSF(t + psi) + braid->center_x;
359 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
360 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
361 SINF(t + psi) + braid->center_y;
362 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
363 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
364 COSF(t + t_inc + psi) + braid->center_x;
365 y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
366 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
367 SINF(t + t_inc + psi) + braid->center_y;
368 if (MI_NPIXELS(mi) > 2)
369 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
371 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
373 XDrawLine(display, window, MI_GC(mi),
374 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
379 if (MI_NPIXELS(mi) > 2) {
380 color_use = color + SPINRATE *
381 braid->components[applywordbackto(braid, s, i)] +
382 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
383 while (color_use >= (float) MI_NPIXELS(mi))
384 color_use -= (float) MI_NPIXELS(mi);
385 while (color_use < 0.0)
386 color_use += (float) MI_NPIXELS(mi);
390 if (MI_NPIXELS(mi) > 2) {
391 color_use += SPINRATE * color_inc;
392 while (color_use >= (float) MI_NPIXELS(mi))
393 color_use -= (float) MI_NPIXELS(mi);
396 r1 = braid->min_radius + r_diff * (float) (s);
397 x_1 = r1 * COSF(t + psi) + braid->center_x;
398 y_1 = r1 * SINF(t + psi) + braid->center_y;
399 x_2 = r1 * COSF(t + t_inc + psi) + braid->center_x;
400 y_2 = r1 * SINF(t + t_inc + psi) + braid->center_y;
401 if (MI_NPIXELS(mi) > 2)
402 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
404 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
406 XDrawLine(display, window, MI_GC(mi),
407 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
413 if (++braid->age > MI_CYCLES(mi)) {
415 erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
422 release_braid(ModeInfo * mi)
424 if (braids != NULL) {
425 (void) free((void *) braids);
431 refresh_braid(ModeInfo * mi)
433 /* Do nothing, it will refresh by itself */