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@netscape.com: 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 "*eraseSpeed: 400 \n" \
41 # define UNIFORM_COLORS
42 # include "xlockmore.h" /* from the xscreensaver distribution */
44 #else /* !STANDALONE */
45 # include "xlock.h" /* from the xlockmore distribution */
46 #endif /* !STANDALONE */
48 ModeSpecOpt braid_opts = {
49 0, NULL, 0, NULL, NULL };
52 #if defined( COLORROUND ) && defined( COLORCOMP )
57 #if !defined( COLORROUND ) && !defined( COLORCOMP )
59 /* to color in a circular pattern use COLORROUND */
62 /* to color by component use COLORCOMP */
67 #define MAXLENGTH 50 /* the maximum length of a braid word */
68 #define MINLENGTH 8 /* the minimum length of a braid word */
69 #define MAXSTRANDS 15 /* the maximum number of strands in the braid */
70 #define MINSTRANDS 3 /* the minimum number of strands in the braid */
71 #define SPINRATE 12.0 /* the rate at which the colors spin */
73 #define INTRAND(min,max) (NRAND((max+1)-(min))+(min))
74 #define FLOATRAND(min,max) ((min)+((double) LRAND()/((double) MAXRAND))*((max)-(min)))
77 int braidword[MAXLENGTH];
78 int components[MAXSTRANDS];
79 int startcomp[MAXLENGTH][MAXSTRANDS];
87 float top, bottom, left, right;
92 static braidtype *braids = NULL;
95 applyword(braidtype * braid, int string, int position)
100 for (i = position; i < braid->braidlength; i++) {
101 if (c == ABS(braid->braidword[i]))
103 else if (c == ABS(braid->braidword[i]) - 1)
106 for (i = 0; i < position; i++) {
107 if (c == ABS(braid->braidword[i]))
109 else if (c == ABS(braid->braidword[i]) - 1)
117 applywordto(braidtype * braid, int string, int position)
122 for (i = 0; i < position; i++) {
123 if (c == ABS(braid->braidword[i])) {
125 } else if (c == ABS(braid->braidword[i]) - 1) {
134 applywordbackto(braidtype * braid, int string, int position)
139 for (i = position - 1; i >= 0; i--) {
140 if (c == ABS(braid->braidword[i])) {
142 } else if (c == ABS(braid->braidword[i]) - 1) {
150 init_braid(ModeInfo * mi)
152 Display *display = MI_DISPLAY(mi);
154 int used[MAXSTRANDS];
155 int i, count, comp, c;
158 if (braids == NULL) {
159 if ((braids = (braidtype *) calloc(MI_NUM_SCREENS(mi),
160 sizeof (braidtype))) == NULL)
163 braid = &braids[MI_SCREEN(mi)];
165 braid->center_x = MI_WIN_WIDTH(mi) / 2;
166 braid->center_y = MI_WIN_HEIGHT(mi) / 2;
169 /* jwz: go in the other direction sometimes. */
170 braid->color_direction = ((LRAND() & 1) ? 1 : -1);
171 XClearWindow(display, MI_WINDOW(mi));
173 min_length = (braid->center_x > braid->center_y) ?
174 braid->center_y : braid->center_x;
175 braid->min_radius = min_length * 0.30;
176 braid->max_radius = min_length * 0.90;
178 if (MI_BATCHCOUNT(mi) < MINSTRANDS)
179 braid->nstrands = MINSTRANDS;
181 braid->nstrands = INTRAND(MINSTRANDS,
182 MAX(MIN(MIN(MAXSTRANDS, MI_BATCHCOUNT(mi)),
183 (int) ((braid->max_radius - braid->min_radius) / 5.0)), MINSTRANDS));
184 braid->braidlength = INTRAND(MINLENGTH, MIN(MAXLENGTH, braid->nstrands * 6));
186 for (i = 0; i < braid->braidlength; i++) {
187 braid->braidword[i] =
188 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
190 while (braid->braidword[i] == -braid->braidword[i - 1])
191 braid->braidword[i] = INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
194 while (braid->braidword[0] == -braid->braidword[braid->braidlength - 1])
195 braid->braidword[braid->braidlength - 1] =
196 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
199 (void) memset((char *) used, 0, sizeof (used));
201 for (i = 0; i < braid->braidlength; i++)
202 used[ABS(braid->braidword[i])]++;
203 for (i = 0; i < braid->nstrands; i++)
204 count += (used[i] > 0) ? 1 : 0;
205 if (count < braid->nstrands - 1) {
206 braid->braidword[braid->braidlength] =
207 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
208 while (braid->braidword[braid->braidlength] ==
209 -braid->braidword[braid->braidlength - 1] &&
210 braid->braidword[0] == -braid->braidword[braid->braidlength])
211 braid->braidword[braid->braidlength] =
212 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
213 braid->braidlength++;
215 } while (count < braid->nstrands - 1 && braid->braidlength < MAXLENGTH);
217 braid->startcolor = (MI_NPIXELS(mi) > 2) ?
218 (float) NRAND(MI_NPIXELS(mi)) : 0.0;
219 /* XSetLineAttributes (display, MI_GC(mi), 2, LineSolid, CapRound,
222 (void) memset((char *) braid->components, 0, sizeof (braid->components));
225 braid->components[0] = 1;
229 i = applyword(braid, i, 0);
230 braid->components[i] = braid->components[comp];
233 for (i = 0; i < braid->nstrands; i++)
234 if (braid->components[i] == 0)
237 for (comp = 0; braid->components[comp] != 0; comp++);
238 braid->components[comp] = ++c;
243 int line_width = MI_SIZE(mi);
247 line_width = NRAND(-line_width)+1;
250 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), line_width,
252 (line_width <= 3 ? CapButt : CapRound),
257 for (i = 0; i < braid->nstrands; i++)
258 if (!(braid->components[i] & 1))
259 braid->components[i] *= -1;
263 draw_braid(ModeInfo * mi)
265 Display *display = MI_DISPLAY(mi);
266 Window window = MI_WINDOW(mi);
267 braidtype *braid = &braids[MI_SCREEN(mi)];
268 float num_points, t_inc;
272 float x_1, y_1, x_2, y_2, r1, r2;
273 float color, color_use = 0.0, color_inc;
276 theta = (2.0 * M_PI) / (float) (braid->braidlength);
277 t_inc = (2.0 * M_PI) / num_points;
278 color_inc = (float) MI_NPIXELS(mi) / num_points;
279 color_inc *= braid->color_direction;
281 braid->startcolor += SPINRATE * color_inc;
282 if (braid->startcolor >= MI_NPIXELS(mi))
283 braid->startcolor = 0.0;
285 r_diff = (braid->max_radius - braid->min_radius) / (float) (braid->nstrands);
287 color = braid->startcolor;
289 for (i = 0; i < braid->braidlength; i++) {
291 for (t = 0.0; t < theta; t += t_inc) {
294 if (color >= (float) (MI_NPIXELS(mi)))
298 for (s = 0; s < braid->nstrands; s++) {
299 if (ABS(braid->braidword[i]) == s)
301 if (ABS(braid->braidword[i]) - 1 == s) {
304 if (MI_NPIXELS(mi) > 2) {
305 color_use = color + SPINRATE *
306 braid->components[applywordbackto(braid, s, i)] +
307 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
308 while (color_use >= (float) MI_NPIXELS(mi))
309 color_use -= (float) MI_NPIXELS(mi);
310 while (color_use < 0.0)
311 color_use += (float) MI_NPIXELS(mi);
315 if (MI_NPIXELS(mi) > 2) {
316 color_use += SPINRATE * color_inc;
317 while (color_use >= (float) (MI_NPIXELS(mi)))
318 color_use -= (float) MI_NPIXELS(mi);
321 r1 = braid->min_radius + r_diff * (float) (s);
322 r2 = braid->min_radius + r_diff * (float) (s + 1);
323 if (braid->braidword[i] > 0 ||
324 (FABSF(t - theta / 2.0) > theta / 7.0)) {
325 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
326 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
327 COSF(t + psi) + braid->center_x;
328 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
329 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
330 SINF(t + psi) + braid->center_y;
331 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
332 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
333 COSF(t + t_inc + psi) + braid->center_x;
334 y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
335 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
336 SINF(t + t_inc + psi) + braid->center_y;
337 if (MI_NPIXELS(mi) > 2)
338 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
340 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
342 XDrawLine(display, window, MI_GC(mi),
343 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
346 if (MI_NPIXELS(mi) > 2) {
347 color_use = color + SPINRATE *
348 braid->components[applywordbackto(braid, s + 1, i)] +
349 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
350 while (color_use >= (float) MI_NPIXELS(mi))
351 color_use -= (float) MI_NPIXELS(mi);
352 while (color_use < 0.0)
353 color_use += (float) MI_NPIXELS(mi);
356 if (braid->braidword[i] < 0 ||
357 (FABSF(t - theta / 2.0) > theta / 7.0)) {
358 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
359 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
360 COSF(t + psi) + braid->center_x;
361 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
362 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
363 SINF(t + psi) + braid->center_y;
364 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
365 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
366 COSF(t + t_inc + psi) + braid->center_x;
367 y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
368 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
369 SINF(t + t_inc + psi) + braid->center_y;
370 if (MI_NPIXELS(mi) > 2)
371 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
373 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
375 XDrawLine(display, window, MI_GC(mi),
376 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
381 if (MI_NPIXELS(mi) > 2) {
382 color_use = color + SPINRATE *
383 braid->components[applywordbackto(braid, s, i)] +
384 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
385 while (color_use >= (float) MI_NPIXELS(mi))
386 color_use -= (float) MI_NPIXELS(mi);
387 while (color_use < 0.0)
388 color_use += (float) MI_NPIXELS(mi);
392 if (MI_NPIXELS(mi) > 2) {
393 color_use += SPINRATE * color_inc;
394 while (color_use >= (float) MI_NPIXELS(mi))
395 color_use -= (float) MI_NPIXELS(mi);
398 r1 = braid->min_radius + r_diff * (float) (s);
399 x_1 = r1 * COSF(t + psi) + braid->center_x;
400 y_1 = r1 * SINF(t + psi) + braid->center_y;
401 x_2 = r1 * COSF(t + t_inc + psi) + braid->center_x;
402 y_2 = r1 * SINF(t + t_inc + psi) + braid->center_y;
403 if (MI_NPIXELS(mi) > 2)
404 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
406 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
408 XDrawLine(display, window, MI_GC(mi),
409 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
415 if (++braid->age > MI_CYCLES(mi)) {
417 erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
424 release_braid(ModeInfo * mi)
426 if (braids != NULL) {
427 (void) free((void *) braids);
433 refresh_braid(ModeInfo * mi)
435 /* Do nothing, it will refresh by itself */