1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* kaleid --- Brewster's Kaleidoscope */
3
4 #if 0
5 static const char sccsid[] = "@(#)kaleid.c 5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10 *
11 * kaleid.c - Brewster's Kaleidoscope (Sir David Brewster invented the
12 * kaleidoscope in 1816 and patented it in 1817.)
13 *
14 * Copyright (c) 1998 by Robert Adam, II <raii@comm.net>
15 *
16 * Permission to use, copy, modify, and distribute this software and its
17 * documentation for any purpose and without fee is hereby granted,
18 * provided that the above copyright notice appear in all copies and that
19 * both that copyright notice and this permission notice appear in
20 * supporting documentation.
21 *
22 * This file is provided AS IS with no warranties of any kind. The author
23 * shall have no liability with respect to the infringement of copyrights,
24 * trade secrets or any patents by this file or any part thereof. In no
25 * event will the author be liable for any lost revenue or profits or
26 * other special, indirect and consequential damages.
27 *
28 * Revision History:
29 * 01-Nov-2000: Allocation checks
30 * 1998: Written
31 *
32 *
33 * -batchcount n number of pens [default 4]
34 *
35 * -cycle n percentage of black in the pattern (0%-95%)
36 *
37 * -size n symmetry mode [default -9]
38 * <0 = random from 0 to -number
39 * >0 = mirrored (-alternate)
40 * rotated (+alternate)
41 *
42 *
43 * -/+disconnected turn on/off disconnected pen movement
44 *
45 * -/+serial turn on/off sequential allocation of colors
46 *
47 * -/+alternate turn on/off alternate display mode
48 *
49 * -/+spiral turn on/off spiral mode
50 *
51 * -/+spots turn on/off spots mode
52 *
53 * -/+quad turn on/off quad mirrored/rotated mode similar
54 * to size 4, works with alternate
55 *
56 * -/+oct turn on/off oct mirrored/rotated moded similar
57 * to size 8, works with alternate
58 *
59 * -/+linear select Cartesian/Polar coordinate mode. Cartesian
60 * uses straight lines similar to -oct and -quad
61 * mode instead of the curved lines of Polar mode.
62 * [default off]
63 *
64 */
65
66 #ifdef STANDALONE
67 #define MODE_kaleid
68 #define DEFAULTS "*delay: 80000 \n" \
69 "*count: 4 \n" \
70 "*cycles: 40 \n" \
71 "*size: -9 \n" \
72 "*ncolors: 200 \n" \
73 "*fullrandom: False \n" \
74
75 # define free_kaleid 0
76 # define reshape_kaleid 0
77 # define kaleid_handle_event 0
78 #define UNIFORM_COLORS
79 #define BRIGHT_COLORS
80 #include "xlockmore.h" /* in xscreensaver distribution */
81 #else /* STANDALONE */
82 #include "xlock.h" /* in xlockmore distribution */
83 #endif /* STANDALONE */
84
85 #ifdef MODE_kaleid
86
87 #include <math.h>
88
89 #define DEF_DISCONNECTED "True"
90 #define DEF_SERIAL "False"
91 #define DEF_ALTERNATE "False"
92 #define DEF_QUAD "False"
93 #define DEF_OCT "False"
94 #define DEF_LINEAR "False"
95 #define DEF_SPIRAL "False"
96 #define DEF_SPOTS "False"
97
98 static Bool Disconnected;
99 static Bool Serial;
100 static Bool Alternate;
101 static Bool Quad;
102 static Bool Oct;
103 static Bool Linear;
104 static Bool Spiral;
105 static Bool Spots;
106
107 static XrmOptionDescRec opts[] =
108 {
109 {(char *) "-disconnected", (char *) ".kaleid.disconnected", XrmoptionNoArg, (caddr_t) "on"},
110 {(char *) "+disconnected", (char *) ".kaleid.disconnected", XrmoptionNoArg, (caddr_t) "off"},
111 {(char *) "-serial", (char *) ".kaleid.serial", XrmoptionNoArg, (caddr_t) "on"},
112 {(char *) "+serial", (char *) ".kaleid.serial", XrmoptionNoArg, (caddr_t) "off"},
113 {(char *) "-alternate", (char *) ".kaleid.alternate", XrmoptionNoArg, (caddr_t) "on"},
114 {(char *) "+alternate", (char *) ".kaleid.alternate", XrmoptionNoArg, (caddr_t) "off"},
115 {(char *) "-spiral", (char *) ".kaleid.spiral", XrmoptionNoArg, (caddr_t) "on"},
116 {(char *) "+spiral", (char *) ".kaleid.spiral", XrmoptionNoArg, (caddr_t) "off"},
117 {(char *) "-spots", (char *) ".kaleid.spots", XrmoptionNoArg, (caddr_t) "on"},
118 {(char *) "+spots", (char *) ".kaleid.spots", XrmoptionNoArg, (caddr_t) "off"},
119 {(char *) "-quad", (char *) ".kaleid.quad", XrmoptionNoArg, (caddr_t) "on"},
120 {(char *) "+quad", (char *) ".kaleid.quad", XrmoptionNoArg, (caddr_t) "off"},
121 {(char *) "-oct", (char *) ".kaleid.oct", XrmoptionNoArg, (caddr_t) "on"},
122 {(char *) "+oct", (char *) ".kaleid.oct", XrmoptionNoArg, (caddr_t) "off"},
123 {(char *) "-linear", (char *) ".kaleid.linear", XrmoptionNoArg, (caddr_t) "on"},
124 {(char *) "+linear", (char *) ".kaleid.linear", XrmoptionNoArg, (caddr_t) "off"}
125 };
126
127 static argtype vars[] =
128 {
129 {(void *) & Disconnected, (char *) "disconnected", (char *) "Disconnected", (char *) DEF_DISCONNECTED, t_Bool},
130 {(void *) & Serial, (char *) "serial", (char *) "Serial", (char *) DEF_SERIAL, t_Bool},
131 {(void *) & Alternate, (char *) "alternate", (char *) "Alternate", (char *) DEF_ALTERNATE, t_Bool},
132 {(void *) & Spiral, (char *) "spiral", (char *) "Spiral", (char *) DEF_SPIRAL, t_Bool},
133 {(void *) & Spots, (char *) "spots", (char *) "Spots", (char *) DEF_SPOTS, t_Bool},
134 {(void *) & Quad, (char *) "quad", (char *) "Quad", (char *) DEF_QUAD, t_Bool},
135 {(void *) & Oct, (char *) "oct", (char *) "Oct", (char *) DEF_OCT, t_Bool},
136 {(void *) & Linear, (char *) "linear", (char *) "Linear", (char *) DEF_LINEAR, t_Bool}
137 };
138
139 static OptionStruct desc[] =
140 {
141 {(char *) "-/+disconnected", (char *) "turn on/off disconnected pen movement"},
142 {(char *) "-/+serial", (char *) "turn on/off sequential color selection"},
143 {(char *) "-/+alternate", (char *) "turn on/off alternate display mode"},
144 {(char *) "-/+spiral", (char *) "turn on/off angular bounding mode"},
145 {(char *) "-/+spots", (char *) "turn on/off circle mode"},
146 {(char *) "-/+quad", (char *) "turn on/off quad mirrored display mode"},
147 {(char *) "-/+oct", (char *) "turn on/off oct mirrored display mode"},
148 {(char *) "-/+linear", (char *) "select Cartesian/Polar coordinate display mode"}
149 };
150
151 ENTRYPOINT ModeSpecOpt kaleid_opts =
152 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
153
154 #ifdef USE_MODULES
155 ModStruct kaleid_description =
156 {
157 "kaleid", "init_kaleid", "draw_kaleid", "release_kaleid",
158 "refresh_kaleid", "init_kaleid", (char *) NULL, &kaleid_opts,
159 80000, 4, 40, -9, 64, 0.6, "",
160 "Shows Brewster's Kaleidoscope", 0, NULL
161 };
162
163 #endif
164
165 #define INTRAND(min,max) (NRAND(((max+1)-(min)))+(min))
166
167 #define MINPENS 1
168 #define MINSIZE 1
169 #define QUAD (-4)
170 #define OCT (-8)
171
172 #define SpotsMult 3
173
174 #define MinVelocity 6
175 #define MaxVelocity 4
176
177 #define MinRadialVelocity 6
178 #define MaxRadialVelocity 30
179
180 #define MinAngularVelocity 5
181 #define MaxAngularVelocity 3
182
183 #define WidthPercent 25
184 #define ChangeChance 2
185
186 #define ToRadians 0.017453293
187 #define ToDegrees 57.29577951
188 #define PolarToCartX(r, t) ((r) * cos((t) * ToRadians))
189 #define PolarToCartY(r, t) ((r) * sin((t) * ToRadians))
190 #define CartToRadius(x, y) (sqrt(((x)*(x)) + ((y)*(y))))
191 #define CartToAngle(x,y) ((((x) == 0.0) && ((y) == 0.0)) ? 0.0 : (atan2((y),(x)) * ToDegrees))
192
193 typedef struct {
194 double cx;
195 double cy;
196 double ox;
197 double oy;
198 double xv;
199 double yv;
200 int curlwidth;
201 int pix;
202 int White;
203 Bool RadiusOut;
204 Bool AngleOut;
205 Bool DeferredChange;
206 } penstruct;
207
208 typedef struct {
209 penstruct *pen;
210
211 int PercentBlack;
212 int PenCount;
213 int maxlwidth;
214 double width, widthby2;
215 double height, heightby2;
216 double radius;
217 double slice;
218 int bouncetype;
219 int modetype;
220 Bool alternate, disconnected, serial, linear, spiral, spots;
221 } kaleidstruct;
222
223 static kaleidstruct *kaleids = (kaleidstruct *) NULL;
224
225 /*-
226 *
227 */
228 static void
QuadMirrored(kaleidstruct * kp,int pn,XSegment segs[4])229 QuadMirrored(
230 kaleidstruct * kp,
231 int pn,
232 XSegment segs[4]
233 )
234 {
235 kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
236 if (kp->pen[pn].cx < 0.0) {
237 kp->pen[pn].cx = -kp->pen[pn].cx;
238 kp->pen[pn].xv = -kp->pen[pn].xv;
239 } else if (kp->pen[pn].cx >= kp->widthby2) {
240 kp->pen[pn].cx = (kp->widthby2 - 1.0)
241 - (kp->pen[pn].cx - kp->widthby2);
242 kp->pen[pn].xv = -kp->pen[pn].xv;
243 }
244 kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
245 if (kp->pen[pn].cy < 0.0) {
246 kp->pen[pn].cy = -kp->pen[pn].cy;
247 kp->pen[pn].yv = -kp->pen[pn].yv;
248 } else if (kp->pen[pn].cy >= kp->heightby2) {
249 kp->pen[pn].cy = (kp->heightby2 - 1.0)
250 - (kp->pen[pn].cy - kp->heightby2);
251 kp->pen[pn].yv = -kp->pen[pn].yv;
252 }
253 segs[0].x1 = (int) kp->pen[pn].ox;
254 segs[0].y1 = (int) kp->pen[pn].oy;
255 segs[0].x2 = (int) kp->pen[pn].cx;
256 segs[0].y2 = (int) kp->pen[pn].cy;
257
258 segs[1].x1 = (int) (kp->width - kp->pen[pn].ox);
259 segs[1].y1 = (int) kp->pen[pn].oy;
260 segs[1].x2 = (int) (kp->width - kp->pen[pn].cx);
261 segs[1].y2 = (int) kp->pen[pn].cy;
262
263 segs[2].x1 = (int) (kp->width - kp->pen[pn].ox);
264 segs[2].y1 = (int) (kp->height - kp->pen[pn].oy);
265 segs[2].x2 = (int) (kp->width - kp->pen[pn].cx);
266 segs[2].y2 = (int) (kp->height - kp->pen[pn].cy);
267
268 segs[3].x1 = (int) kp->pen[pn].ox;
269 segs[3].y1 = (int) (kp->height - kp->pen[pn].oy);
270 segs[3].x2 = (int) kp->pen[pn].cx;
271 segs[3].y2 = (int) (kp->height - kp->pen[pn].cy);
272
273 }
274
275 /*-
276 *
277 */
278 static void
QuadRotated(kaleidstruct * kp,int pn,XSegment segs[4])279 QuadRotated(
280 kaleidstruct * kp,
281 int pn,
282 XSegment segs[4]
283 )
284 {
285 double oxscaled2y;
286 double oyscaled2x;
287 double cxscaled2y;
288 double cyscaled2x;
289
290 kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
291 if (kp->pen[pn].cx < 0.0) {
292 kp->pen[pn].cx = -kp->pen[pn].cx;
293 kp->pen[pn].xv = -kp->pen[pn].xv;
294 } else if (kp->pen[pn].cx >= kp->widthby2) {
295 kp->pen[pn].cx = (kp->widthby2 - 1.0)
296 - (kp->pen[pn].cx - kp->widthby2);
297 kp->pen[pn].xv = -kp->pen[pn].xv;
298 }
299 kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
300 if (kp->pen[pn].cy < 0.0) {
301 kp->pen[pn].cy = -kp->pen[pn].cy;
302 kp->pen[pn].yv = -kp->pen[pn].yv;
303 } else if (kp->pen[pn].cy >= kp->heightby2) {
304 kp->pen[pn].cy = (kp->heightby2 - 1.0)
305 - (kp->pen[pn].cy - kp->heightby2);
306 kp->pen[pn].yv = -kp->pen[pn].yv;
307 }
308 segs[0].x1 = (int) kp->pen[pn].ox;
309 segs[0].y1 = (int) kp->pen[pn].oy;
310 segs[0].x2 = (int) kp->pen[pn].cx;
311 segs[0].y2 = (int) kp->pen[pn].cy;
312
313 oxscaled2y = ((kp->pen[pn].ox * kp->heightby2) / kp->widthby2);
314 oyscaled2x = ((kp->pen[pn].oy * kp->widthby2) / kp->heightby2);
315 cxscaled2y = ((kp->pen[pn].cx * kp->heightby2) / kp->widthby2);
316 cyscaled2x = ((kp->pen[pn].cy * kp->widthby2) / kp->heightby2);
317
318 segs[1].x1 = (int) (kp->width - oyscaled2x);
319 segs[1].y1 = (int) oxscaled2y;
320 segs[1].x2 = (int) (kp->width - cyscaled2x);
321 segs[1].y2 = (int) cxscaled2y;
322
323 segs[2].x1 = (int) (kp->width - kp->pen[pn].ox);
324 segs[2].y1 = (int) (kp->height - kp->pen[pn].oy);
325 segs[2].x2 = (int) (kp->width - kp->pen[pn].cx);
326 segs[2].y2 = (int) (kp->height - kp->pen[pn].cy);
327
328 segs[3].x1 = (int) oyscaled2x;
329 segs[3].y1 = (int) (kp->height - oxscaled2y);
330 segs[3].x2 = (int) cyscaled2x;
331 segs[3].y2 = (int) (kp->height - cxscaled2y);
332
333 }
334
335 /*-
336 *
337 */
338 static void
GeneralPolarMoveAndBounce(kaleidstruct * kp,int pn)339 GeneralPolarMoveAndBounce(
340 kaleidstruct * kp,
341 int pn
342 )
343 {
344 kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
345 if (kp->pen[pn].cx < 0.0) {
346 kp->pen[pn].cx = -kp->pen[pn].cx;
347 kp->pen[pn].xv = -kp->pen[pn].xv;
348 } else if (kp->pen[pn].cx >= kp->radius) {
349 kp->pen[pn].cx = (kp->radius - 1.0)
350 - (kp->pen[pn].cx - kp->radius);
351 kp->pen[pn].xv = -kp->pen[pn].xv;
352 }
353 switch (kp->bouncetype) {
354 case 0:
355 {
356 kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
357 break;
358 }
359 case 1:
360 {
361 kp->pen[pn].cy = kp->pen[pn].cy
362 + ((kp->pen[pn].yv * kp->pen[pn].cx) / kp->radius);
363 break;
364 }
365 case 2:
366 {
367 kp->pen[pn].cy = kp->pen[pn].cy
368 + ((kp->pen[pn].yv * (kp->radius - kp->pen[pn].cx)) / kp->radius);
369 break;
370 }
371 default:
372 {
373 kp->pen[pn].cy = kp->slice / 2.0;
374 kp->pen[pn].cx = kp->radius / 2.0;
375 break;
376 }
377 }
378
379 if (kp->pen[pn].cy < 0) {
380 if (kp->spiral) {
381 kp->pen[pn].RadiusOut = False;
382 kp->pen[pn].cy = kp->pen[pn].cy + 360.0;
383 } else {
384 kp->pen[pn].RadiusOut = True;
385 if (kp->pen[pn].oy >= 0) {
386 kp->pen[pn].yv = -kp->pen[pn].yv;
387 }
388 }
389 } else if (kp->spiral) {
390 if (kp->pen[pn].cy > 360.0) {
391 kp->pen[pn].RadiusOut = False;
392 kp->pen[pn].cy = kp->pen[pn].cy - 360.0;
393 }
394 } else if (kp->pen[pn].cy >= kp->slice) {
395 kp->pen[pn].RadiusOut = True;
396 if (kp->pen[pn].oy < kp->slice) {
397 kp->pen[pn].yv = -kp->pen[pn].yv;
398 }
399 } else {
400 kp->pen[pn].RadiusOut = False;
401 }
402
403 }
404
405
406 /*-
407 *
408 */
409 static void
GeneralRotated(kaleidstruct * kp,int pn,XSegment * segs)410 GeneralRotated(
411 kaleidstruct * kp,
412 int pn,
413 XSegment * segs
414 )
415 {
416 double Angle;
417 int segnum;
418
419
420 GeneralPolarMoveAndBounce(kp, pn);
421
422 Angle = 0.0;
423 for (segnum = 0; segnum < kp->modetype; segnum += 1) {
424 if (! kp->spots) {
425 segs[segnum].x1 = (int) (PolarToCartX(kp->pen[pn].ox,
426 kp->pen[pn].oy + Angle
427 ) + kp->widthby2
428 );
429
430 segs[segnum].y1 = (int) (PolarToCartY(kp->pen[pn].ox,
431 kp->pen[pn].oy + Angle
432 ) + kp->heightby2
433 );
434 }
435 segs[segnum].x2 = (int) (PolarToCartX(kp->pen[pn].cx,
436 kp->pen[pn].cy + Angle
437 ) + kp->widthby2
438 );
439 segs[segnum].y2 = (int) (PolarToCartY(kp->pen[pn].cx,
440 kp->pen[pn].cy + Angle
441 ) + kp->heightby2
442 );
443
444 if (kp->spots) {
445 segs[segnum].x1 = segs[segnum].x2;
446 segs[segnum].y1 = segs[segnum].y2;
447 }
448
449 Angle += kp->slice;
450 }
451 }
452
453 /*-
454 *
455 */
456 static void
GeneralMirrored(kaleidstruct * kp,int pn,XSegment * segs)457 GeneralMirrored(
458 kaleidstruct * kp,
459 int pn,
460 XSegment * segs
461 )
462 {
463 double Angle;
464 int segnum;
465
466 GeneralPolarMoveAndBounce(kp, pn);
467
468 Angle = 0.0;
469 for (segnum = 0; segnum < kp->modetype; segnum += 2) {
470 if (! kp->spots) {
471 segs[segnum].x1 = (int) (PolarToCartX(kp->pen[pn].ox,
472 kp->pen[pn].oy + Angle
473 ) + kp->widthby2
474 );
475
476 segs[segnum].y1 = (int) (PolarToCartY(kp->pen[pn].ox,
477 kp->pen[pn].oy + Angle
478 ) + kp->heightby2
479 );
480 }
481
482 segs[segnum].x2 = (int) (PolarToCartX(kp->pen[pn].cx,
483 kp->pen[pn].cy + Angle
484 ) + kp->widthby2
485 );
486
487 segs[segnum].y2 = (int) (PolarToCartY(kp->pen[pn].cx,
488 kp->pen[pn].cy + Angle
489 ) + kp->heightby2
490 );
491
492 if (kp->spots) {
493 segs[segnum].x1 = segs[segnum].x2;
494 segs[segnum].y1 = segs[segnum].y2;
495 }
496
497 Angle += (2.0 * kp->slice);
498 }
499
500 Angle = 360.0 - kp->slice;
501 for (segnum = 1; segnum < kp->modetype; segnum += 2) {
502 if (! kp->spots) {
503 segs[segnum].x1 =
504 (int) (PolarToCartX(kp->pen[pn].ox,
505 (kp->slice - kp->pen[pn].oy) + Angle
506 ) + kp->widthby2
507 );
508
509 segs[segnum].y1 =
510 (int) (PolarToCartY(kp->pen[pn].ox,
511 (kp->slice - kp->pen[pn].oy) + Angle
512 ) + kp->heightby2
513 );
514 }
515
516 segs[segnum].x2 =
517 (int) (PolarToCartX(kp->pen[pn].cx,
518 (kp->slice - kp->pen[pn].cy) + Angle
519 ) + kp->widthby2
520 );
521
522 segs[segnum].y2 =
523 (int) (PolarToCartY(kp->pen[pn].cx,
524 (kp->slice - kp->pen[pn].cy) + Angle
525 ) + kp->heightby2
526 );
527
528 if (kp->spots) {
529 segs[segnum].x1 = segs[segnum].x2;
530 segs[segnum].y1 = segs[segnum].y2;
531 }
532 Angle -= (2.0 * kp->slice);
533 }
534 }
535
536 /*-
537 *
538 */
539 static void
OctMirrored(kaleidstruct * kp,int pn,XSegment * segs)540 OctMirrored(
541 kaleidstruct * kp,
542 int pn,
543 XSegment * segs
544 )
545 {
546 double xdiag;
547 double ydiag;
548 double oxscaled2y, cxscaled2y;
549 double oyscaled2x, cyscaled2x;
550
551 /*
552 * I know that the "bounce" is not really accurate, but I like the way
553 * it looks.
554 */
555
556 xdiag = (kp->widthby2 * kp->pen[pn].oy) / kp->heightby2;
557
558 kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
559 if (kp->pen[pn].cx < xdiag) {
560 kp->pen[pn].cx = xdiag + (xdiag - kp->pen[pn].cx);
561 kp->pen[pn].xv = -kp->pen[pn].xv;
562 } else if (kp->pen[pn].cx >= kp->widthby2) {
563 kp->pen[pn].cx = (kp->widthby2 - 1.0)
564 - (kp->pen[pn].cx - kp->widthby2);
565 kp->pen[pn].xv = -kp->pen[pn].xv;
566 }
567 ydiag = (kp->heightby2 * kp->pen[pn].cx) / kp->widthby2;
568
569 kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
570 if (kp->pen[pn].cy < 0.0) {
571 kp->pen[pn].cy = -kp->pen[pn].cy;
572 kp->pen[pn].yv = -kp->pen[pn].yv;
573 } else if (kp->pen[pn].cy > ydiag) {
574 kp->pen[pn].cy = ydiag - (kp->pen[pn].cy - ydiag);
575 kp->pen[pn].yv = -kp->pen[pn].yv;
576 }
577 segs[0].x1 = (int) kp->pen[pn].ox;
578 segs[0].y1 = (int) kp->pen[pn].oy;
579 segs[0].x2 = (int) kp->pen[pn].cx;
580 segs[0].y2 = (int) kp->pen[pn].cy;
581
582 segs[1].x1 = (int) (kp->width - kp->pen[pn].ox);
583 segs[1].y1 = (int) kp->pen[pn].oy;
584 segs[1].x2 = (int) (kp->width - kp->pen[pn].cx);
585 segs[1].y2 = (int) kp->pen[pn].cy;
586
587 segs[4].x1 = segs[1].x1;
588 segs[4].y1 = (int) kp->height - segs[0].y1;
589 segs[4].x2 = segs[1].x2;
590 segs[4].y2 = (int) kp->height - segs[0].y2;
591
592 segs[5].x1 = segs[0].x1;
593 segs[5].y1 = (int) kp->height - segs[0].y1;
594 segs[5].x2 = segs[0].x2;
595 segs[5].y2 = (int) kp->height - segs[0].y2;
596
597
598 oxscaled2y = ((kp->pen[pn].ox * kp->heightby2) / kp->widthby2);
599 oyscaled2x = ((kp->pen[pn].oy * kp->widthby2) / kp->heightby2);
600 cxscaled2y = ((kp->pen[pn].cx * kp->heightby2) / kp->widthby2);
601 cyscaled2x = ((kp->pen[pn].cy * kp->widthby2) / kp->heightby2);
602
603
604 segs[7].x1 = (int) oyscaled2x;
605 segs[7].y1 = (int) oxscaled2y;
606 segs[7].x2 = (int) cyscaled2x;
607 segs[7].y2 = (int) cxscaled2y;
608
609
610 segs[2].x1 = (int) kp->width - segs[7].x1;
611 segs[2].y1 = segs[7].y1;
612 segs[2].x2 = (int) kp->width - segs[7].x2;
613 segs[2].y2 = segs[7].y2;
614
615 segs[6].x1 = segs[7].x1;
616 segs[6].y1 = (int) kp->height - segs[7].y1;
617 segs[6].x2 = segs[7].x2;
618 segs[6].y2 = (int) kp->height - segs[7].y2;
619
620 segs[3].x1 = (int) kp->width - segs[7].x1;
621 segs[3].y1 = segs[6].y1;
622 segs[3].x2 = (int) kp->width - segs[7].x2;
623 segs[3].y2 = segs[6].y2;
624
625 }
626
627
628
629 /*-
630 *
631 */
632 #if 0
633 static void
634 OldOctRotated(
635 kaleidstruct * kp,
636 int pn,
637 XSegment * segs
638 )
639 {
640 double angle, radius;
641 double oangle, oradius;
642 double rv, av;
643 double perp, para;
644 int i;
645
646 /*
647 * I know that the "bounce" is not really accurate, but I like the way
648 * it looks.
649 */
650
651 kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
652 kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
653 angle = CartToAngle(kp->pen[pn].cx, kp->pen[pn].cy);
654 radius = CartToRadius(kp->pen[pn].cx, kp->pen[pn].cy);
655
656 oangle = CartToAngle(kp->pen[pn].ox, kp->pen[pn].oy);
657 oradius = CartToRadius(kp->pen[pn].ox, kp->pen[pn].oy);
658
659 if (radius < 0.0) {
660 if (kp->pen[pn].xv < 0.0) {
661 kp->pen[pn].xv = -kp->pen[pn].xv;
662 }
663 } else if (radius > kp->radius) {
664 if (kp->pen[pn].xv > 0.0) {
665 kp->pen[pn].xv = -kp->pen[pn].xv;
666 }
667 }
668 if (angle < 0.0) {
669 if (oangle > 0.0) {
670 kp->pen[pn].yv = -kp->pen[pn].yv;
671 }
672 } else if (angle > 45.0) {
673 if (oangle < 45.0) {
674 rv = CartToRadius(kp->pen[pn].xv, kp->pen[pn].yv);
675 av = CartToAngle(kp->pen[pn].xv, kp->pen[pn].yv);
676
677 para = PolarToCartX(rv, av - 45.0);
678 perp = PolarToCartY(rv, av - 45.0);
679
680 rv = CartToRadius(para, -perp);
681 av = CartToAngle(para, -perp);
682
683 kp->pen[pn].xv = PolarToCartX(rv, av + 45.0);
684 kp->pen[pn].yv = PolarToCartY(rv, av + 45.0);
685 }
686 }
687 for (i = 0; i < 8; i += 1) {
688 segs[i].x1 = (int) (kp->widthby2 + PolarToCartX(oradius, oangle));
689 segs[i].y1 = (int) (kp->heightby2 - PolarToCartY(oradius, oangle));
690 segs[i].x2 = (int) (kp->widthby2 + PolarToCartX(radius, angle));
691 segs[i].y2 = (int) (kp->heightby2 - PolarToCartY(radius, angle));
692
693 oangle += 45.0;
694 angle += 45.0;
695 }
696 }
697
698 #endif
699
700 /*-
701 *
702 */
703 static void
OctRotated(kaleidstruct * kp,int pn,XSegment * segs)704 OctRotated(
705 kaleidstruct * kp,
706 int pn,
707 XSegment * segs
708 )
709 {
710 double xdiag;
711 double ydiag;
712 double radius, angle;
713 double oradius, oangle;
714 double ox, oy, cx, cy;
715 double offset;
716 int i;
717
718 /*
719 * I know that the "bounce" is not really accurate, but I like the way
720 * it looks.
721 */
722
723 xdiag = (kp->widthby2 * kp->pen[pn].oy) / kp->heightby2;
724
725 kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
726 if (kp->pen[pn].cx < xdiag) {
727 kp->pen[pn].cx = xdiag + (xdiag - kp->pen[pn].cx);
728 kp->pen[pn].xv = -kp->pen[pn].xv;
729 } else if (kp->pen[pn].cx >= kp->widthby2) {
730 kp->pen[pn].cx = (kp->widthby2 - 1.0)
731 - (kp->pen[pn].cx - kp->widthby2);
732 kp->pen[pn].xv = -kp->pen[pn].xv;
733 }
734 ydiag = (kp->heightby2 * kp->pen[pn].cx) / kp->widthby2;
735
736 kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
737 if (kp->pen[pn].cy < 0.0) {
738 kp->pen[pn].cy = -kp->pen[pn].cy;
739 kp->pen[pn].yv = -kp->pen[pn].yv;
740 } else if (kp->pen[pn].cy > ydiag) {
741 kp->pen[pn].cy = ydiag - (kp->pen[pn].cy - ydiag);
742 kp->pen[pn].yv = -kp->pen[pn].yv;
743 }
744 offset = CartToRadius(kp->heightby2, kp->widthby2);
745 ox = (kp->pen[pn].ox * offset) / kp->widthby2;
746 oy = (kp->pen[pn].oy * offset) / kp->heightby2;
747 cx = (kp->pen[pn].cx * offset) / kp->widthby2;
748 cy = (kp->pen[pn].cy * offset) / kp->heightby2;
749
750 angle = CartToAngle(cx - offset,
751 offset - cy
752 ) - 90.0;
753 radius = CartToRadius(cx - offset,
754 offset - cy
755 );
756
757 oangle = CartToAngle(ox - offset,
758 offset - oy
759 ) - 90.0;
760 oradius = CartToRadius(ox - offset,
761 offset - oy
762 );
763
764
765 for (i = 0; i < 8; i += 1) {
766 segs[i].x1 = (int) (kp->widthby2 + PolarToCartX(oradius, oangle));
767 segs[i].y1 = (int) (kp->heightby2 - PolarToCartY(oradius, oangle));
768 segs[i].x2 = (int) (kp->widthby2 + PolarToCartX(radius, angle));
769 segs[i].y2 = (int) (kp->heightby2 - PolarToCartY(radius, angle));
770
771 oangle += 45.0;
772 angle += 45.0;
773 }
774
775 }
776
777 /*-
778 *
779 */
780 static void
GeneralLinearMoveAndBounce(kaleidstruct * kp,int pn,double * angle,double * radius,double * oangle,double * oradius)781 GeneralLinearMoveAndBounce(
782 kaleidstruct * kp,
783 int pn,
784 double *angle,
785 double *radius,
786 double *oangle,
787 double *oradius
788 )
789 {
790 double rv, av;
791 double perp, para;
792
793 kp->pen[pn].cx = kp->pen[pn].cx + kp->pen[pn].xv;
794 kp->pen[pn].cy = kp->pen[pn].cy + kp->pen[pn].yv;
795
796 *angle = CartToAngle(kp->pen[pn].cx, kp->pen[pn].cy);
797 *radius = CartToRadius(kp->pen[pn].cx, kp->pen[pn].cy);
798
799 *oangle = CartToAngle(kp->pen[pn].ox, kp->pen[pn].oy);
800 *oradius = CartToRadius(kp->pen[pn].ox, kp->pen[pn].oy);
801
802 if (*radius < 0.0) {
803 kp->pen[pn].RadiusOut = True;
804 if (*oradius > 0.0) {
805 rv = CartToRadius(kp->pen[pn].xv, kp->pen[pn].yv);
806 av = CartToAngle(kp->pen[pn].xv, kp->pen[pn].yv);
807
808 para = PolarToCartX(rv, av - (*angle + 90.0));
809 perp = PolarToCartY(rv, av - (*angle + 90.0));
810
811 rv = CartToRadius(para, -perp);
812 av = CartToAngle(para, -perp);
813
814 kp->pen[pn].xv = PolarToCartX(rv, av + (*angle + 90.0));
815 kp->pen[pn].yv = PolarToCartY(rv, av + (*angle + 90.0));
816 }
817 } else if (*radius > kp->radius) {
818 kp->pen[pn].RadiusOut = True;
819 if (*oradius < kp->radius) {
820 rv = CartToRadius(kp->pen[pn].xv, kp->pen[pn].yv);
821 av = CartToAngle(kp->pen[pn].xv, kp->pen[pn].yv);
822
823 para = PolarToCartX(rv, av - (*angle + 90.0));
824 perp = PolarToCartY(rv, av - (*angle + 90.0));
825
826 rv = CartToRadius(para, -perp);
827 av = CartToAngle(para, -perp);
828
829 kp->pen[pn].xv = PolarToCartX(rv, av + (*angle + 90.0));
830 kp->pen[pn].yv = PolarToCartY(rv, av + (*angle + 90.0));
831 }
832 } else {
833 kp->pen[pn].RadiusOut = False;
834 }
835
836
837 if (*angle < 0.0) {
838 if (kp->spiral) {
839 kp->pen[pn].AngleOut = False;
840 *angle = *angle + 360.0;
841 } else {
842 kp->pen[pn].AngleOut = True;
843 if (*oangle > 0.0) {
844 rv = CartToRadius(kp->pen[pn].xv, kp->pen[pn].yv);
845 av = CartToAngle(kp->pen[pn].xv, kp->pen[pn].yv);
846
847 para = PolarToCartX(rv, av);
848 perp = PolarToCartY(rv, av);
849
850 rv = CartToRadius(para, -perp);
851 av = CartToAngle(para, -perp);
852
853 kp->pen[pn].xv = PolarToCartX(rv, av);
854 kp->pen[pn].yv = PolarToCartY(rv, av);
855 }
856 }
857 } else if (kp->spiral) {
858 if (*angle > 360.0) {
859 kp->pen[pn].AngleOut = False;
860 *angle = *angle - 360.0;
861 }
862 } else if (*angle > kp->slice) {
863 kp->pen[pn].AngleOut = True;
864 if (*oangle < kp->slice) {
865 rv = CartToRadius(kp->pen[pn].xv, kp->pen[pn].yv);
866 av = CartToAngle(kp->pen[pn].xv, kp->pen[pn].yv);
867
868 para = PolarToCartX(rv, av - kp->slice);
869 perp = PolarToCartY(rv, av - kp->slice);
870
871 rv = CartToRadius(para, -perp);
872 av = CartToAngle(para, -perp);
873
874 kp->pen[pn].xv = PolarToCartX(rv, av + kp->slice);
875 kp->pen[pn].yv = PolarToCartY(rv, av + kp->slice);
876 }
877 } else {
878 kp->pen[pn].AngleOut = False;
879 }
880 }
881
882 /*-
883 *
884 */
885 static void
GeneralLinearRotated(kaleidstruct * kp,int pn,XSegment * segs)886 GeneralLinearRotated(
887 kaleidstruct * kp,
888 int pn,
889 XSegment * segs
890 )
891 {
892 double angle, radius;
893 double oangle, oradius;
894 int i;
895
896 GeneralLinearMoveAndBounce(kp, pn, &angle, &radius, &oangle, &oradius);
897
898 for (i = 0; i < kp->modetype; i += 1) {
899 if (! kp->spots) {
900 segs[i].x1 = (int) (kp->widthby2 + PolarToCartX(oradius, oangle));
901 segs[i].y1 = (int) (kp->heightby2 - PolarToCartY(oradius, oangle));
902 }
903
904 segs[i].x2 = (int) (kp->widthby2 + PolarToCartX(radius, angle));
905 segs[i].y2 = (int) (kp->heightby2 - PolarToCartY(radius, angle));
906
907 if (kp->spots) {
908 segs[i].x1 = segs[i].x2;
909 segs[i].y1 = segs[i].y2;
910 }
911
912 oangle += kp->slice;
913 angle += kp->slice;
914 }
915 }
916
917
918
919 /*-
920 *
921 */
922 static void
GeneralLinearMirrored(kaleidstruct * kp,int pn,XSegment * segs)923 GeneralLinearMirrored(
924 kaleidstruct * kp,
925 int pn,
926 XSegment * segs
927 )
928 {
929 double hangle, angle, radius;
930 double hoangle, oangle, oradius;
931 int i;
932
933
934 GeneralLinearMoveAndBounce(kp, pn, &angle, &radius, &oangle, &oradius);
935
936 hoangle = oangle;
937 hangle = angle;
938
939 for (i = 0; i < kp->modetype; i += 2) {
940 if (! kp->spots) {
941 segs[i].x1 = (int) (kp->widthby2 + PolarToCartX(oradius, oangle));
942 segs[i].y1 = (int) (kp->heightby2 - PolarToCartY(oradius, oangle));
943 }
944
945 segs[i].x2 = (int) (kp->widthby2 + PolarToCartX(radius, angle));
946 segs[i].y2 = (int) (kp->heightby2 - PolarToCartY(radius, angle));
947
948 if (kp->spots) {
949 segs[i].x1 = segs[i].x2;
950 segs[i].y1 = segs[i].y2;
951 }
952
953 oangle += 2.0 * kp->slice;
954 angle += 2.0 * kp->slice;
955 }
956
957 oangle = kp->slice * 2.0;
958 angle = kp->slice * 2.0;
959 for (i = 1; i < kp->modetype; i += 2) {
960 if (! kp->spots) {
961 segs[i].x1 = (int) (kp->widthby2 + PolarToCartX(oradius, oangle - hoangle));
962 segs[i].y1 = (int) (kp->heightby2 - PolarToCartY(oradius, oangle - hoangle));
963 }
964
965 segs[i].x2 = (int) (kp->widthby2 + PolarToCartX(radius, angle - hangle));
966 segs[i].y2 = (int) (kp->heightby2 - PolarToCartY(radius, angle - hangle));
967
968 if (kp->spots) {
969 segs[i].x1 = segs[i].x2;
970 segs[i].y1 = segs[i].y2;
971 }
972
973 oangle += 2.0 * kp->slice;
974 angle += 2.0 * kp->slice;
975 }
976 }
977
978 /*-
979 *
980 */
981 static void
random_velocity(kaleidstruct * kp,int i)982 random_velocity(kaleidstruct * kp, int i)
983 {
984 int tMxRV, tMnRV;
985 int tMxAV, tMnAV;
986 int tMxV, tMnV;
987
988 if (kp->spots) {
989 tMxRV = MaxRadialVelocity * SpotsMult;
990 tMnRV = MinRadialVelocity * SpotsMult;
991 tMxAV = MaxAngularVelocity * SpotsMult;
992 tMnAV = MinAngularVelocity * SpotsMult;
993 tMxV = MaxVelocity * SpotsMult;
994 tMnV = MinVelocity * SpotsMult;
995 } else {
996 tMxRV = MaxRadialVelocity;
997 tMnRV = MinRadialVelocity;
998 tMxAV = MaxAngularVelocity;
999 tMnAV = MinAngularVelocity;
1000 tMxV = MaxVelocity;
1001 tMnV = MinVelocity;
1002 }
1003
1004
1005 if (kp->modetype > 0) {
1006 kp->pen[i].xv = INTRAND(-tMxRV, tMxRV);
1007 if (kp->pen[i].xv > 0.0) {
1008 kp->pen[i].xv += tMnRV;
1009 } else if (kp->pen[i].xv < 0.0) {
1010 kp->pen[i].xv -= tMnRV;
1011 }
1012 kp->pen[i].yv = INTRAND(-tMxAV, tMxAV);
1013 if (kp->pen[i].yv > 0.0) {
1014 kp->pen[i].yv += tMnAV;
1015 } else if (kp->pen[i].yv < 0.0) {
1016 kp->pen[i].yv -= tMnAV;
1017 }
1018 } else {
1019 kp->pen[i].xv = INTRAND(-tMxV, tMxV);
1020 if (kp->pen[i].xv > 0.0) {
1021 kp->pen[i].xv += tMnV;
1022 } else if (kp->pen[i].xv < 0.0) {
1023 kp->pen[i].xv -= tMnV;
1024 }
1025 kp->pen[i].yv = INTRAND(-tMxV, tMxV);
1026 if (kp->pen[i].yv > 0.0) {
1027 kp->pen[i].yv += tMnV;
1028 } else if (kp->pen[i].yv < 0.0) {
1029 kp->pen[i].yv -= tMnV;
1030 }
1031 }
1032 }
1033
1034
1035 static void
random_position(kaleidstruct * kp,int i)1036 random_position(kaleidstruct * kp, int i)
1037 {
1038
1039 if (kp->modetype >= 0) {
1040 if (kp->linear) {
1041 double radius, angle;
1042
1043 radius = (double) INTRAND(0, (int) (kp->radius - 1.0));
1044 angle = (double) INTRAND(0, (int) (kp->slice - 1.0));
1045
1046 kp->pen[i].cx = PolarToCartX(radius, angle);
1047 kp->pen[i].cy = PolarToCartY(radius, angle);
1048 } else {
1049 kp->pen[i].cx = (double) INTRAND(0, (int) (kp->radius - 1.0));
1050 kp->pen[i].cy = (double) INTRAND(0, (int) (kp->slice - 1.0));
1051 }
1052 } else if (kp->modetype == OCT) {
1053 double radius, angle;
1054
1055 radius = (double) INTRAND(0, (int) (kp->radius - 1.0));
1056 angle = (double) INTRAND(0, 44);
1057
1058 kp->pen[i].cx = PolarToCartX(radius, angle);
1059 kp->pen[i].cy = PolarToCartY(radius, angle);
1060 } else {
1061 kp->pen[i].cx = (double) INTRAND(0, (int) (kp->widthby2 - 1.0));
1062 kp->pen[i].cy = (double) INTRAND(0,
1063 (int) ((kp->heightby2 * kp->pen[i].cx) / kp->widthby2));
1064 }
1065 }
1066
1067 static void
free_kaleid_screen(kaleidstruct * kp)1068 free_kaleid_screen(kaleidstruct *kp)
1069 {
1070 if (kp == NULL) {
1071 return;
1072 }
1073 if (kp->pen != NULL)
1074 free(kp->pen);
1075 kp = NULL;
1076 }
1077
1078 /*-
1079 *
1080 */
1081 ENTRYPOINT void
init_kaleid(ModeInfo * mi)1082 init_kaleid(ModeInfo * mi)
1083 {
1084 int i;
1085 kaleidstruct *kp;
1086
1087 MI_INIT(mi, kaleids);
1088 kp = &kaleids[MI_SCREEN(mi)];
1089
1090 kp->PenCount = MI_COUNT(mi);
1091
1092 if (MI_IS_FULLRANDOM(mi)) {
1093 kp->alternate = (Bool) (LRAND() & 1);
1094 kp->disconnected = (Bool) (LRAND() & 1);
1095 kp->serial = (Bool) (LRAND() & 1);
1096 kp->linear = (Bool) (LRAND() & 1);
1097 kp->spiral = (Bool) (LRAND() & 1);
1098 kp->spots = (Bool) (LRAND() & 1);
1099 } else {
1100 kp->alternate = Alternate;
1101 kp->disconnected = Disconnected;
1102 kp->serial = Serial;
1103 kp->linear = Linear;
1104 kp->spiral = Spiral;
1105 kp->spots = Spots;
1106 }
1107
1108 if (kp->PenCount < -MINPENS) {
1109 /* if kp->PenCount is random ... the size can change */
1110 if (kp->pen != NULL) {
1111 free(kp->pen);
1112 kp->pen = (penstruct *) NULL;
1113 }
1114 kp->PenCount = NRAND(-kp->PenCount - MINPENS + 1) + MINPENS;
1115 } else if (kp->PenCount < MINPENS)
1116 kp->PenCount = MINPENS;
1117
1118 if (kp->pen == NULL) {
1119 if ((kp->pen = (penstruct *) malloc(kp->PenCount *
1120 sizeof (penstruct))) == NULL)
1121 return;
1122 }
1123
1124 if ((MI_SIZE(mi)) > MINSIZE) {
1125 kp->modetype = (!kp->alternate + 1) * MI_SIZE(mi);
1126 } else if ((MI_SIZE(mi)) < -MINSIZE) {
1127 kp->modetype = (!kp->alternate + 1) * (NRAND(-MI_SIZE(mi) + 1) + MINSIZE);
1128 } else {
1129 kp->modetype = (!kp->alternate + 1) * MINSIZE;
1130 }
1131 if (MI_IS_FULLRANDOM(mi)) {
1132 int tmp;
1133
1134 tmp = NRAND(ABS(MI_SIZE(mi)) + 2);
1135 if (tmp == 0)
1136 kp->modetype = OCT;
1137 else if (tmp == 1)
1138 kp->modetype = QUAD;
1139 } else {
1140 if (Oct)
1141 kp->modetype = OCT;
1142 else if (Quad)
1143 kp->modetype = QUAD;
1144 }
1145
1146 kp->PercentBlack = (int) MAX(0, MIN(MI_CYCLES(mi), 95));
1147
1148
1149 /* set various size parameters */
1150
1151 kp->width = (double) MI_WIDTH(mi);
1152 kp->height = (double) MI_HEIGHT(mi);
1153
1154 if (kp->width < 2.0)
1155 kp->width = 2.0;
1156 if (kp->height < 2.0)
1157 kp->height = 2.0;
1158
1159 kp->radius = sqrt(((kp->width * kp->width) +
1160 (kp->height * kp->height)
1161 ) / 4.0
1162 );
1163
1164
1165 if (kp->modetype >= 0) {
1166 kp->bouncetype = INTRAND(0, 2);
1167
1168 kp->slice = 360.0 / (double) kp->modetype;
1169
1170 kp->widthby2 = kp->width / 2.0;
1171 kp->heightby2 = kp->height / 2.0;
1172 } else {
1173 kp->widthby2 = kp->width / 2.0;
1174 kp->heightby2 = kp->height / 2.0;
1175 }
1176
1177 /* set the maximum pen width */
1178 if (kp->modetype >= 0) {
1179 if ((kp->slice == 360.0) || (kp->slice == 180.0)) {
1180 kp->maxlwidth = (int) ((((double) MIN(kp->widthby2, kp->heightby2)) *
1181 (double) WidthPercent) / 100.0);
1182 } else {
1183 kp->maxlwidth = (int) (((sin(kp->slice * ToRadians) *
1184 MIN(kp->widthby2, kp->heightby2)) *
1185 (double) WidthPercent) / 100.0);
1186 }
1187 } else {
1188 kp->maxlwidth = (int) ((MIN(kp->widthby2,
1189 kp->heightby2
1190 ) * (double) WidthPercent
1191 ) / 100.0
1192 );
1193 }
1194
1195 if (kp->spots) {
1196 kp->maxlwidth = 2 * kp->maxlwidth;
1197 }
1198
1199 if (kp->maxlwidth <= 0) {
1200 kp->maxlwidth = 1;
1201 }
1202
1203 for (i = 0; i < kp->PenCount; i += 1) {
1204 if (MI_NPIXELS(mi) > 2) {
1205 kp->pen[i].pix = NRAND(MI_NPIXELS(mi));
1206 kp->pen[i].White = 1;
1207 } else {
1208 kp->pen[i].White = 1;
1209 }
1210
1211 kp->pen[i].curlwidth = INTRAND(1, kp->maxlwidth);
1212
1213 kp->pen[i].RadiusOut = False;
1214 kp->pen[i].AngleOut = False;
1215
1216 random_position(kp, i);
1217
1218 kp->pen[i].ox = kp->pen[i].cx;
1219 kp->pen[i].oy = kp->pen[i].cy;
1220 kp->pen[i].DeferredChange = False;
1221
1222 random_velocity(kp, i);
1223 }
1224
1225 MI_CLEARWINDOW(mi);
1226
1227 }
1228
1229 /*-
1230 *
1231 */
1232 static void
set_pen_attributes(ModeInfo * mi,kaleidstruct * kp,int i)1233 set_pen_attributes(ModeInfo * mi, kaleidstruct * kp, int i)
1234 {
1235 Display *display = MI_DISPLAY(mi);
1236 GC gc = MI_GC(mi);
1237
1238 if (kp->pen[i].White) {
1239 if (MI_NPIXELS(mi) > 2)
1240 XSetForeground(display, gc, MI_PIXEL(mi, kp->pen[i].pix));
1241 else
1242 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
1243 } else {
1244 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
1245 }
1246 XSetLineAttributes(display, gc,
1247 kp->pen[i].curlwidth, LineSolid, CapRound, JoinRound);
1248 }
1249
1250 /*-
1251 *
1252 */
1253 static void
change_pen(ModeInfo * mi,kaleidstruct * kp,int i)1254 change_pen(ModeInfo * mi, kaleidstruct * kp, int i)
1255 {
1256 if (INTRAND(0, 100) < kp->PercentBlack) {
1257 kp->pen[i].White = 0;
1258 } else {
1259 kp->pen[i].White = 1;
1260 if (kp->serial) {
1261 if (MI_NPIXELS(mi) > 2) {
1262 if (++kp->pen[i].pix >= MI_NPIXELS(mi))
1263 kp->pen[i].pix = 0;
1264 }
1265 } else {
1266 if (MI_NPIXELS(mi) > 2) {
1267 kp->pen[i].pix = NRAND(MI_NPIXELS(mi));
1268 }
1269 }
1270 }
1271
1272 random_velocity(kp, i);
1273
1274 kp->pen[i].curlwidth = INTRAND(1, kp->maxlwidth);
1275
1276 if (kp->modetype >= 0) {
1277 kp->bouncetype = INTRAND(0, 2);
1278 }
1279 if (kp->disconnected) {
1280 random_position(kp, i);
1281 kp->pen[i].ox = kp->pen[i].cx;
1282 kp->pen[i].oy = kp->pen[i].cy;
1283 }
1284 }
1285
1286 /*-
1287 *
1288 */
1289 ENTRYPOINT void
draw_kaleid(ModeInfo * mi)1290 draw_kaleid(ModeInfo * mi)
1291 {
1292 Display *display = MI_DISPLAY(mi);
1293 GC gc = MI_GC(mi);
1294 XSegment *segs;
1295 int NumberOfSegments;
1296 int i;
1297 kaleidstruct *kp;
1298
1299 if (kaleids == NULL)
1300 return;
1301 kp = &kaleids[MI_SCREEN(mi)];
1302 if (kp->pen == NULL)
1303 return;
1304
1305 MI_IS_DRAWN(mi) = True;
1306 if (kp->modetype == QUAD) {
1307 NumberOfSegments = 4;
1308 } else if (kp->modetype == OCT) {
1309 NumberOfSegments = 8;
1310 } else { /* if (kp->modetype > 0) */
1311 NumberOfSegments = kp->modetype;
1312 }
1313 if ((segs = (XSegment *) malloc(NumberOfSegments *
1314 sizeof (XSegment))) == NULL) {
1315 free(kp->pen);
1316 kp->pen = (penstruct *) NULL;
1317 return;
1318 }
1319
1320 for (i = 0; i < kp->PenCount; i++) {
1321 set_pen_attributes(mi, kp, i);
1322
1323 if (kp->modetype == QUAD) {
1324 if (kp->alternate) {
1325 QuadRotated(kp, i, segs);
1326 } else {
1327 QuadMirrored(kp, i, segs);
1328 }
1329 } else if (kp->modetype == OCT) {
1330 if (kp->alternate) {
1331 OctRotated(kp, i, segs);
1332 } else {
1333 OctMirrored(kp, i, segs);
1334 }
1335 } else {
1336 if (kp->alternate) {
1337
1338 if (kp->linear) {
1339 GeneralLinearRotated(kp, i, segs);
1340 } else {
1341 GeneralRotated(kp, i, segs);
1342 }
1343 } else {
1344 if (kp->linear) {
1345 GeneralLinearMirrored(kp, i, segs);
1346 } else {
1347 GeneralMirrored(kp, i, segs);
1348 }
1349 }
1350 }
1351 XDrawSegments(
1352 display,
1353 MI_WINDOW(mi),
1354 gc,
1355 segs,
1356 NumberOfSegments
1357 );
1358
1359 kp->pen[i].ox = kp->pen[i].cx;
1360 kp->pen[i].oy = kp->pen[i].cy;
1361
1362
1363 if ((INTRAND(0, 100) < ChangeChance) || kp->pen[i].DeferredChange) {
1364 if (!kp->pen[i].AngleOut && !kp->pen[i].RadiusOut) {
1365 kp->pen[i].DeferredChange = False;
1366 change_pen(mi, kp, i);
1367 } else {
1368 kp->pen[i].DeferredChange = True;
1369 }
1370 }
1371 }
1372
1373
1374 XSetLineAttributes(display, gc, 1, LineSolid, CapRound, JoinRound);
1375 free(segs);
1376 }
1377
1378 /*-
1379 *
1380 */
1381 ENTRYPOINT void
release_kaleid(ModeInfo * mi)1382 release_kaleid(ModeInfo * mi)
1383 {
1384 if (kaleids != NULL) {
1385 int screen;
1386
1387 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1388 free_kaleid_screen(&kaleids[screen]);
1389 }
1390 free(kaleids);
1391 kaleids = (kaleidstruct *) NULL;
1392 }
1393 }
1394
1395 #ifndef STANDALONE
1396 /*-
1397 *
1398 */
1399 ENTRYPOINT void
refresh_kaleid(ModeInfo * mi)1400 refresh_kaleid(ModeInfo * mi)
1401 {
1402 MI_CLEARWINDOW(mi);
1403 }
1404 #endif
1405
1406 XSCREENSAVER_MODULE ("Kaleid", kaleid)
1407
1408 #endif /* MODE_kaleid */
1409