1 | /* nerverot, nervous rotation of random thingies, v1.4 |
---|
2 | * by Dan Bornstein, danfuzz@milk.com |
---|
3 | * Copyright (c) 2000-2001 Dan Bornstein. All rights reserved. |
---|
4 | * |
---|
5 | * Permission to use, copy, modify, distribute, and sell this software and its |
---|
6 | * documentation for any purpose is hereby granted without fee, provided that |
---|
7 | * the above copyright notice appear in all copies and that both that |
---|
8 | * copyright notice and this permission notice appear in supporting |
---|
9 | * documentation. No representations are made about the suitability of this |
---|
10 | * software for any purpose. It is provided "as is" without express or |
---|
11 | * implied warranty. |
---|
12 | * |
---|
13 | * The goal of this screensaver is to be interesting and compelling to |
---|
14 | * watch, yet induce a state of nervous edginess in the viewer. |
---|
15 | * |
---|
16 | * See the included man page for more details. |
---|
17 | */ |
---|
18 | |
---|
19 | #include <math.h> |
---|
20 | #include "screenhack.h" |
---|
21 | |
---|
22 | #define FLOAT double |
---|
23 | |
---|
24 | /* random float in the range (-1..1) */ |
---|
25 | #define RAND_FLOAT_PM1 \ |
---|
26 | (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000) * 2 - 1) |
---|
27 | |
---|
28 | /* random float in the range (0..1) */ |
---|
29 | #define RAND_FLOAT_01 \ |
---|
30 | (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000)) |
---|
31 | |
---|
32 | |
---|
33 | |
---|
34 | /* parameters that are user configurable */ |
---|
35 | |
---|
36 | /* number of blots */ |
---|
37 | static int requestedBlotCount; |
---|
38 | |
---|
39 | /* delay (usec) between iterations */ |
---|
40 | int delay; |
---|
41 | |
---|
42 | /* max iterations per model */ |
---|
43 | int maxIters; |
---|
44 | |
---|
45 | /* variability of xoff/yoff per iteration (0..1) */ |
---|
46 | static FLOAT nervousness; |
---|
47 | |
---|
48 | /* max nervousness radius (0..1) */ |
---|
49 | static FLOAT maxNerveRadius; |
---|
50 | |
---|
51 | /* chance per iteration that an event will happen */ |
---|
52 | static FLOAT eventChance; |
---|
53 | |
---|
54 | /* fraction (0..1) towards rotation target or scale target to move each |
---|
55 | * iteration */ |
---|
56 | static FLOAT iterAmt; |
---|
57 | |
---|
58 | /* min and max scale for drawing, as fraction of baseScale */ |
---|
59 | static FLOAT minScale; |
---|
60 | static FLOAT maxScale; |
---|
61 | |
---|
62 | /* min and max radius of blot drawing */ |
---|
63 | static int minRadius; |
---|
64 | static int maxRadius; |
---|
65 | |
---|
66 | /* the number of colors to use */ |
---|
67 | static int colorCount; |
---|
68 | |
---|
69 | /* width of lines */ |
---|
70 | static int lineWidth; |
---|
71 | |
---|
72 | /* whether or not to do double-buffering */ |
---|
73 | static Bool doubleBuffer; |
---|
74 | |
---|
75 | |
---|
76 | |
---|
77 | /* non-user-modifiable immutable definitions */ |
---|
78 | |
---|
79 | /* base scale factor for drawing, calculated as |
---|
80 | * max(screenWidth,screenHeight) */ |
---|
81 | static int baseScale; |
---|
82 | |
---|
83 | /* width and height of the window */ |
---|
84 | static int windowWidth; |
---|
85 | static int windowHeight; |
---|
86 | |
---|
87 | /* center position of the window */ |
---|
88 | static int centerX; |
---|
89 | static int centerY; |
---|
90 | |
---|
91 | static Display *display; /* the display to draw on */ |
---|
92 | static Window window; /* the window to draw on */ |
---|
93 | static Drawable drawable; /* the thing to directly draw on */ |
---|
94 | static GC *gcs; /* array of gcs, one per color used */ |
---|
95 | |
---|
96 | |
---|
97 | |
---|
98 | /* structure of the model */ |
---|
99 | |
---|
100 | /* each point-like thingy to draw is represented as a blot */ |
---|
101 | typedef struct blot_s |
---|
102 | { |
---|
103 | FLOAT x; /* 3d x position (-1..1) */ |
---|
104 | FLOAT y; /* 3d y position (-1..1) */ |
---|
105 | FLOAT z; /* 3d z position (-1..1) */ |
---|
106 | FLOAT xoff[3][3]; /* display x offset per drawn point (-1..1) */ |
---|
107 | FLOAT yoff[3][3]; /* display x offset per drawn point (-1..1) */ |
---|
108 | } Blot; |
---|
109 | |
---|
110 | /* each drawn line is represented as a LineSegment */ |
---|
111 | typedef struct linesegment_s |
---|
112 | { |
---|
113 | GC gc; |
---|
114 | int x1; |
---|
115 | int y1; |
---|
116 | int x2; |
---|
117 | int y2; |
---|
118 | } LineSegment; |
---|
119 | |
---|
120 | /* array of the blots in the model */ |
---|
121 | static Blot *blots = NULL; |
---|
122 | static int blotCount; |
---|
123 | |
---|
124 | /* each blot draws as a simple 2d shape with each coordinate as an int |
---|
125 | * in the range (-1..1); this is the base shape */ |
---|
126 | static XPoint blotShape[] = { { 0, 0}, { 1, 0}, { 1, 1}, |
---|
127 | { 0, 1}, {-1, 1}, {-1, 0}, |
---|
128 | {-1,-1}, { 0,-1}, { 1,-1} }; |
---|
129 | static int blotShapeCount = sizeof (blotShape) / sizeof (XPoint); |
---|
130 | |
---|
131 | /* two arrays of line segments; one for the ones to erase, and one for the |
---|
132 | * ones to draw */ |
---|
133 | static int segCount; |
---|
134 | static LineSegment *segsToDraw = NULL; |
---|
135 | static LineSegment *segsToErase = NULL; |
---|
136 | |
---|
137 | /* current rotation values per axis, scale factor, and light position */ |
---|
138 | static FLOAT xRot; |
---|
139 | static FLOAT yRot; |
---|
140 | static FLOAT zRot; |
---|
141 | static FLOAT curScale; |
---|
142 | static FLOAT lightX; |
---|
143 | static FLOAT lightY; |
---|
144 | static FLOAT lightZ; |
---|
145 | |
---|
146 | /* target rotation values per axis, scale factor, and light position */ |
---|
147 | static FLOAT xRotTarget; |
---|
148 | static FLOAT yRotTarget; |
---|
149 | static FLOAT zRotTarget; |
---|
150 | static FLOAT scaleTarget; |
---|
151 | static FLOAT lightXTarget; |
---|
152 | static FLOAT lightYTarget; |
---|
153 | static FLOAT lightZTarget; |
---|
154 | |
---|
155 | /* current absolute offsets from the center */ |
---|
156 | static int centerXOff = 0; |
---|
157 | static int centerYOff = 0; |
---|
158 | |
---|
159 | /* iterations until the model changes */ |
---|
160 | static int itersTillNext; |
---|
161 | |
---|
162 | |
---|
163 | |
---|
164 | /* |
---|
165 | * generic blot setup and manipulation |
---|
166 | */ |
---|
167 | |
---|
168 | /* initialize a blot with the given coordinates and random display offsets */ |
---|
169 | static void initBlot (Blot *b, FLOAT x, FLOAT y, FLOAT z) |
---|
170 | { |
---|
171 | int i, j; |
---|
172 | |
---|
173 | b->x = x; |
---|
174 | b->y = y; |
---|
175 | b->z = z; |
---|
176 | |
---|
177 | for (i = 0; i < 3; i++) |
---|
178 | { |
---|
179 | for (j = 0; j < 3; j++) |
---|
180 | { |
---|
181 | b->xoff[i][j] = RAND_FLOAT_PM1; |
---|
182 | b->yoff[i][j] = RAND_FLOAT_PM1; |
---|
183 | } |
---|
184 | } |
---|
185 | } |
---|
186 | |
---|
187 | /* scale the blots to have a max distance of 1 from the center */ |
---|
188 | static void scaleBlotsToRadius1 (void) |
---|
189 | { |
---|
190 | FLOAT max = 0.0; |
---|
191 | int n; |
---|
192 | |
---|
193 | for (n = 0; n < blotCount; n++) |
---|
194 | { |
---|
195 | FLOAT distSquare = |
---|
196 | blots[n].x * blots[n].x + |
---|
197 | blots[n].y * blots[n].y + |
---|
198 | blots[n].z * blots[n].z; |
---|
199 | if (distSquare > max) |
---|
200 | { |
---|
201 | max = distSquare; |
---|
202 | } |
---|
203 | } |
---|
204 | |
---|
205 | if (max == 0.0) |
---|
206 | { |
---|
207 | return; |
---|
208 | } |
---|
209 | |
---|
210 | max = sqrt (max); |
---|
211 | |
---|
212 | for (n = 0; n < blotCount; n++) |
---|
213 | { |
---|
214 | blots[n].x /= max; |
---|
215 | blots[n].y /= max; |
---|
216 | blots[n].z /= max; |
---|
217 | } |
---|
218 | } |
---|
219 | |
---|
220 | /* randomly reorder the blots */ |
---|
221 | static void randomlyReorderBlots (void) |
---|
222 | { |
---|
223 | int n; |
---|
224 | |
---|
225 | for (n = 0; n < blotCount; n++) |
---|
226 | { |
---|
227 | int m = RAND_FLOAT_01 * (blotCount - n) + n; |
---|
228 | Blot tmpBlot = blots[n]; |
---|
229 | blots[n] = blots[m]; |
---|
230 | blots[m] = tmpBlot; |
---|
231 | } |
---|
232 | } |
---|
233 | |
---|
234 | /* randomly rotate the blots around the origin */ |
---|
235 | static void randomlyRotateBlots (void) |
---|
236 | { |
---|
237 | int n; |
---|
238 | |
---|
239 | /* random amounts to rotate about each axis */ |
---|
240 | FLOAT xRot = RAND_FLOAT_PM1 * M_PI; |
---|
241 | FLOAT yRot = RAND_FLOAT_PM1 * M_PI; |
---|
242 | FLOAT zRot = RAND_FLOAT_PM1 * M_PI; |
---|
243 | |
---|
244 | /* rotation factors */ |
---|
245 | FLOAT sinX = sin (xRot); |
---|
246 | FLOAT cosX = cos (xRot); |
---|
247 | FLOAT sinY = sin (yRot); |
---|
248 | FLOAT cosY = cos (yRot); |
---|
249 | FLOAT sinZ = sin (zRot); |
---|
250 | FLOAT cosZ = cos (zRot); |
---|
251 | |
---|
252 | for (n = 0; n < blotCount; n++) |
---|
253 | { |
---|
254 | FLOAT x1 = blots[n].x; |
---|
255 | FLOAT y1 = blots[n].y; |
---|
256 | FLOAT z1 = blots[n].z; |
---|
257 | FLOAT x2, y2, z2; |
---|
258 | |
---|
259 | /* rotate on z axis */ |
---|
260 | x2 = x1 * cosZ - y1 * sinZ; |
---|
261 | y2 = x1 * sinZ + y1 * cosZ; |
---|
262 | z2 = z1; |
---|
263 | |
---|
264 | /* rotate on x axis */ |
---|
265 | y1 = y2 * cosX - z2 * sinX; |
---|
266 | z1 = y2 * sinX + z2 * cosX; |
---|
267 | x1 = x2; |
---|
268 | |
---|
269 | /* rotate on y axis */ |
---|
270 | z2 = z1 * cosY - x1 * sinY; |
---|
271 | x2 = z1 * sinY + x1 * cosY; |
---|
272 | y2 = y1; |
---|
273 | |
---|
274 | blots[n].x = x2; |
---|
275 | blots[n].y = y2; |
---|
276 | blots[n].z = z2; |
---|
277 | } |
---|
278 | } |
---|
279 | |
---|
280 | |
---|
281 | |
---|
282 | /* |
---|
283 | * blot configurations |
---|
284 | */ |
---|
285 | |
---|
286 | /* set up the initial array of blots to be a at the edge of a sphere */ |
---|
287 | static void setupBlotsSphere (void) |
---|
288 | { |
---|
289 | int n; |
---|
290 | |
---|
291 | blotCount = requestedBlotCount; |
---|
292 | blots = calloc (sizeof (Blot), blotCount); |
---|
293 | |
---|
294 | for (n = 0; n < blotCount; n++) |
---|
295 | { |
---|
296 | /* pick a spot, but reject if its radius is < 0.2 or > 1 to |
---|
297 | * avoid scaling problems */ |
---|
298 | FLOAT x, y, z, radius; |
---|
299 | |
---|
300 | for (;;) |
---|
301 | { |
---|
302 | x = RAND_FLOAT_PM1; |
---|
303 | y = RAND_FLOAT_PM1; |
---|
304 | z = RAND_FLOAT_PM1; |
---|
305 | |
---|
306 | radius = sqrt (x * x + y * y + z * z); |
---|
307 | if ((radius >= 0.2) && (radius <= 1.0)) |
---|
308 | { |
---|
309 | break; |
---|
310 | } |
---|
311 | } |
---|
312 | |
---|
313 | x /= radius; |
---|
314 | y /= radius; |
---|
315 | z /= radius; |
---|
316 | |
---|
317 | initBlot (&blots[n], x, y, z); |
---|
318 | } |
---|
319 | } |
---|
320 | |
---|
321 | /* set up the initial array of blots to be a simple cube */ |
---|
322 | static void setupBlotsCube (void) |
---|
323 | { |
---|
324 | int i, j, k, n; |
---|
325 | |
---|
326 | /* derive blotsPerEdge from blotCount, but then do the reverse |
---|
327 | * since roundoff may have changed blotCount */ |
---|
328 | int blotsPerEdge = ((requestedBlotCount - 8) / 12) + 2; |
---|
329 | FLOAT distBetween; |
---|
330 | |
---|
331 | if (blotsPerEdge < 2) |
---|
332 | { |
---|
333 | blotsPerEdge = 2; |
---|
334 | } |
---|
335 | |
---|
336 | distBetween = 2.0 / (blotsPerEdge - 1.0); |
---|
337 | |
---|
338 | blotCount = 8 + (blotsPerEdge - 2) * 12; |
---|
339 | blots = calloc (sizeof (Blot), blotCount); |
---|
340 | n = 0; |
---|
341 | |
---|
342 | /* define the corners */ |
---|
343 | for (i = -1; i < 2; i += 2) |
---|
344 | { |
---|
345 | for (j = -1; j < 2; j += 2) |
---|
346 | { |
---|
347 | for (k = -1; k < 2; k += 2) |
---|
348 | { |
---|
349 | initBlot (&blots[n], i, j, k); |
---|
350 | n++; |
---|
351 | } |
---|
352 | } |
---|
353 | } |
---|
354 | |
---|
355 | /* define the edges */ |
---|
356 | for (i = 1; i < (blotsPerEdge - 1); i++) |
---|
357 | { |
---|
358 | FLOAT varEdge = distBetween * i - 1; |
---|
359 | initBlot (&blots[n++], varEdge, -1, -1); |
---|
360 | initBlot (&blots[n++], varEdge, 1, -1); |
---|
361 | initBlot (&blots[n++], varEdge, -1, 1); |
---|
362 | initBlot (&blots[n++], varEdge, 1, 1); |
---|
363 | initBlot (&blots[n++], -1, varEdge, -1); |
---|
364 | initBlot (&blots[n++], 1, varEdge, -1); |
---|
365 | initBlot (&blots[n++], -1, varEdge, 1); |
---|
366 | initBlot (&blots[n++], 1, varEdge, 1); |
---|
367 | initBlot (&blots[n++], -1, -1, varEdge); |
---|
368 | initBlot (&blots[n++], 1, -1, varEdge); |
---|
369 | initBlot (&blots[n++], -1, 1, varEdge); |
---|
370 | initBlot (&blots[n++], 1, 1, varEdge); |
---|
371 | } |
---|
372 | |
---|
373 | scaleBlotsToRadius1 (); |
---|
374 | randomlyReorderBlots (); |
---|
375 | randomlyRotateBlots (); |
---|
376 | } |
---|
377 | |
---|
378 | /* set up the initial array of blots to be a cylinder */ |
---|
379 | static void setupBlotsCylinder (void) |
---|
380 | { |
---|
381 | int i, j, n; |
---|
382 | FLOAT distBetween; |
---|
383 | |
---|
384 | /* derive blotsPerEdge and blotsPerRing from blotCount, but then do the |
---|
385 | * reverse since roundoff may have changed blotCount */ |
---|
386 | FLOAT reqRoot = sqrt ((FLOAT) requestedBlotCount); |
---|
387 | int blotsPerRing = ceil (RAND_FLOAT_PM1 * reqRoot) / 2 + reqRoot; |
---|
388 | int blotsPerEdge = requestedBlotCount / blotsPerRing; |
---|
389 | |
---|
390 | if (blotsPerRing < 2) |
---|
391 | { |
---|
392 | blotsPerRing = 2; |
---|
393 | } |
---|
394 | |
---|
395 | if (blotsPerEdge < 2) |
---|
396 | { |
---|
397 | blotsPerEdge = 2; |
---|
398 | } |
---|
399 | |
---|
400 | distBetween = 2.0 / (blotsPerEdge - 1); |
---|
401 | |
---|
402 | blotCount = blotsPerEdge * blotsPerRing; |
---|
403 | blots = calloc (sizeof (Blot), blotCount); |
---|
404 | n = 0; |
---|
405 | |
---|
406 | /* define the edges */ |
---|
407 | for (i = 0; i < blotsPerRing; i++) |
---|
408 | { |
---|
409 | FLOAT x = sin (2 * M_PI / blotsPerRing * i); |
---|
410 | FLOAT y = cos (2 * M_PI / blotsPerRing * i); |
---|
411 | for (j = 0; j < blotsPerEdge; j++) |
---|
412 | { |
---|
413 | initBlot (&blots[n], x, y, j * distBetween - 1); |
---|
414 | n++; |
---|
415 | } |
---|
416 | } |
---|
417 | |
---|
418 | scaleBlotsToRadius1 (); |
---|
419 | randomlyReorderBlots (); |
---|
420 | randomlyRotateBlots (); |
---|
421 | } |
---|
422 | |
---|
423 | /* set up the initial array of blots to be a squiggle */ |
---|
424 | static void setupBlotsSquiggle (void) |
---|
425 | { |
---|
426 | FLOAT x, y, z, xv, yv, zv, len; |
---|
427 | int minCoor, maxCoor; |
---|
428 | int n; |
---|
429 | |
---|
430 | blotCount = requestedBlotCount; |
---|
431 | blots = calloc (sizeof (Blot), blotCount); |
---|
432 | |
---|
433 | maxCoor = (int) (RAND_FLOAT_01 * 5) + 1; |
---|
434 | minCoor = -maxCoor; |
---|
435 | |
---|
436 | x = RAND_FLOAT_PM1; |
---|
437 | y = RAND_FLOAT_PM1; |
---|
438 | z = RAND_FLOAT_PM1; |
---|
439 | |
---|
440 | xv = RAND_FLOAT_PM1; |
---|
441 | yv = RAND_FLOAT_PM1; |
---|
442 | zv = RAND_FLOAT_PM1; |
---|
443 | len = sqrt (xv * xv + yv * yv + zv * zv); |
---|
444 | xv /= len; |
---|
445 | yv /= len; |
---|
446 | zv /= len; |
---|
447 | |
---|
448 | for (n = 0; n < blotCount; n++) |
---|
449 | { |
---|
450 | FLOAT newx, newy, newz; |
---|
451 | initBlot (&blots[n], x, y, z); |
---|
452 | |
---|
453 | for (;;) |
---|
454 | { |
---|
455 | xv += RAND_FLOAT_PM1 * 0.1; |
---|
456 | yv += RAND_FLOAT_PM1 * 0.1; |
---|
457 | zv += RAND_FLOAT_PM1 * 0.1; |
---|
458 | len = sqrt (xv * xv + yv * yv + zv * zv); |
---|
459 | xv /= len; |
---|
460 | yv /= len; |
---|
461 | zv /= len; |
---|
462 | |
---|
463 | newx = x + xv * 0.1; |
---|
464 | newy = y + yv * 0.1; |
---|
465 | newz = z + zv * 0.1; |
---|
466 | |
---|
467 | if ( (newx >= minCoor) && (newx <= maxCoor) |
---|
468 | && (newy >= minCoor) && (newy <= maxCoor) |
---|
469 | && (newz >= minCoor) && (newz <= maxCoor)) |
---|
470 | { |
---|
471 | break; |
---|
472 | } |
---|
473 | } |
---|
474 | |
---|
475 | x = newx; |
---|
476 | y = newy; |
---|
477 | z = newz; |
---|
478 | } |
---|
479 | |
---|
480 | scaleBlotsToRadius1 (); |
---|
481 | randomlyReorderBlots (); |
---|
482 | } |
---|
483 | |
---|
484 | /* set up the initial array of blots to be near the corners of a |
---|
485 | * cube, distributed slightly */ |
---|
486 | static void setupBlotsCubeCorners (void) |
---|
487 | { |
---|
488 | int n; |
---|
489 | |
---|
490 | blotCount = requestedBlotCount; |
---|
491 | blots = calloc (sizeof (Blot), blotCount); |
---|
492 | |
---|
493 | for (n = 0; n < blotCount; n++) |
---|
494 | { |
---|
495 | FLOAT x = rint (RAND_FLOAT_01) * 2 - 1; |
---|
496 | FLOAT y = rint (RAND_FLOAT_01) * 2 - 1; |
---|
497 | FLOAT z = rint (RAND_FLOAT_01) * 2 - 1; |
---|
498 | |
---|
499 | x += RAND_FLOAT_PM1 * 0.3; |
---|
500 | y += RAND_FLOAT_PM1 * 0.3; |
---|
501 | z += RAND_FLOAT_PM1 * 0.3; |
---|
502 | |
---|
503 | initBlot (&blots[n], x, y, z); |
---|
504 | } |
---|
505 | |
---|
506 | scaleBlotsToRadius1 (); |
---|
507 | randomlyRotateBlots (); |
---|
508 | } |
---|
509 | |
---|
510 | /* set up the initial array of blots to be randomly distributed |
---|
511 | * on the surface of a tetrahedron */ |
---|
512 | static void setupBlotsTetrahedron (void) |
---|
513 | { |
---|
514 | /* table of corners of the tetrahedron */ |
---|
515 | static FLOAT cor[4][3] = { { 0.0, 1.0, 0.0 }, |
---|
516 | { -0.75, -0.5, -0.433013 }, |
---|
517 | { 0.0, -0.5, 0.866025 }, |
---|
518 | { 0.75, -0.5, -0.433013 } }; |
---|
519 | |
---|
520 | int n, c; |
---|
521 | |
---|
522 | /* derive blotsPerSurface from blotCount, but then do the reverse |
---|
523 | * since roundoff may have changed blotCount */ |
---|
524 | int blotsPerSurface = requestedBlotCount / 4; |
---|
525 | |
---|
526 | blotCount = blotsPerSurface * 4; |
---|
527 | blots = calloc (sizeof (Blot), blotCount); |
---|
528 | |
---|
529 | for (n = 0; n < blotCount; n += 4) |
---|
530 | { |
---|
531 | /* pick a random point on a unit right triangle */ |
---|
532 | FLOAT rawx = RAND_FLOAT_01; |
---|
533 | FLOAT rawy = RAND_FLOAT_01; |
---|
534 | |
---|
535 | if ((rawx + rawy) > 1) |
---|
536 | { |
---|
537 | /* swap coords into place */ |
---|
538 | FLOAT t = 1.0 - rawx; |
---|
539 | rawx = 1.0 - rawy; |
---|
540 | rawy = t; |
---|
541 | } |
---|
542 | |
---|
543 | /* translate the point to be on each of the surfaces */ |
---|
544 | for (c = 0; c < 4; c++) |
---|
545 | { |
---|
546 | FLOAT x, y, z; |
---|
547 | |
---|
548 | int c1 = (c + 1) % 4; |
---|
549 | int c2 = (c + 2) % 4; |
---|
550 | |
---|
551 | x = (cor[c1][0] - cor[c][0]) * rawx + |
---|
552 | (cor[c2][0] - cor[c][0]) * rawy + |
---|
553 | cor[c][0]; |
---|
554 | |
---|
555 | y = (cor[c1][1] - cor[c][1]) * rawx + |
---|
556 | (cor[c2][1] - cor[c][1]) * rawy + |
---|
557 | cor[c][1]; |
---|
558 | |
---|
559 | z = (cor[c1][2] - cor[c][2]) * rawx + |
---|
560 | (cor[c2][2] - cor[c][2]) * rawy + |
---|
561 | cor[c][2]; |
---|
562 | |
---|
563 | initBlot (&blots[n + c], x, y, z); |
---|
564 | } |
---|
565 | } |
---|
566 | |
---|
567 | randomlyRotateBlots (); |
---|
568 | } |
---|
569 | |
---|
570 | /* set up the initial array of blots to be an almost-evenly-distributed |
---|
571 | * square sheet */ |
---|
572 | static void setupBlotsSheet (void) |
---|
573 | { |
---|
574 | int x, y; |
---|
575 | |
---|
576 | int blotsPerDimension = floor (sqrt (requestedBlotCount)); |
---|
577 | FLOAT spaceBetween; |
---|
578 | |
---|
579 | if (blotsPerDimension < 2) |
---|
580 | { |
---|
581 | blotsPerDimension = 2; |
---|
582 | } |
---|
583 | |
---|
584 | spaceBetween = 2.0 / (blotsPerDimension - 1); |
---|
585 | |
---|
586 | blotCount = blotsPerDimension * blotsPerDimension; |
---|
587 | blots = calloc (sizeof (Blot), blotCount); |
---|
588 | |
---|
589 | for (x = 0; x < blotsPerDimension; x++) |
---|
590 | { |
---|
591 | for (y = 0; y < blotsPerDimension; y++) |
---|
592 | { |
---|
593 | FLOAT x1 = x * spaceBetween - 1.0; |
---|
594 | FLOAT y1 = y * spaceBetween - 1.0; |
---|
595 | FLOAT z1 = 0.0; |
---|
596 | |
---|
597 | x1 += RAND_FLOAT_PM1 * spaceBetween / 3; |
---|
598 | y1 += RAND_FLOAT_PM1 * spaceBetween / 3; |
---|
599 | z1 += RAND_FLOAT_PM1 * spaceBetween / 2; |
---|
600 | |
---|
601 | initBlot (&blots[x + y * blotsPerDimension], x1, y1, z1); |
---|
602 | } |
---|
603 | } |
---|
604 | |
---|
605 | scaleBlotsToRadius1 (); |
---|
606 | randomlyReorderBlots (); |
---|
607 | randomlyRotateBlots (); |
---|
608 | } |
---|
609 | |
---|
610 | /* set up the initial array of blots to be a swirlycone */ |
---|
611 | static void setupBlotsSwirlyCone (void) |
---|
612 | { |
---|
613 | FLOAT radSpace = 1.0 / (requestedBlotCount - 1); |
---|
614 | FLOAT zSpace = radSpace * 2; |
---|
615 | FLOAT rotAmt = RAND_FLOAT_PM1 * M_PI / 10; |
---|
616 | |
---|
617 | int n; |
---|
618 | FLOAT rot = 0.0; |
---|
619 | |
---|
620 | blotCount = requestedBlotCount; |
---|
621 | blots = calloc (sizeof (Blot), blotCount); |
---|
622 | |
---|
623 | for (n = 0; n < blotCount; n++) |
---|
624 | { |
---|
625 | FLOAT radius = n * radSpace; |
---|
626 | FLOAT x = cos (rot) * radius; |
---|
627 | FLOAT y = sin (rot) * radius; |
---|
628 | FLOAT z = n * zSpace - 1.0; |
---|
629 | |
---|
630 | rot += rotAmt; |
---|
631 | initBlot (&blots[n], x, y, z); |
---|
632 | } |
---|
633 | |
---|
634 | scaleBlotsToRadius1 (); |
---|
635 | randomlyReorderBlots (); |
---|
636 | randomlyRotateBlots (); |
---|
637 | } |
---|
638 | |
---|
639 | /* forward declaration for recursive use immediately below */ |
---|
640 | static void setupBlots (void); |
---|
641 | |
---|
642 | /* set up the blots to be two of the other choices, placed next to |
---|
643 | * each other */ |
---|
644 | static void setupBlotsDuo (void) |
---|
645 | { |
---|
646 | int origRequest = requestedBlotCount; |
---|
647 | FLOAT tx, ty, tz, radius; |
---|
648 | Blot *blots1, *blots2; |
---|
649 | int count1, count2; |
---|
650 | int n; |
---|
651 | |
---|
652 | if (requestedBlotCount < 15) |
---|
653 | { |
---|
654 | /* special case bottom-out */ |
---|
655 | setupBlotsSphere (); |
---|
656 | return; |
---|
657 | } |
---|
658 | |
---|
659 | tx = RAND_FLOAT_PM1; |
---|
660 | ty = RAND_FLOAT_PM1; |
---|
661 | tz = RAND_FLOAT_PM1; |
---|
662 | radius = sqrt (tx * tx + ty * ty + tz * tz); |
---|
663 | tx /= radius; |
---|
664 | ty /= radius; |
---|
665 | tz /= radius; |
---|
666 | |
---|
667 | /* recursive call to setup set 1 */ |
---|
668 | requestedBlotCount = origRequest / 2; |
---|
669 | setupBlots (); |
---|
670 | |
---|
671 | if (blotCount >= origRequest) |
---|
672 | { |
---|
673 | /* return immediately if this satisfies the original count request */ |
---|
674 | requestedBlotCount = origRequest; |
---|
675 | return; |
---|
676 | } |
---|
677 | |
---|
678 | blots1 = blots; |
---|
679 | count1 = blotCount; |
---|
680 | blots = NULL; |
---|
681 | blotCount = 0; |
---|
682 | |
---|
683 | /* translate to new position */ |
---|
684 | for (n = 0; n < count1; n++) |
---|
685 | { |
---|
686 | blots1[n].x += tx; |
---|
687 | blots1[n].y += ty; |
---|
688 | blots1[n].z += tz; |
---|
689 | } |
---|
690 | |
---|
691 | /* recursive call to setup set 2 */ |
---|
692 | requestedBlotCount = origRequest - count1; |
---|
693 | setupBlots (); |
---|
694 | blots2 = blots; |
---|
695 | count2 = blotCount; |
---|
696 | |
---|
697 | /* translate to new position */ |
---|
698 | for (n = 0; n < count2; n++) |
---|
699 | { |
---|
700 | blots2[n].x -= tx; |
---|
701 | blots2[n].y -= ty; |
---|
702 | blots2[n].z -= tz; |
---|
703 | } |
---|
704 | |
---|
705 | /* combine the two arrays */ |
---|
706 | blotCount = count1 + count2; |
---|
707 | blots = calloc (sizeof (Blot), blotCount); |
---|
708 | memcpy (&blots[0], blots1, sizeof (Blot) * count1); |
---|
709 | memcpy (&blots[count1], blots2, sizeof (Blot) * count2); |
---|
710 | free (blots1); |
---|
711 | free (blots2); |
---|
712 | |
---|
713 | scaleBlotsToRadius1 (); |
---|
714 | randomlyReorderBlots (); |
---|
715 | |
---|
716 | /* restore the original requested count, for future iterations */ |
---|
717 | requestedBlotCount = origRequest; |
---|
718 | } |
---|
719 | |
---|
720 | |
---|
721 | |
---|
722 | /* |
---|
723 | * main blot setup |
---|
724 | */ |
---|
725 | |
---|
726 | /* free the blots, in preparation for a new shape */ |
---|
727 | static void freeBlots (void) |
---|
728 | { |
---|
729 | if (blots != NULL) |
---|
730 | { |
---|
731 | free (blots); |
---|
732 | blots = NULL; |
---|
733 | } |
---|
734 | |
---|
735 | if (segsToErase != NULL) |
---|
736 | { |
---|
737 | free (segsToErase); |
---|
738 | segsToErase = NULL; |
---|
739 | } |
---|
740 | |
---|
741 | if (segsToDraw != NULL) |
---|
742 | { |
---|
743 | free (segsToDraw); |
---|
744 | segsToDraw = NULL; |
---|
745 | } |
---|
746 | } |
---|
747 | |
---|
748 | /* set up the initial arrays of blots */ |
---|
749 | static void setupBlots (void) |
---|
750 | { |
---|
751 | int which = RAND_FLOAT_01 * 11; |
---|
752 | |
---|
753 | freeBlots (); |
---|
754 | |
---|
755 | switch (which) |
---|
756 | { |
---|
757 | case 0: |
---|
758 | setupBlotsCube (); |
---|
759 | break; |
---|
760 | case 1: |
---|
761 | setupBlotsSphere (); |
---|
762 | break; |
---|
763 | case 2: |
---|
764 | setupBlotsCylinder (); |
---|
765 | break; |
---|
766 | case 3: |
---|
767 | setupBlotsSquiggle (); |
---|
768 | break; |
---|
769 | case 4: |
---|
770 | setupBlotsCubeCorners (); |
---|
771 | break; |
---|
772 | case 5: |
---|
773 | setupBlotsTetrahedron (); |
---|
774 | break; |
---|
775 | case 6: |
---|
776 | setupBlotsSheet (); |
---|
777 | break; |
---|
778 | case 7: |
---|
779 | setupBlotsSwirlyCone (); |
---|
780 | break; |
---|
781 | case 8: |
---|
782 | case 9: |
---|
783 | case 10: |
---|
784 | setupBlotsDuo (); |
---|
785 | break; |
---|
786 | } |
---|
787 | } |
---|
788 | |
---|
789 | /* set up the segments arrays */ |
---|
790 | static void setupSegs (void) |
---|
791 | { |
---|
792 | /* there are blotShapeCount - 1 line segments per blot */ |
---|
793 | segCount = blotCount * (blotShapeCount - 1); |
---|
794 | segsToErase = calloc (sizeof (LineSegment), segCount); |
---|
795 | segsToDraw = calloc (sizeof (LineSegment), segCount); |
---|
796 | |
---|
797 | /* erase the world */ |
---|
798 | XFillRectangle (display, drawable, gcs[0], 0, 0, |
---|
799 | windowWidth, windowHeight); |
---|
800 | } |
---|
801 | |
---|
802 | |
---|
803 | |
---|
804 | /* |
---|
805 | * color setup stuff |
---|
806 | */ |
---|
807 | |
---|
808 | /* set up the colormap */ |
---|
809 | static void setupColormap (XWindowAttributes *xgwa) |
---|
810 | { |
---|
811 | int n; |
---|
812 | XGCValues gcv; |
---|
813 | XColor *colors = (XColor *) calloc (sizeof (XColor), colorCount + 1); |
---|
814 | |
---|
815 | unsigned short r, g, b; |
---|
816 | int h1, h2; |
---|
817 | double s1, s2, v1, v2; |
---|
818 | |
---|
819 | r = RAND_FLOAT_01 * 0x10000; |
---|
820 | g = RAND_FLOAT_01 * 0x10000; |
---|
821 | b = RAND_FLOAT_01 * 0x10000; |
---|
822 | rgb_to_hsv (r, g, b, &h1, &s1, &v1); |
---|
823 | v1 = 1.0; |
---|
824 | s1 = 1.0; |
---|
825 | |
---|
826 | r = RAND_FLOAT_01 * 0x10000; |
---|
827 | g = RAND_FLOAT_01 * 0x10000; |
---|
828 | b = RAND_FLOAT_01 * 0x10000; |
---|
829 | rgb_to_hsv (r, g, b, &h2, &s2, &v2); |
---|
830 | s2 = 0.7; |
---|
831 | v2 = 0.7; |
---|
832 | |
---|
833 | colors[0].pixel = get_pixel_resource ("background", "Background", |
---|
834 | display, xgwa->colormap); |
---|
835 | |
---|
836 | make_color_ramp (display, xgwa->colormap, h1, s1, v1, h2, s2, v2, |
---|
837 | colors + 1, &colorCount, False, True, False); |
---|
838 | |
---|
839 | if (colorCount < 1) |
---|
840 | { |
---|
841 | fprintf (stderr, "%s: couldn't allocate any colors\n", progname); |
---|
842 | exit (-1); |
---|
843 | } |
---|
844 | |
---|
845 | gcs = (GC *) calloc (sizeof (GC), colorCount + 1); |
---|
846 | |
---|
847 | for (n = 0; n <= colorCount; n++) |
---|
848 | { |
---|
849 | gcv.foreground = colors[n].pixel; |
---|
850 | gcv.line_width = lineWidth; |
---|
851 | gcs[n] = XCreateGC (display, window, GCForeground | GCLineWidth, &gcv); |
---|
852 | } |
---|
853 | |
---|
854 | free (colors); |
---|
855 | } |
---|
856 | |
---|
857 | |
---|
858 | |
---|
859 | /* |
---|
860 | * overall setup stuff |
---|
861 | */ |
---|
862 | |
---|
863 | /* set up the system */ |
---|
864 | static void setup (void) |
---|
865 | { |
---|
866 | XWindowAttributes xgwa; |
---|
867 | |
---|
868 | XGetWindowAttributes (display, window, &xgwa); |
---|
869 | |
---|
870 | windowWidth = xgwa.width; |
---|
871 | windowHeight = xgwa.height; |
---|
872 | centerX = windowWidth / 2; |
---|
873 | centerY = windowHeight / 2; |
---|
874 | baseScale = (xgwa.height < xgwa.width) ? xgwa.height : xgwa.width; |
---|
875 | |
---|
876 | if (doubleBuffer) |
---|
877 | { |
---|
878 | drawable = XCreatePixmap (display, window, xgwa.width, xgwa.height, |
---|
879 | xgwa.depth); |
---|
880 | } |
---|
881 | else |
---|
882 | { |
---|
883 | drawable = window; |
---|
884 | } |
---|
885 | |
---|
886 | setupColormap (&xgwa); |
---|
887 | setupBlots (); |
---|
888 | setupSegs (); |
---|
889 | |
---|
890 | /* set up the initial rotation, scale, and light values as random, but |
---|
891 | * with the targets equal to where it is */ |
---|
892 | xRot = xRotTarget = RAND_FLOAT_01 * M_PI; |
---|
893 | yRot = yRotTarget = RAND_FLOAT_01 * M_PI; |
---|
894 | zRot = zRotTarget = RAND_FLOAT_01 * M_PI; |
---|
895 | curScale = scaleTarget = RAND_FLOAT_01 * (maxScale - minScale) + minScale; |
---|
896 | lightX = lightXTarget = RAND_FLOAT_PM1; |
---|
897 | lightY = lightYTarget = RAND_FLOAT_PM1; |
---|
898 | lightZ = lightZTarget = RAND_FLOAT_PM1; |
---|
899 | |
---|
900 | itersTillNext = RAND_FLOAT_01 * maxIters; |
---|
901 | } |
---|
902 | |
---|
903 | |
---|
904 | |
---|
905 | /* |
---|
906 | * the simulation |
---|
907 | */ |
---|
908 | |
---|
909 | /* "render" the blots into segsToDraw, with the current rotation factors */ |
---|
910 | static void renderSegs (void) |
---|
911 | { |
---|
912 | int n; |
---|
913 | int m = 0; |
---|
914 | |
---|
915 | /* rotation factors */ |
---|
916 | FLOAT sinX = sin (xRot); |
---|
917 | FLOAT cosX = cos (xRot); |
---|
918 | FLOAT sinY = sin (yRot); |
---|
919 | FLOAT cosY = cos (yRot); |
---|
920 | FLOAT sinZ = sin (zRot); |
---|
921 | FLOAT cosZ = cos (zRot); |
---|
922 | |
---|
923 | for (n = 0; n < blotCount; n++) |
---|
924 | { |
---|
925 | Blot *b = &blots[n]; |
---|
926 | int i, j; |
---|
927 | int baseX, baseY; |
---|
928 | FLOAT radius; |
---|
929 | int x[3][3]; |
---|
930 | int y[3][3]; |
---|
931 | int color; |
---|
932 | |
---|
933 | FLOAT x1 = blots[n].x; |
---|
934 | FLOAT y1 = blots[n].y; |
---|
935 | FLOAT z1 = blots[n].z; |
---|
936 | FLOAT x2, y2, z2; |
---|
937 | |
---|
938 | /* rotate on z axis */ |
---|
939 | x2 = x1 * cosZ - y1 * sinZ; |
---|
940 | y2 = x1 * sinZ + y1 * cosZ; |
---|
941 | z2 = z1; |
---|
942 | |
---|
943 | /* rotate on x axis */ |
---|
944 | y1 = y2 * cosX - z2 * sinX; |
---|
945 | z1 = y2 * sinX + z2 * cosX; |
---|
946 | x1 = x2; |
---|
947 | |
---|
948 | /* rotate on y axis */ |
---|
949 | z2 = z1 * cosY - x1 * sinY; |
---|
950 | x2 = z1 * sinY + x1 * cosY; |
---|
951 | y2 = y1; |
---|
952 | |
---|
953 | /* the color to draw is based on the distance from the light of |
---|
954 | * the post-rotation blot */ |
---|
955 | x1 = x2 - lightX; |
---|
956 | y1 = y2 - lightY; |
---|
957 | z1 = z2 - lightZ; |
---|
958 | color = 1 + (x1 * x1 + y1 * y1 + z1 * z1) / 4 * colorCount; |
---|
959 | if (color > colorCount) |
---|
960 | { |
---|
961 | color = colorCount; |
---|
962 | } |
---|
963 | |
---|
964 | /* set up the base screen coordinates for drawing */ |
---|
965 | baseX = x2 / 2 * baseScale * curScale + centerX + centerXOff; |
---|
966 | baseY = y2 / 2 * baseScale * curScale + centerY + centerYOff; |
---|
967 | |
---|
968 | radius = (z2 + 1) / 2 * (maxRadius - minRadius) + minRadius; |
---|
969 | |
---|
970 | for (i = 0; i < 3; i++) |
---|
971 | { |
---|
972 | for (j = 0; j < 3; j++) |
---|
973 | { |
---|
974 | x[i][j] = baseX + |
---|
975 | ((i - 1) + (b->xoff[i][j] * maxNerveRadius)) * radius; |
---|
976 | y[i][j] = baseY + |
---|
977 | ((j - 1) + (b->yoff[i][j] * maxNerveRadius)) * radius; |
---|
978 | } |
---|
979 | } |
---|
980 | |
---|
981 | for (i = 1; i < blotShapeCount; i++) |
---|
982 | { |
---|
983 | segsToDraw[m].gc = gcs[color]; |
---|
984 | segsToDraw[m].x1 = x[blotShape[i-1].x + 1][blotShape[i-1].y + 1]; |
---|
985 | segsToDraw[m].y1 = y[blotShape[i-1].x + 1][blotShape[i-1].y + 1]; |
---|
986 | segsToDraw[m].x2 = x[blotShape[i].x + 1][blotShape[i].y + 1]; |
---|
987 | segsToDraw[m].y2 = y[blotShape[i].x + 1][blotShape[i].y + 1]; |
---|
988 | m++; |
---|
989 | } |
---|
990 | } |
---|
991 | } |
---|
992 | |
---|
993 | /* update blots, adjusting the offsets and rotation factors. */ |
---|
994 | static void updateWithFeeling (void) |
---|
995 | { |
---|
996 | int n, i, j; |
---|
997 | |
---|
998 | /* pick a new model if the time is right */ |
---|
999 | itersTillNext--; |
---|
1000 | if (itersTillNext < 0) |
---|
1001 | { |
---|
1002 | itersTillNext = RAND_FLOAT_01 * maxIters; |
---|
1003 | setupBlots (); |
---|
1004 | setupSegs (); |
---|
1005 | renderSegs (); |
---|
1006 | } |
---|
1007 | |
---|
1008 | /* update the rotation factors by moving them a bit toward the targets */ |
---|
1009 | xRot = xRot + (xRotTarget - xRot) * iterAmt; |
---|
1010 | yRot = yRot + (yRotTarget - yRot) * iterAmt; |
---|
1011 | zRot = zRot + (zRotTarget - zRot) * iterAmt; |
---|
1012 | |
---|
1013 | /* similarly the scale factor */ |
---|
1014 | curScale = curScale + (scaleTarget - curScale) * iterAmt; |
---|
1015 | |
---|
1016 | /* and similarly the light position */ |
---|
1017 | lightX = lightX + (lightXTarget - lightX) * iterAmt; |
---|
1018 | lightY = lightY + (lightYTarget - lightY) * iterAmt; |
---|
1019 | lightZ = lightZ + (lightZTarget - lightZ) * iterAmt; |
---|
1020 | |
---|
1021 | /* for each blot... */ |
---|
1022 | for (n = 0; n < blotCount; n++) |
---|
1023 | { |
---|
1024 | /* add a bit of random jitter to xoff/yoff */ |
---|
1025 | for (i = 0; i < 3; i++) |
---|
1026 | { |
---|
1027 | for (j = 0; j < 3; j++) |
---|
1028 | { |
---|
1029 | FLOAT newOff; |
---|
1030 | |
---|
1031 | newOff = blots[n].xoff[i][j] + RAND_FLOAT_PM1 * nervousness; |
---|
1032 | if (newOff < -1) newOff = -(newOff + 1) - 1; |
---|
1033 | else if (newOff > 1) newOff = -(newOff - 1) + 1; |
---|
1034 | blots[n].xoff[i][j] = newOff; |
---|
1035 | |
---|
1036 | newOff = blots[n].yoff[i][j] + RAND_FLOAT_PM1 * nervousness; |
---|
1037 | if (newOff < -1) newOff = -(newOff + 1) - 1; |
---|
1038 | else if (newOff > 1) newOff = -(newOff - 1) + 1; |
---|
1039 | blots[n].yoff[i][j] = newOff; |
---|
1040 | } |
---|
1041 | } |
---|
1042 | } |
---|
1043 | |
---|
1044 | /* depending on random chance, update one or more factors */ |
---|
1045 | if (RAND_FLOAT_01 <= eventChance) |
---|
1046 | { |
---|
1047 | int which = RAND_FLOAT_01 * 14; |
---|
1048 | switch (which) |
---|
1049 | { |
---|
1050 | case 0: |
---|
1051 | { |
---|
1052 | xRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1053 | break; |
---|
1054 | } |
---|
1055 | case 1: |
---|
1056 | { |
---|
1057 | yRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1058 | break; |
---|
1059 | } |
---|
1060 | case 2: |
---|
1061 | { |
---|
1062 | zRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1063 | break; |
---|
1064 | } |
---|
1065 | case 3: |
---|
1066 | { |
---|
1067 | xRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1068 | yRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1069 | break; |
---|
1070 | } |
---|
1071 | case 4: |
---|
1072 | { |
---|
1073 | xRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1074 | zRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1075 | break; |
---|
1076 | } |
---|
1077 | case 5: |
---|
1078 | { |
---|
1079 | yRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1080 | zRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1081 | break; |
---|
1082 | } |
---|
1083 | case 6: |
---|
1084 | { |
---|
1085 | xRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1086 | yRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1087 | zRotTarget = RAND_FLOAT_PM1 * M_PI * 2; |
---|
1088 | break; |
---|
1089 | } |
---|
1090 | case 7: |
---|
1091 | { |
---|
1092 | centerXOff = RAND_FLOAT_PM1 * maxRadius; |
---|
1093 | break; |
---|
1094 | } |
---|
1095 | case 8: |
---|
1096 | { |
---|
1097 | centerYOff = RAND_FLOAT_PM1 * maxRadius; |
---|
1098 | break; |
---|
1099 | } |
---|
1100 | case 9: |
---|
1101 | { |
---|
1102 | centerXOff = RAND_FLOAT_PM1 * maxRadius; |
---|
1103 | centerYOff = RAND_FLOAT_PM1 * maxRadius; |
---|
1104 | break; |
---|
1105 | } |
---|
1106 | case 10: |
---|
1107 | { |
---|
1108 | scaleTarget = |
---|
1109 | RAND_FLOAT_01 * (maxScale - minScale) + minScale; |
---|
1110 | break; |
---|
1111 | } |
---|
1112 | case 11: |
---|
1113 | { |
---|
1114 | curScale = |
---|
1115 | RAND_FLOAT_01 * (maxScale - minScale) + minScale; |
---|
1116 | break; |
---|
1117 | } |
---|
1118 | case 12: |
---|
1119 | { |
---|
1120 | lightX = RAND_FLOAT_PM1; |
---|
1121 | lightY = RAND_FLOAT_PM1; |
---|
1122 | lightZ = RAND_FLOAT_PM1; |
---|
1123 | break; |
---|
1124 | } |
---|
1125 | case 13: |
---|
1126 | { |
---|
1127 | lightXTarget = RAND_FLOAT_PM1; |
---|
1128 | lightYTarget = RAND_FLOAT_PM1; |
---|
1129 | lightZTarget = RAND_FLOAT_PM1; |
---|
1130 | break; |
---|
1131 | } |
---|
1132 | } |
---|
1133 | } |
---|
1134 | } |
---|
1135 | |
---|
1136 | /* erase segsToErase and draw segsToDraw */ |
---|
1137 | static void eraseAndDraw (void) |
---|
1138 | { |
---|
1139 | int n; |
---|
1140 | |
---|
1141 | for (n = 0; n < segCount; n++) |
---|
1142 | { |
---|
1143 | LineSegment *seg = &segsToErase[n]; |
---|
1144 | XDrawLine (display, drawable, gcs[0], |
---|
1145 | seg->x1, seg->y1, seg->x2, seg->y2); |
---|
1146 | seg = &segsToDraw[n]; |
---|
1147 | XDrawLine (display, drawable, seg->gc, |
---|
1148 | seg->x1, seg->y1, seg->x2, seg->y2); |
---|
1149 | } |
---|
1150 | |
---|
1151 | if (doubleBuffer) |
---|
1152 | { |
---|
1153 | XCopyArea (display, drawable, window, gcs[0], 0, 0, |
---|
1154 | windowWidth, windowHeight, 0, 0); |
---|
1155 | } |
---|
1156 | } |
---|
1157 | |
---|
1158 | /* do one iteration */ |
---|
1159 | static void oneIteration (void) |
---|
1160 | { |
---|
1161 | /* switch segsToErase and segsToDraw */ |
---|
1162 | LineSegment *temp = segsToDraw; |
---|
1163 | segsToDraw = segsToErase; |
---|
1164 | segsToErase = temp; |
---|
1165 | |
---|
1166 | /* update the model */ |
---|
1167 | updateWithFeeling (); |
---|
1168 | |
---|
1169 | /* render new segments */ |
---|
1170 | renderSegs (); |
---|
1171 | |
---|
1172 | /* erase old segments and draw new ones */ |
---|
1173 | eraseAndDraw (); |
---|
1174 | } |
---|
1175 | |
---|
1176 | char *progclass = "NerveRot"; |
---|
1177 | |
---|
1178 | char *defaults [] = { |
---|
1179 | ".background: black", |
---|
1180 | ".foreground: white", |
---|
1181 | "*count: 250", |
---|
1182 | "*colors: 4", |
---|
1183 | "*delay: 10000", |
---|
1184 | "*maxIters: 1200", |
---|
1185 | "*doubleBuffer: false", |
---|
1186 | "*eventChance: 0.2", |
---|
1187 | "*iterAmt: 0.01", |
---|
1188 | "*lineWidth: 0", |
---|
1189 | "*minScale: 0.6", |
---|
1190 | "*maxScale: 1.75", |
---|
1191 | "*minRadius: 3", |
---|
1192 | "*maxRadius: 25", |
---|
1193 | "*maxNerveRadius: 0.7", |
---|
1194 | "*nervousness: 0.3", |
---|
1195 | 0 |
---|
1196 | }; |
---|
1197 | |
---|
1198 | XrmOptionDescRec options [] = { |
---|
1199 | { "-count", ".count", XrmoptionSepArg, 0 }, |
---|
1200 | { "-colors", ".colors", XrmoptionSepArg, 0 }, |
---|
1201 | { "-delay", ".delay", XrmoptionSepArg, 0 }, |
---|
1202 | { "-max-iters", ".maxIters", XrmoptionSepArg, 0 }, |
---|
1203 | { "-db", ".doubleBuffer", XrmoptionNoArg, "true" }, |
---|
1204 | { "-no-db", ".doubleBuffer", XrmoptionNoArg, "false" }, |
---|
1205 | { "-event-chance", ".eventChance", XrmoptionSepArg, 0 }, |
---|
1206 | { "-iter-amt", ".iterAmt", XrmoptionSepArg, 0 }, |
---|
1207 | { "-line-width", ".lineWidth", XrmoptionSepArg, 0 }, |
---|
1208 | { "-min-scale", ".minScale", XrmoptionSepArg, 0 }, |
---|
1209 | { "-max-scale", ".maxScale", XrmoptionSepArg, 0 }, |
---|
1210 | { "-min-radius", ".minRadius", XrmoptionSepArg, 0 }, |
---|
1211 | { "-max-radius", ".maxRadius", XrmoptionSepArg, 0 }, |
---|
1212 | { "-max-nerve-radius", ".maxNerveRadius", XrmoptionSepArg, 0 }, |
---|
1213 | { "-nervousness", ".nervousness", XrmoptionSepArg, 0 }, |
---|
1214 | { 0, 0, 0, 0 } |
---|
1215 | }; |
---|
1216 | |
---|
1217 | /* initialize the user-specifiable params */ |
---|
1218 | static void initParams (void) |
---|
1219 | { |
---|
1220 | int problems = 0; |
---|
1221 | |
---|
1222 | delay = get_integer_resource ("delay", "Delay"); |
---|
1223 | if (delay < 0) |
---|
1224 | { |
---|
1225 | fprintf (stderr, "error: delay must be at least 0\n"); |
---|
1226 | problems = 1; |
---|
1227 | } |
---|
1228 | |
---|
1229 | maxIters = get_integer_resource ("maxIters", "Integer"); |
---|
1230 | if (maxIters < 0) |
---|
1231 | { |
---|
1232 | fprintf (stderr, "error: maxIters must be at least 0\n"); |
---|
1233 | problems = 1; |
---|
1234 | } |
---|
1235 | |
---|
1236 | doubleBuffer = get_boolean_resource ("doubleBuffer", "Boolean"); |
---|
1237 | |
---|
1238 | requestedBlotCount = get_integer_resource ("count", "Count"); |
---|
1239 | if (requestedBlotCount <= 0) |
---|
1240 | { |
---|
1241 | fprintf (stderr, "error: count must be at least 0\n"); |
---|
1242 | problems = 1; |
---|
1243 | } |
---|
1244 | |
---|
1245 | colorCount = get_integer_resource ("colors", "Colors"); |
---|
1246 | if (colorCount <= 0) |
---|
1247 | { |
---|
1248 | fprintf (stderr, "error: colors must be at least 1\n"); |
---|
1249 | problems = 1; |
---|
1250 | } |
---|
1251 | |
---|
1252 | lineWidth = get_integer_resource ("lineWidth", "LineWidth"); |
---|
1253 | if (lineWidth < 0) |
---|
1254 | { |
---|
1255 | fprintf (stderr, "error: line width must be at least 0\n"); |
---|
1256 | problems = 1; |
---|
1257 | } |
---|
1258 | |
---|
1259 | nervousness = get_float_resource ("nervousness", "Float"); |
---|
1260 | if ((nervousness < 0) || (nervousness > 1)) |
---|
1261 | { |
---|
1262 | fprintf (stderr, "error: nervousness must be in the range 0..1\n"); |
---|
1263 | problems = 1; |
---|
1264 | } |
---|
1265 | |
---|
1266 | maxNerveRadius = get_float_resource ("maxNerveRadius", "Float"); |
---|
1267 | if ((maxNerveRadius < 0) || (maxNerveRadius > 1)) |
---|
1268 | { |
---|
1269 | fprintf (stderr, "error: maxNerveRadius must be in the range 0..1\n"); |
---|
1270 | problems = 1; |
---|
1271 | } |
---|
1272 | |
---|
1273 | eventChance = get_float_resource ("eventChance", "Float"); |
---|
1274 | if ((eventChance < 0) || (eventChance > 1)) |
---|
1275 | { |
---|
1276 | fprintf (stderr, "error: eventChance must be in the range 0..1\n"); |
---|
1277 | problems = 1; |
---|
1278 | } |
---|
1279 | |
---|
1280 | iterAmt = get_float_resource ("iterAmt", "Float"); |
---|
1281 | if ((iterAmt < 0) || (iterAmt > 1)) |
---|
1282 | { |
---|
1283 | fprintf (stderr, "error: iterAmt must be in the range 0..1\n"); |
---|
1284 | problems = 1; |
---|
1285 | } |
---|
1286 | |
---|
1287 | minScale = get_float_resource ("minScale", "Float"); |
---|
1288 | if ((minScale < 0) || (minScale > 10)) |
---|
1289 | { |
---|
1290 | fprintf (stderr, "error: minScale must be in the range 0..10\n"); |
---|
1291 | problems = 1; |
---|
1292 | } |
---|
1293 | |
---|
1294 | maxScale = get_float_resource ("maxScale", "Float"); |
---|
1295 | if ((maxScale < 0) || (maxScale > 10)) |
---|
1296 | { |
---|
1297 | fprintf (stderr, "error: maxScale must be in the range 0..10\n"); |
---|
1298 | problems = 1; |
---|
1299 | } |
---|
1300 | |
---|
1301 | if (maxScale < minScale) |
---|
1302 | { |
---|
1303 | fprintf (stderr, "error: maxScale must be >= minScale\n"); |
---|
1304 | problems = 1; |
---|
1305 | } |
---|
1306 | |
---|
1307 | minRadius = get_integer_resource ("minRadius", "Integer"); |
---|
1308 | if ((minRadius < 1) || (minRadius > 100)) |
---|
1309 | { |
---|
1310 | fprintf (stderr, "error: minRadius must be in the range 1..100\n"); |
---|
1311 | problems = 1; |
---|
1312 | } |
---|
1313 | |
---|
1314 | maxRadius = get_integer_resource ("maxRadius", "Integer"); |
---|
1315 | if ((maxRadius < 1) || (maxRadius > 100)) |
---|
1316 | { |
---|
1317 | fprintf (stderr, "error: maxRadius must be in the range 1..100\n"); |
---|
1318 | problems = 1; |
---|
1319 | } |
---|
1320 | |
---|
1321 | if (maxRadius < minRadius) |
---|
1322 | { |
---|
1323 | fprintf (stderr, "error: maxRadius must be >= minRadius\n"); |
---|
1324 | problems = 1; |
---|
1325 | } |
---|
1326 | |
---|
1327 | if (problems) |
---|
1328 | { |
---|
1329 | exit (1); |
---|
1330 | } |
---|
1331 | } |
---|
1332 | |
---|
1333 | /* main function */ |
---|
1334 | void screenhack (Display *dpy, Window win) |
---|
1335 | { |
---|
1336 | display = dpy; |
---|
1337 | window = win; |
---|
1338 | |
---|
1339 | initParams (); |
---|
1340 | setup (); |
---|
1341 | |
---|
1342 | /* make a valid set to erase at first */ |
---|
1343 | renderSegs (); |
---|
1344 | |
---|
1345 | for (;;) |
---|
1346 | { |
---|
1347 | oneIteration (); |
---|
1348 | XSync (dpy, False); |
---|
1349 | screenhack_handle_events (dpy); |
---|
1350 | usleep (delay); |
---|
1351 | } |
---|
1352 | } |
---|