1 /* -*- Mode: C; tab-width: 4 -*- */
3 * braid --- random braids around a circle and then changes the color in
7 #if !defined( lint ) && !defined( SABER )
8 static const char sccsid[] = "@(#)braid.c 5.00 2000/11/01 xlockmore";
13 * Copyright (c) 1995 by John Neil.
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation.
21 * This file is provided AS IS with no warranties of any kind. The author
22 * shall have no liability with respect to the infringement of copyrights,
23 * trade secrets or any patents by this file or any part thereof. In no
24 * event will the author be liable for any lost revenue or profits or
25 * other special, indirect and consequential damages.
28 * 01-Nov-2000: Allocation checks
29 * 10-May-1997: Jamie Zawinski <jwz@jwz.org> compatible with xscreensaver
30 * 01-Sep-1995: color knotted components differently, J. Neil.
31 * 29-Aug-1995: Written. John Neil <neil@math.idbsu.edu>
36 #define PROGCLASS "Braid"
37 #define HACK_INIT init_braid
38 #define HACK_DRAW draw_braid
39 #define braid_opts xlockmore_opts
40 #define DEFAULTS "*delay: 1000 \n" \
45 #define UNIFORM_COLORS
46 #include "xlockmore.h"
48 #else /* STANDALONE */
51 #endif /* STANDALONE */
55 ModeSpecOpt braid_opts =
56 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
59 ModStruct braid_description =
60 {"braid", "init_braid", "draw_braid", "release_braid",
61 "refresh_braid", "init_braid", (char *) NULL, &braid_opts,
62 1000, 15, 100, 1, 64, 1.0, "",
63 "Shows random braids and knots", 0, NULL};
67 #if defined( COLORROUND ) && defined( COLORCOMP )
72 #if !defined( COLORROUND ) && !defined( COLORCOMP )
74 /* to color in a circular pattern use COLORROUND */
77 /* to color by component use COLORCOMP */
82 #define MAXLENGTH 50 /* the maximum length of a braid word */
83 #define MINLENGTH 8 /* the minimum length of a braid word */
84 #define MAXSTRANDS 15 /* the maximum number of strands in the braid */
85 #define MINSTRANDS 3 /* the minimum number of strands in the braid */
86 #define SPINRATE 12.0 /* the rate at which the colors spin */
88 #define INTRAND(min,max) (NRAND((max+1)-(min))+(min))
89 #define FLOATRAND(min,max) ((min)+((double) LRAND()/((double) MAXRAND))*((max)-(min)))
93 int braidword[MAXLENGTH];
94 int components[MAXSTRANDS];
95 int startcomp[MAXLENGTH][MAXSTRANDS];
103 float top, bottom, left, right;
108 static braidtype *braids = (braidtype *) NULL;
111 applyword(braidtype * braid, int string, int position)
116 for (i = position; i < braid->braidlength; i++) {
117 if (c == ABS(braid->braidword[i]))
119 else if (c == ABS(braid->braidword[i]) - 1)
122 for (i = 0; i < position; i++) {
123 if (c == ABS(braid->braidword[i]))
125 else if (c == ABS(braid->braidword[i]) - 1)
133 applywordto(braidtype * braid, int string, int position)
138 for (i = 0; i < position; i++) {
139 if (c == ABS(braid->braidword[i])) {
141 } else if (c == ABS(braid->braidword[i]) - 1) {
150 applywordbackto(braidtype * braid, int string, int position)
155 for (i = position - 1; i >= 0; i--) {
156 if (c == ABS(braid->braidword[i])) {
158 } else if (c == ABS(braid->braidword[i]) - 1) {
166 init_braid(ModeInfo * mi)
169 int used[MAXSTRANDS];
170 int i, count, comp, c;
173 if (braids == NULL) {
174 if ((braids = (braidtype *) calloc(MI_NUM_SCREENS(mi),
175 sizeof (braidtype))) == NULL)
178 braid = &braids[MI_SCREEN(mi)];
180 braid->center_x = MI_WIDTH(mi) / 2;
181 braid->center_y = MI_HEIGHT(mi) / 2;
184 /* jwz: go in the other direction sometimes. */
185 braid->color_direction = ((LRAND() & 1) ? 1 : -1);
189 min_length = (braid->center_x > braid->center_y) ?
190 braid->center_y : braid->center_x;
191 braid->min_radius = min_length * 0.30;
192 braid->max_radius = min_length * 0.90;
194 if (MI_COUNT(mi) < MINSTRANDS)
195 braid->nstrands = MINSTRANDS;
197 braid->nstrands = INTRAND(MINSTRANDS,
198 MAX(MIN(MIN(MAXSTRANDS, MI_COUNT(mi)),
199 (int) ((braid->max_radius - braid->min_radius) / 5.0)), MINSTRANDS));
200 braid->braidlength = INTRAND(MINLENGTH, MIN(MAXLENGTH, braid->nstrands * 6));
202 for (i = 0; i < braid->braidlength; i++) {
203 braid->braidword[i] =
204 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
206 while (braid->braidword[i] == -braid->braidword[i - 1])
207 braid->braidword[i] = INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
210 while (braid->braidword[0] == -braid->braidword[braid->braidlength - 1])
211 braid->braidword[braid->braidlength - 1] =
212 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
215 (void) memset((char *) used, 0, sizeof (used));
217 for (i = 0; i < braid->braidlength; i++)
218 used[ABS(braid->braidword[i])]++;
219 for (i = 0; i < braid->nstrands; i++)
220 count += (used[i] > 0) ? 1 : 0;
221 if (count < braid->nstrands - 1) {
222 braid->braidword[braid->braidlength] =
223 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
224 while (braid->braidword[braid->braidlength] ==
225 -braid->braidword[braid->braidlength - 1] &&
226 braid->braidword[0] == -braid->braidword[braid->braidlength])
227 braid->braidword[braid->braidlength] =
228 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
229 braid->braidlength++;
231 } while (count < braid->nstrands - 1 && braid->braidlength < MAXLENGTH);
233 braid->startcolor = (MI_NPIXELS(mi) > 2) ?
234 (float) NRAND(MI_NPIXELS(mi)) : 0.0;
235 /* XSetLineAttributes (display, MI_GC(mi), 2, LineSolid, CapRound,
238 (void) memset((char *) braid->components, 0, sizeof (braid->components));
241 braid->components[0] = 1;
245 i = applyword(braid, i, 0);
246 braid->components[i] = braid->components[comp];
249 for (i = 0; i < braid->nstrands; i++)
250 if (braid->components[i] == 0)
253 for (comp = 0; braid->components[comp] != 0; comp++);
254 braid->components[comp] = ++c;
258 braid->linewidth = MI_SIZE(mi);
260 if (braid->linewidth < 0)
261 braid->linewidth = NRAND(-braid->linewidth) + 1;
262 if (braid->linewidth * braid->linewidth * 8 > MIN(MI_WIDTH(mi), MI_HEIGHT(mi)))
263 braid->linewidth = MIN(1, (int) sqrt((double) MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) / 8));
264 for (i = 0; i < braid->nstrands; i++)
265 if (!(braid->components[i] & 1))
266 braid->components[i] *= -1;
270 draw_braid(ModeInfo * mi)
272 Display *display = MI_DISPLAY(mi);
273 Window window = MI_WINDOW(mi);
274 int num_points = 500;
279 float x_1, y_1, x_2, y_2, r1, r2;
280 float color, color_use = 0.0, color_inc;
285 braid = &braids[MI_SCREEN(mi)];
287 MI_IS_DRAWN(mi) = True;
288 XSetLineAttributes(display, MI_GC(mi), braid->linewidth,
290 (braid->linewidth <= 3 ? CapButt : CapRound),
293 theta = (2.0 * M_PI) / (float) (braid->braidlength);
294 t_inc = (2.0 * M_PI) / (float) num_points;
295 color_inc = (float) MI_NPIXELS(mi) * braid->color_direction /
297 braid->startcolor += SPINRATE * color_inc;
298 if (((int) braid->startcolor) >= MI_NPIXELS(mi))
299 braid->startcolor = 0.0;
301 r_diff = (braid->max_radius - braid->min_radius) / (float) (braid->nstrands);
303 color = braid->startcolor;
305 for (i = 0; i < braid->braidlength; i++) {
307 for (t = 0.0; t < theta; t += t_inc) {
310 if (((int) color) >= MI_NPIXELS(mi))
314 for (s = 0; s < braid->nstrands; s++) {
315 if (ABS(braid->braidword[i]) == s)
317 if (ABS(braid->braidword[i]) - 1 == s) {
320 if (MI_NPIXELS(mi) > 2) {
321 color_use = color + SPINRATE *
322 braid->components[applywordbackto(braid, s, i)] +
323 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
324 while (((int) color_use) >= MI_NPIXELS(mi))
325 color_use -= (float) MI_NPIXELS(mi);
326 while (((int) color_use) < 0)
327 color_use += (float) MI_NPIXELS(mi);
331 if (MI_NPIXELS(mi) > 2) {
332 color_use += SPINRATE * color_inc;
333 while (((int) color_use) >= MI_NPIXELS(mi))
334 color_use -= (float) MI_NPIXELS(mi);
337 r1 = braid->min_radius + r_diff * (float) (s);
338 r2 = braid->min_radius + r_diff * (float) (s + 1);
339 if (braid->braidword[i] > 0 ||
340 (FABSF(t - theta / 2.0) > theta / 7.0)) {
341 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
342 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
343 COSF(t + psi) + braid->center_x;
344 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
345 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
346 SINF(t + psi) + braid->center_y;
347 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
348 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
349 COSF(t + t_inc + psi) + braid->center_x;
350 y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
351 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
352 SINF(t + t_inc + psi) + braid->center_y;
353 if (MI_NPIXELS(mi) > 2)
354 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
356 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
358 XDrawLine(display, window, MI_GC(mi),
359 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
362 if (MI_NPIXELS(mi) > 2) {
363 color_use = color + SPINRATE *
364 braid->components[applywordbackto(braid, s + 1, i)] +
365 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
366 while (((int) color_use) >= MI_NPIXELS(mi))
367 color_use -= (float) MI_NPIXELS(mi);
368 while (((int) color_use) < 0)
369 color_use += (float) MI_NPIXELS(mi);
372 if (braid->braidword[i] < 0 ||
373 (FABSF(t - theta / 2.0) > theta / 7.0)) {
374 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
375 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
376 COSF(t + psi) + braid->center_x;
377 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
378 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
379 SINF(t + psi) + braid->center_y;
380 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
381 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
382 COSF(t + t_inc + psi) + braid->center_x;
383 y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
384 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
385 SINF(t + t_inc + psi) + braid->center_y;
386 if (MI_NPIXELS(mi) > 2)
387 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
389 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
391 XDrawLine(display, window, MI_GC(mi),
392 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
397 if (MI_NPIXELS(mi) > 2) {
398 color_use = color + SPINRATE *
399 braid->components[applywordbackto(braid, s, i)] +
400 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
401 while (((int) color_use) >= MI_NPIXELS(mi))
402 color_use -= (float) MI_NPIXELS(mi);
403 while (((int) color_use) < 0)
404 color_use += (float) MI_NPIXELS(mi);
408 if (MI_NPIXELS(mi) > 2) {
409 color_use += SPINRATE * color_inc;
410 while (((int) color_use) >= MI_NPIXELS(mi))
411 color_use -= (float) MI_NPIXELS(mi);
414 r1 = braid->min_radius + r_diff * (float) (s);
415 x_1 = r1 * COSF(t + psi) + braid->center_x;
416 y_1 = r1 * SINF(t + psi) + braid->center_y;
417 x_2 = r1 * COSF(t + t_inc + psi) + braid->center_x;
418 y_2 = r1 * SINF(t + t_inc + psi) + braid->center_y;
419 if (MI_NPIXELS(mi) > 2)
420 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
422 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
424 XDrawLine(display, window, MI_GC(mi),
425 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
430 XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinRound);
432 if (++braid->age > MI_CYCLES(mi)) {
434 erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
441 release_braid(ModeInfo * mi)
443 if (braids != NULL) {
444 (void) free((void *) braids);
445 braids = (braidtype *) NULL;
450 refresh_braid(ModeInfo * mi)
455 #endif /* MODE_braid */