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
44 # define release_braid 0
45 # include "xlockmore.h"
47 #else /* STANDALONE */
49 # define ENTRYPOINT /**/
50 #endif /* STANDALONE */
54 ENTRYPOINT ModeSpecOpt braid_opts = {0, NULL, 0, NULL, NULL};
57 ModStruct braid_description =
58 {"braid", "init_braid", "draw_braid", (char *) NULL,
59 "refresh_braid", "init_braid", (char *) NULL, &braid_opts,
60 1000, 15, 100, 1, 64, 1.0, "",
61 "Shows random braids and knots", 0, NULL};
65 #if defined( COLORROUND ) && defined( COLORCOMP )
70 #if !defined( COLORROUND ) && !defined( COLORCOMP )
72 /* to color in a circular pattern use COLORROUND */
75 /* to color by component use COLORCOMP */
80 #define MAXLENGTH 50 /* the maximum length of a braid word */
81 #define MINLENGTH 8 /* the minimum length of a braid word */
82 #define MAXSTRANDS 15 /* the maximum number of strands in the braid */
83 #define MINSTRANDS 3 /* the minimum number of strands in the braid */
84 #define SPINRATE 12.0 /* the rate at which the colors spin */
86 #define INTRAND(min,max) (NRAND((max+1)-(min))+(min))
87 #define FLOATRAND(min,max) ((min)+((double) LRAND()/((double) MAXRAND))*((max)-(min)))
91 int braidword[MAXLENGTH];
92 int components[MAXSTRANDS];
93 int startcomp[MAXLENGTH][MAXSTRANDS];
101 float top, bottom, left, right;
105 eraser_state *eraser;
109 static braidtype *braids = (braidtype *) NULL;
112 applyword(braidtype * braid, int string, int position)
117 for (i = position; i < braid->braidlength; i++) {
118 if (c == ABS(braid->braidword[i]))
120 else if (c == ABS(braid->braidword[i]) - 1)
123 for (i = 0; i < position; i++) {
124 if (c == ABS(braid->braidword[i]))
126 else if (c == ABS(braid->braidword[i]) - 1)
134 applywordto(braidtype * braid, int string, int position)
139 for (i = 0; i < position; i++) {
140 if (c == ABS(braid->braidword[i])) {
142 } else if (c == ABS(braid->braidword[i]) - 1) {
151 applywordbackto(braidtype * braid, int string, int position)
156 for (i = position - 1; i >= 0; i--) {
157 if (c == ABS(braid->braidword[i])) {
159 } else if (c == ABS(braid->braidword[i]) - 1) {
167 init_braid(ModeInfo * mi)
170 int used[MAXSTRANDS];
171 int i, count, comp, c;
174 MI_INIT (mi, braids, 0);
175 braid = &braids[MI_SCREEN(mi)];
177 braid->center_x = MI_WIDTH(mi) / 2;
178 braid->center_y = MI_HEIGHT(mi) / 2;
181 /* jwz: go in the other direction sometimes. */
182 braid->color_direction = ((LRAND() & 1) ? 1 : -1);
188 min_length = (braid->center_x > braid->center_y) ?
189 braid->center_y : braid->center_x;
190 braid->min_radius = min_length * 0.30;
191 braid->max_radius = min_length * 0.90;
193 if (MI_COUNT(mi) < MINSTRANDS)
194 braid->nstrands = MINSTRANDS;
196 braid->nstrands = INTRAND(MINSTRANDS,
197 MAX(MIN(MIN(MAXSTRANDS, MI_COUNT(mi)),
198 (int) ((braid->max_radius - braid->min_radius) / 5.0)), MINSTRANDS));
199 braid->braidlength = INTRAND(MINLENGTH, MIN(MAXLENGTH -1, braid->nstrands * 6));
201 for (i = 0; i < braid->braidlength; i++) {
202 braid->braidword[i] =
203 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
205 while (braid->braidword[i] == -braid->braidword[i - 1])
206 braid->braidword[i] = INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
209 while (braid->braidword[0] == -braid->braidword[braid->braidlength - 1])
210 braid->braidword[braid->braidlength - 1] =
211 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
214 (void) memset((char *) used, 0, sizeof (used));
216 for (i = 0; i < braid->braidlength; i++)
217 used[ABS(braid->braidword[i])]++;
218 for (i = 0; i < braid->nstrands; i++)
219 count += (used[i] > 0) ? 1 : 0;
220 if (count < braid->nstrands - 1) {
221 braid->braidword[braid->braidlength] =
222 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
223 while (braid->braidword[braid->braidlength] ==
224 -braid->braidword[braid->braidlength - 1] &&
225 braid->braidword[0] == -braid->braidword[braid->braidlength])
226 braid->braidword[braid->braidlength] =
227 INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3);
228 braid->braidlength++;
230 } while (count < braid->nstrands - 1 && braid->braidlength < MAXLENGTH);
232 braid->startcolor = (MI_NPIXELS(mi) > 2) ?
233 (float) NRAND(MI_NPIXELS(mi)) : 0.0;
234 /* XSetLineAttributes (display, MI_GC(mi), 2, LineSolid, CapRound,
237 (void) memset((char *) braid->components, 0, sizeof (braid->components));
240 braid->components[0] = 1;
244 i = applyword(braid, i, 0);
245 braid->components[i] = braid->components[comp];
248 for (i = 0; i < braid->nstrands; i++)
249 if (braid->components[i] == 0)
252 for (comp = 0; braid->components[comp] != 0; comp++);
253 braid->components[comp] = ++c;
257 braid->linewidth = MI_SIZE(mi);
259 if (braid->linewidth < 0)
260 braid->linewidth = NRAND(-braid->linewidth) + 1;
261 if (braid->linewidth * braid->linewidth * 8 > MIN(MI_WIDTH(mi), MI_HEIGHT(mi)))
262 braid->linewidth = MIN(1, (int) sqrt((double) MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) / 8));
263 for (i = 0; i < braid->nstrands; i++)
264 if (!(braid->components[i] & 1))
265 braid->components[i] *= -1;
269 draw_braid(ModeInfo * mi)
271 Display *display = MI_DISPLAY(mi);
272 Window window = MI_WINDOW(mi);
273 int num_points = 500;
278 float x_1, y_1, x_2, y_2, r1, r2;
279 float color, color_use = 0.0, color_inc;
284 braid = &braids[MI_SCREEN(mi)];
288 braid->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), braid->eraser);
295 MI_IS_DRAWN(mi) = True;
296 XSetLineAttributes(display, MI_GC(mi), braid->linewidth,
298 (braid->linewidth <= 3 ? CapButt : CapRound),
301 theta = (2.0 * M_PI) / (float) (braid->braidlength);
302 t_inc = (2.0 * M_PI) / (float) num_points;
303 color_inc = (float) MI_NPIXELS(mi) * braid->color_direction /
305 braid->startcolor += SPINRATE * color_inc;
306 if (((int) braid->startcolor) >= MI_NPIXELS(mi))
307 braid->startcolor = 0.0;
309 r_diff = (braid->max_radius - braid->min_radius) / (float) (braid->nstrands);
311 color = braid->startcolor;
313 for (i = 0; i < braid->braidlength; i++) {
315 for (t = 0.0; t < theta; t += t_inc) {
318 if (((int) color) >= MI_NPIXELS(mi))
322 for (s = 0; s < braid->nstrands; s++) {
323 if (ABS(braid->braidword[i]) == s)
325 if (ABS(braid->braidword[i]) - 1 == s) {
328 if (MI_NPIXELS(mi) > 2) {
329 color_use = color + SPINRATE *
330 braid->components[applywordbackto(braid, s, i)] +
331 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
332 while (((int) color_use) >= MI_NPIXELS(mi))
333 color_use -= (float) MI_NPIXELS(mi);
334 while (((int) color_use) < 0)
335 color_use += (float) MI_NPIXELS(mi);
339 if (MI_NPIXELS(mi) > 2) {
340 color_use += SPINRATE * color_inc;
341 while (((int) color_use) >= MI_NPIXELS(mi))
342 color_use -= (float) MI_NPIXELS(mi);
345 r1 = braid->min_radius + r_diff * (float) (s);
346 r2 = braid->min_radius + r_diff * (float) (s + 1);
347 if (braid->braidword[i] > 0 ||
348 (FABSF(t - theta / 2.0) > theta / 7.0)) {
349 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
350 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
351 COSF(t + psi) + braid->center_x;
352 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 +
353 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) *
354 SINF(t + psi) + braid->center_y;
355 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
356 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
357 COSF(t + t_inc + psi) + braid->center_x;
358 y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 +
359 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) *
360 SINF(t + t_inc + psi) + braid->center_y;
361 if (MI_NPIXELS(mi) > 2)
362 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
364 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
366 XDrawLine(display, window, MI_GC(mi),
367 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
370 if (MI_NPIXELS(mi) > 2) {
371 color_use = color + SPINRATE *
372 braid->components[applywordbackto(braid, s + 1, i)] +
373 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
374 while (((int) color_use) >= MI_NPIXELS(mi))
375 color_use -= (float) MI_NPIXELS(mi);
376 while (((int) color_use) < 0)
377 color_use += (float) MI_NPIXELS(mi);
380 if (braid->braidword[i] < 0 ||
381 (FABSF(t - theta / 2.0) > theta / 7.0)) {
382 x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
383 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
384 COSF(t + psi) + braid->center_x;
385 y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 +
386 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) *
387 SINF(t + psi) + braid->center_y;
388 x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
389 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
390 COSF(t + t_inc + psi) + braid->center_x;
391 y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 +
392 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) *
393 SINF(t + t_inc + psi) + braid->center_y;
394 if (MI_NPIXELS(mi) > 2)
395 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
397 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
399 XDrawLine(display, window, MI_GC(mi),
400 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
405 if (MI_NPIXELS(mi) > 2) {
406 color_use = color + SPINRATE *
407 braid->components[applywordbackto(braid, s, i)] +
408 (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi);
409 while (((int) color_use) >= MI_NPIXELS(mi))
410 color_use -= (float) MI_NPIXELS(mi);
411 while (((int) color_use) < 0)
412 color_use += (float) MI_NPIXELS(mi);
416 if (MI_NPIXELS(mi) > 2) {
417 color_use += SPINRATE * color_inc;
418 while (((int) color_use) >= MI_NPIXELS(mi))
419 color_use -= (float) MI_NPIXELS(mi);
422 r1 = braid->min_radius + r_diff * (float) (s);
423 x_1 = r1 * COSF(t + psi) + braid->center_x;
424 y_1 = r1 * SINF(t + psi) + braid->center_y;
425 x_2 = r1 * COSF(t + t_inc + psi) + braid->center_x;
426 y_2 = r1 * SINF(t + t_inc + psi) + braid->center_y;
427 if (MI_NPIXELS(mi) > 2)
428 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use));
430 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
432 XDrawLine(display, window, MI_GC(mi),
433 (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2));
438 XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinRound);
440 if (++braid->age > MI_CYCLES(mi)) {
442 braid->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), braid->eraser);
450 reshape_braid(ModeInfo * mi, int width, int height)
452 XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi));
457 braid_handle_event (ModeInfo *mi, XEvent *event)
459 if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
461 reshape_braid (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
469 refresh_braid(ModeInfo * mi)
474 XSCREENSAVER_MODULE ("Braid", braid)
476 #endif /* MODE_braid */