1 /* -*- Mode: C; tab-width: 4 -*- */
3 * braid --- random braids around a circle and then changes the color in
8 static const char sccsid[] = "@(#)braid.c 5.00 2000/11/01 xlockmore";
12 * Copyright (c) 1995 by John Neil.
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.
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.
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>
35 # define DEFAULTS "*delay: 1000 \n" \
40 "*fpsSolid: true \n" \
41 "*ignoreRotation: True" \
43 # define UNIFORM_COLORS
45 # define release_braid 0
46 # define reshape_braid 0
47 # define braid_handle_event 0
48 # include "xlockmore.h"
49 #else /* STANDALONE */
51 # define ENTRYPOINT /**/
52 #endif /* STANDALONE */
56 ENTRYPOINT ModeSpecOpt braid_opts = {0, NULL, 0, NULL, NULL};
59 ModStruct braid_description =
60 {"braid", "init_braid", "draw_braid", (char *) NULL,
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 MI_INIT (mi, braids);
174 braid = &braids[MI_SCREEN(mi)];
176 braid->center_x = MI_WIDTH(mi) / 2;
177 braid->center_y = MI_HEIGHT(mi) / 2;
180 /* jwz: go in the other direction sometimes. */
181 braid->color_direction = ((LRAND() & 1) ? 1 : -1);
185 min_length = (braid->center_x > braid->center_y) ?
186 braid->center_y : braid->center_x;
187 braid->min_radius = min_length * 0.30;
188 braid->max_radius = min_length * 0.90;
190 if (MI_COUNT(mi) < MINSTRANDS)
191 braid->nstrands = MINSTRANDS;
193 braid->nstrands = INTRAND(MINSTRANDS,
194 MAX(MIN(MIN(MAXSTRANDS, MI_COUNT(mi)),
195 (int) ((braid->max_radius - braid->min_radius) / 5.0)), MINSTRANDS));
196 braid->braidlength = INTRAND(MINLENGTH, MIN(MAXLENGTH -1, braid->nstrands * 6));
198 for (i = 0; i < braid->braidlength; i++) {
199 braid->braidword[i] =
200 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
202 while (braid->braidword[i] == -braid->braidword[i - 1])
203 braid->braidword[i] = INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
206 while (braid->braidword[0] == -braid->braidword[braid->braidlength - 1])
207 braid->braidword[braid->braidlength - 1] =
208 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
211 (void) memset((char *) used, 0, sizeof (used));
213 for (i = 0; i < braid->braidlength; i++)
214 used[ABS(braid->braidword[i])]++;
215 for (i = 0; i < braid->nstrands; i++)
216 count += (used[i] > 0) ? 1 : 0;
217 if (count < braid->nstrands - 1) {
218 braid->braidword[braid->braidlength] =
219 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
220 while (braid->braidword[braid->braidlength] ==
221 -braid->braidword[braid->braidlength - 1] &&
222 braid->braidword[0] == -braid->braidword[braid->braidlength])
223 braid->braidword[braid->braidlength] =
224 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
225 braid->braidlength++;
227 } while (count < braid->nstrands - 1 && braid->braidlength < MAXLENGTH);
229 braid->startcolor = (MI_NPIXELS(mi) > 2) ?
230 (float) NRAND(MI_NPIXELS(mi)) : 0.0;
231 /* XSetLineAttributes (display, MI_GC(mi), 2, LineSolid, CapRound,
234 (void) memset((char *) braid->components, 0, sizeof (braid->components));
237 braid->components[0] = 1;
241 i = applyword(braid, i, 0);
242 braid->components[i] = braid->components[comp];
245 for (i = 0; i < braid->nstrands; i++)
246 if (braid->components[i] == 0)
249 for (comp = 0; braid->components[comp] != 0; comp++);
250 braid->components[comp] = ++c;
254 braid->linewidth = MI_SIZE(mi);
256 if (braid->linewidth < 0)
257 braid->linewidth = NRAND(-braid->linewidth) + 1;
258 if (braid->linewidth * braid->linewidth * 8 > MIN(MI_WIDTH(mi), MI_HEIGHT(mi)))
259 braid->linewidth = MIN(1, (int) sqrt((double) MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) / 8));
260 for (i = 0; i < braid->nstrands; i++)
261 if (!(braid->components[i] & 1))
262 braid->components[i] *= -1;
266 draw_braid(ModeInfo * mi)
268 Display *display = MI_DISPLAY(mi);
269 Window window = MI_WINDOW(mi);
270 int num_points = 500;
275 float x_1, y_1, x_2, y_2, r1, r2;
276 float color, color_use = 0.0, color_inc;
281 braid = &braids[MI_SCREEN(mi)];
283 MI_IS_DRAWN(mi) = True;
284 XSetLineAttributes(display, MI_GC(mi), braid->linewidth,
286 (braid->linewidth <= 3 ? CapButt : CapRound),
289 theta = (2.0 * M_PI) / (float) (braid->braidlength);
290 t_inc = (2.0 * M_PI) / (float) num_points;
291 color_inc = (float) MI_NPIXELS(mi) * braid->color_direction /
293 braid->startcolor += SPINRATE * color_inc;
294 if (((int) braid->startcolor) >= MI_NPIXELS(mi))
295 braid->startcolor = 0.0;
297 r_diff = (braid->max_radius - braid->min_radius) / (float) (braid->nstrands);
299 color = braid->startcolor;
301 for (i = 0; i < braid->braidlength; i++) {
303 for (t = 0.0; t < theta; t += t_inc) {
306 if (((int) color) >= MI_NPIXELS(mi))
310 for (s = 0; s < braid->nstrands; s++) {
311 if (ABS(braid->braidword[i]) == s)
313 if (ABS(braid->braidword[i]) - 1 == s) {
316 if (MI_NPIXELS(mi) > 2) {
317 color_use = color + SPINRATE *
318 braid->components[applywordbackto(braid, s, i)] +
319 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
320 while (((int) color_use) >= MI_NPIXELS(mi))
321 color_use -= (float) MI_NPIXELS(mi);
322 while (((int) color_use) < 0)
323 color_use += (float) MI_NPIXELS(mi);
327 if (MI_NPIXELS(mi) > 2) {
328 color_use += SPINRATE * color_inc;
329 while (((int) color_use) >= MI_NPIXELS(mi))
330 color_use -= (float) MI_NPIXELS(mi);
333 r1 = braid->min_radius + r_diff * (float) (s);
334 r2 = braid->min_radius + r_diff * (float) (s + 1);
335 if (braid->braidword[i] > 0 ||
336 (FABSF(t - theta / 2.0) > theta / 7.0)) {
337 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
338 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
339 COSF(t + psi) + braid->center_x;
340 y_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 SINF(t + psi) + braid->center_y;
343 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
344 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
345 COSF(t + t_inc + psi) + braid->center_x;
346 y_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 SINF(t + t_inc + psi) + braid->center_y;
349 if (MI_NPIXELS(mi) > 2)
350 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
352 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
354 XDrawLine(display, window, MI_GC(mi),
355 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
358 if (MI_NPIXELS(mi) > 2) {
359 color_use = color + SPINRATE *
360 braid->components[applywordbackto(braid, s + 1, i)] +
361 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
362 while (((int) color_use) >= MI_NPIXELS(mi))
363 color_use -= (float) MI_NPIXELS(mi);
364 while (((int) color_use) < 0)
365 color_use += (float) MI_NPIXELS(mi);
368 if (braid->braidword[i] < 0 ||
369 (FABSF(t - theta / 2.0) > theta / 7.0)) {
370 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
371 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
372 COSF(t + psi) + braid->center_x;
373 y_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 SINF(t + psi) + braid->center_y;
376 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
377 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
378 COSF(t + t_inc + psi) + braid->center_x;
379 y_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 SINF(t + t_inc + psi) + braid->center_y;
382 if (MI_NPIXELS(mi) > 2)
383 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
385 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
387 XDrawLine(display, window, MI_GC(mi),
388 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
393 if (MI_NPIXELS(mi) > 2) {
394 color_use = color + SPINRATE *
395 braid->components[applywordbackto(braid, s, i)] +
396 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
397 while (((int) color_use) >= MI_NPIXELS(mi))
398 color_use -= (float) MI_NPIXELS(mi);
399 while (((int) color_use) < 0)
400 color_use += (float) MI_NPIXELS(mi);
404 if (MI_NPIXELS(mi) > 2) {
405 color_use += SPINRATE * color_inc;
406 while (((int) color_use) >= MI_NPIXELS(mi))
407 color_use -= (float) MI_NPIXELS(mi);
410 r1 = braid->min_radius + r_diff * (float) (s);
411 x_1 = r1 * COSF(t + psi) + braid->center_x;
412 y_1 = r1 * SINF(t + psi) + braid->center_y;
413 x_2 = r1 * COSF(t + t_inc + psi) + braid->center_x;
414 y_2 = r1 * SINF(t + t_inc + psi) + braid->center_y;
415 if (MI_NPIXELS(mi) > 2)
416 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
418 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
420 XDrawLine(display, window, MI_GC(mi),
421 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
426 XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinRound);
428 if (++braid->age > MI_CYCLES(mi)) {
435 refresh_braid(ModeInfo * mi)
441 XSCREENSAVER_MODULE ("Braid", braid)
443 #endif /* MODE_braid */