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" \
38 # define UNIFORM_COLORS
39 # include "xlockmore.h" /* from the xscreensaver distribution */
40 #else /* !STANDALONE */
41 # include "xlock.h" /* from the xlockmore distribution */
42 #endif /* !STANDALONE */
44 ModeSpecOpt braid_opts = {
45 0, NULL, 0, NULL, NULL };
48 #if defined( COLORROUND ) && defined( COLORCOMP )
53 #if !defined( COLORROUND ) && !defined( COLORCOMP )
55 /* to color in a circular pattern use COLORROUND */
58 /* to color by component use COLORCOMP */
63 #define MAXLENGTH 50 /* the maximum length of a braid word */
64 #define MINLENGTH 8 /* the minimum length of a braid word */
65 #define MAXSTRANDS 15 /* the maximum number of strands in the braid */
66 #define MINSTRANDS 3 /* the minimum number of strands in the braid */
67 #define SPINRATE 12.0 /* the rate at which the colors spin */
69 #define INTRAND(min,max) (NRAND((max+1)-(min))+(min))
70 #define FLOATRAND(min,max) ((min)+((double) LRAND()/((double) MAXRAND))*((max)-(min)))
73 int braidword[MAXLENGTH];
74 int components[MAXSTRANDS];
75 int startcomp[MAXLENGTH][MAXSTRANDS];
83 float top, bottom, left, right;
88 static braidtype *braids = NULL;
91 applyword(braidtype * braid, int string, int position)
96 for (i = position; i < braid->braidlength; i++) {
97 if (c == ABS(braid->braidword[i]))
99 else if (c == ABS(braid->braidword[i]) - 1)
102 for (i = 0; i < position; i++) {
103 if (c == ABS(braid->braidword[i]))
105 else if (c == ABS(braid->braidword[i]) - 1)
113 applywordto(braidtype * braid, int string, int position)
118 for (i = 0; i < position; i++) {
119 if (c == ABS(braid->braidword[i])) {
121 } else if (c == ABS(braid->braidword[i]) - 1) {
130 applywordbackto(braidtype * braid, int string, int position)
135 for (i = position - 1; i >= 0; i--) {
136 if (c == ABS(braid->braidword[i])) {
138 } else if (c == ABS(braid->braidword[i]) - 1) {
146 init_braid(ModeInfo * mi)
148 Display *display = MI_DISPLAY(mi);
150 int used[MAXSTRANDS];
151 int i, count, comp, c;
154 if (braids == NULL) {
155 if ((braids = (braidtype *) calloc(MI_NUM_SCREENS(mi),
156 sizeof (braidtype))) == NULL)
159 braid = &braids[MI_SCREEN(mi)];
161 braid->center_x = MI_WIN_WIDTH(mi) / 2;
162 braid->center_y = MI_WIN_HEIGHT(mi) / 2;
165 /* jwz: go in the other direction sometimes. */
166 braid->color_direction = ((LRAND() & 1) ? 1 : -1);
168 XClearWindow(display, MI_WINDOW(mi));
170 min_length = (braid->center_x > braid->center_y) ?
171 braid->center_y : braid->center_x;
172 braid->min_radius = min_length * 0.30;
173 braid->max_radius = min_length * 0.90;
175 if (MI_BATCHCOUNT(mi) < MINSTRANDS)
176 braid->nstrands = MINSTRANDS;
178 braid->nstrands = INTRAND(MINSTRANDS,
179 MAX(MIN(MIN(MAXSTRANDS, MI_BATCHCOUNT(mi)),
180 (int) ((braid->max_radius - braid->min_radius) / 5.0)), MINSTRANDS));
181 braid->braidlength = INTRAND(MINLENGTH, MIN(MAXLENGTH, braid->nstrands * 6));
183 for (i = 0; i < braid->braidlength; i++) {
184 braid->braidword[i] =
185 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
187 while (braid->braidword[i] == -braid->braidword[i - 1])
188 braid->braidword[i] = INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
191 while (braid->braidword[0] == -braid->braidword[braid->braidlength - 1])
192 braid->braidword[braid->braidlength - 1] =
193 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
196 (void) memset((char *) used, 0, sizeof (used));
198 for (i = 0; i < braid->braidlength; i++)
199 used[ABS(braid->braidword[i])]++;
200 for (i = 0; i < braid->nstrands; i++)
201 count += (used[i] > 0) ? 1 : 0;
202 if (count < braid->nstrands - 1) {
203 braid->braidword[braid->braidlength] =
204 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
205 while (braid->braidword[braid->braidlength] ==
206 -braid->braidword[braid->braidlength - 1] &&
207 braid->braidword[0] == -braid->braidword[braid->braidlength])
208 braid->braidword[braid->braidlength] =
209 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
210 braid->braidlength++;
212 } while (count < braid->nstrands - 1 && braid->braidlength < MAXLENGTH);
214 braid->startcolor = (MI_NPIXELS(mi) > 2) ?
215 (float) NRAND(MI_NPIXELS(mi)) : 0.0;
216 /* XSetLineAttributes (display, MI_GC(mi), 2, LineSolid, CapRound,
219 (void) memset((char *) braid->components, 0, sizeof (braid->components));
222 braid->components[0] = 1;
226 i = applyword(braid, i, 0);
227 braid->components[i] = braid->components[comp];
230 for (i = 0; i < braid->nstrands; i++)
231 if (braid->components[i] == 0)
234 for (comp = 0; braid->components[comp] != 0; comp++);
235 braid->components[comp] = ++c;
239 for (i = 0; i < braid->nstrands; i++)
240 if (!(braid->components[i] & 1))
241 braid->components[i] *= -1;
245 draw_braid(ModeInfo * mi)
247 Display *display = MI_DISPLAY(mi);
248 Window window = MI_WINDOW(mi);
249 braidtype *braid = &braids[MI_SCREEN(mi)];
250 float num_points, t_inc;
254 float x_1, y_1, x_2, y_2, r1, r2;
255 float color, color_use = 0.0, color_inc;
258 theta = (2.0 * M_PI) / (float) (braid->braidlength);
259 t_inc = (2.0 * M_PI) / num_points;
260 color_inc = (float) MI_NPIXELS(mi) / num_points;
261 color_inc *= braid->color_direction;
263 braid->startcolor += SPINRATE * color_inc;
264 if (braid->startcolor >= MI_NPIXELS(mi))
265 braid->startcolor = 0.0;
267 r_diff = (braid->max_radius - braid->min_radius) / (float) (braid->nstrands);
269 color = braid->startcolor;
271 for (i = 0; i < braid->braidlength; i++) {
273 for (t = 0.0; t < theta; t += t_inc) {
276 if (color >= (float) (MI_NPIXELS(mi)))
280 for (s = 0; s < braid->nstrands; s++) {
281 if (ABS(braid->braidword[i]) == s)
283 if (ABS(braid->braidword[i]) - 1 == s) {
286 if (MI_NPIXELS(mi) > 2) {
287 color_use = color + SPINRATE *
288 braid->components[applywordbackto(braid, s, i)] +
289 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
290 while (color_use >= (float) MI_NPIXELS(mi))
291 color_use -= (float) MI_NPIXELS(mi);
292 while (color_use < 0.0)
293 color_use += (float) MI_NPIXELS(mi);
297 if (MI_NPIXELS(mi) > 2) {
298 color_use += SPINRATE * color_inc;
299 while (color_use >= (float) (MI_NPIXELS(mi)))
300 color_use -= (float) MI_NPIXELS(mi);
303 r1 = braid->min_radius + r_diff * (float) (s);
304 r2 = braid->min_radius + r_diff * (float) (s + 1);
305 if (braid->braidword[i] > 0 ||
306 (FABSF(t - theta / 2.0) > theta / 7.0)) {
307 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
308 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
309 COSF(t + psi) + braid->center_x;
310 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
311 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
312 SINF(t + psi) + braid->center_y;
313 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
314 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
315 COSF(t + t_inc + psi) + braid->center_x;
316 y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
317 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
318 SINF(t + t_inc + psi) + braid->center_y;
319 if (MI_NPIXELS(mi) > 2)
320 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
322 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
324 XDrawLine(display, window, MI_GC(mi),
325 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
328 if (MI_NPIXELS(mi) > 2) {
329 color_use = color + SPINRATE *
330 braid->components[applywordbackto(braid, s + 1, i)] +
331 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
332 while (color_use >= (float) MI_NPIXELS(mi))
333 color_use -= (float) MI_NPIXELS(mi);
334 while (color_use < 0.0)
335 color_use += (float) MI_NPIXELS(mi);
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)) * r1 +
341 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
342 COSF(t + psi) + braid->center_x;
343 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
344 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
345 SINF(t + psi) + braid->center_y;
346 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
347 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
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)) * r1 +
350 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
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));
355 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
357 XDrawLine(display, window, MI_GC(mi),
358 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
363 if (MI_NPIXELS(mi) > 2) {
364 color_use = color + SPINRATE *
365 braid->components[applywordbackto(braid, s, i)] +
366 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
367 while (color_use >= (float) MI_NPIXELS(mi))
368 color_use -= (float) MI_NPIXELS(mi);
369 while (color_use < 0.0)
370 color_use += (float) MI_NPIXELS(mi);
374 if (MI_NPIXELS(mi) > 2) {
375 color_use += SPINRATE * color_inc;
376 while (color_use >= (float) MI_NPIXELS(mi))
377 color_use -= (float) MI_NPIXELS(mi);
380 r1 = braid->min_radius + r_diff * (float) (s);
381 x_1 = r1 * COSF(t + psi) + braid->center_x;
382 y_1 = r1 * SINF(t + psi) + braid->center_y;
383 x_2 = r1 * COSF(t + t_inc + psi) + braid->center_x;
384 y_2 = r1 * 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));
388 XSetForeground(display, MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
390 XDrawLine(display, window, MI_GC(mi),
391 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
397 if (++braid->age > MI_CYCLES(mi))
402 release_braid(ModeInfo * mi)
404 if (braids != NULL) {
405 (void) free((void *) braids);
411 refresh_braid(ModeInfo * mi)
413 /* Do nothing, it will refresh by itself */