1 /*
2 * Copyright (C) 2002 Terence M. Welsh
3 * Ported to Linux by Tugrul Galatali <tugrul@galatali.com>
4 *
5 * Flux is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Flux is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 // Flux screen saver
20
21 #include <math.h>
22 #include <stdio.h>
23 #include <GL/gl.h>
24 #include <GL/glu.h>
25
26 #include "driver.h"
27 #include "rgbhsl.h"
28 #include "rsRand.h"
29 #include "rsDefines.h"
30
31 const char *hack_name = "flux";
32
33 #define NUMCONSTS 8
34 #define LIGHTSIZE 64
35
36 #define DEFAULTS1 1
37 #define DEFAULTS2 2
38 #define DEFAULTS3 3
39 #define DEFAULTS4 4
40 #define DEFAULTS5 5
41 #define DEFAULTS6 6
42
43 class flux;
44 class particle;
45
46 // Global variables
47 unsigned int tex;
48 flux *fluxes;
49 float lumdiff;
50 int whichparticle;
51 float cosCameraAngle, sinCameraAngle;
52 unsigned char lightTexture[LIGHTSIZE][LIGHTSIZE];
53 float aspectRatio;
54 float orbitiness = 0.0f;
55 float prevOrbitiness = 0.0f;
56
57
58 // Parameters edited in the dialog box
59 int dFluxes;
60 int dParticles;
61 int dTrail;
62 int dGeometry;
63 int dSize;
64 int dComplexity;
65 int dRandomize;
66 int dExpansion;
67 int dRotation;
68 int dWind;
69 int dInstability;
70 int dBlur;
71 int dSmart;
72
73 // This class is poorly named. It's actually a whole trail of particles.
74 class particle {
75 public:
76 float **vertices;
77 int counter;
78 float offset[3];
79
80 particle ();
81 ~particle ();
82 float update (float *c);
83 };
84
particle()85 particle::particle ()
86 {
87 int i;
88
89 // Offsets are somewhat like default positions for the head of each
90 // particle trail. Offsets spread out the particle trails and keep
91 // them from all overlapping.
92 offset[0] = cos (PIx2 * float (whichparticle) / float (dParticles));
93 offset[1] = float (whichparticle) / float (dParticles) - 0.5f;
94 offset[2] = sin (PIx2 * float (whichparticle) / float (dParticles));
95
96 whichparticle++;
97
98 // Initialize memory and set initial positions out of view of the
99 // camera
100 vertices = new float *[dTrail];
101
102 for (i = 0; i < dTrail; i++) {
103 vertices[i] = new float[5]; // 0,1,2 = position, 3 = hue, 4 =
104
105 // saturation
106 vertices[i][0] = 0.0f;
107 vertices[i][1] = 3.0f;
108 vertices[i][2] = 0.0f;
109 vertices[i][3] = 0.0f;
110 vertices[i][4] = 0.0f;
111 }
112
113 counter = 0;
114 }
115
~particle()116 particle::~particle ()
117 {
118 for (int i = 0; i < dTrail; i++)
119 delete[]vertices[i];
120 delete[]vertices;
121 }
122
123 float
update(float * c)124 particle::update (float *c)
125 {
126 int i, p, growth;
127 float rgb[3];
128 float cx, cy, cz; // Containment variables
129 float luminosity;
130 static float expander = 1.0f + 0.0005f * float (dExpansion);
131 static float blower = 0.001f * float (dWind);
132 float depth = 0;
133
134 // Record old position
135 int oldc = counter;
136 float oldpos[3];
137
138 oldpos[0] = vertices[oldc][0];
139 oldpos[1] = vertices[oldc][1];
140 oldpos[2] = vertices[oldc][2];
141
142 counter++;
143 if (counter >= dTrail)
144 counter = 0;
145
146 // Here's the iterative math for calculating new vertex positions
147 // first calculate limiting terms which keep vertices from constantly
148 // flying off to infinity
149 cx = vertices[oldc][0] * (1.0f - 1.0f / (vertices[oldc][0] * vertices[oldc][0] + 1.0f));
150 cy = vertices[oldc][1] * (1.0f - 1.0f / (vertices[oldc][1] * vertices[oldc][1] + 1.0f));
151 cz = vertices[oldc][2] * (1.0f - 1.0f / (vertices[oldc][2] * vertices[oldc][2] + 1.0f));
152 // then calculate new positions
153 vertices[counter][0] = vertices[oldc][0] + c[6] * offset[0] - cx + c[2] * vertices[oldc][1]
154 + c[5] * vertices[oldc][2];
155 vertices[counter][1] = vertices[oldc][1] + c[6] * offset[1] - cy + c[1] * vertices[oldc][2]
156 + c[4] * vertices[oldc][0];
157 vertices[counter][2] = vertices[oldc][2] + c[6] * offset[2] - cz + c[0] * vertices[oldc][0]
158 + c[3] * vertices[oldc][1];
159
160 // calculate "orbitiness" of particles
161 const float xdiff(vertices[counter][0] - vertices[oldc][0]);
162 const float ydiff(vertices[counter][1] - vertices[oldc][1]);
163 const float zdiff(vertices[counter][2] - vertices[oldc][2]);
164 const float distsq(vertices[counter][0] * vertices[counter][0]
165 + vertices[counter][1] * vertices[counter][1]
166 + vertices[counter][2] * vertices[counter][2]);
167 const float oldDistsq(vertices[oldc][0] * vertices[oldc][0]
168 + vertices[oldc][1] * vertices[oldc][1]
169 + vertices[oldc][2] * vertices[oldc][2]);
170 orbitiness += (xdiff * xdiff + ydiff * ydiff + zdiff * zdiff)
171 / (2.0f - fabs(distsq - oldDistsq));
172
173 // Pick a hue
174 vertices[counter][3] = cx * cx + cy * cy + cz * cz;
175 if (vertices[counter][3] > 1.0f)
176 vertices[counter][3] = 1.0f;
177 vertices[counter][3] += c[7];
178 // Limit the hue (0 - 1)
179 if (vertices[counter][3] > 1.0f)
180 vertices[counter][3] -= 1.0f;
181 if (vertices[counter][3] < 0.0f)
182 vertices[counter][3] += 1.0f;
183 // Pick a saturation
184 vertices[counter][4] = c[0] + vertices[counter][3];
185 // Limit the saturation (0 - 1)
186 if (vertices[counter][4] < 0.0f)
187 vertices[counter][4] = -vertices[counter][4];
188 vertices[counter][4] -= float (int (vertices[counter][4]));
189
190 vertices[counter][4] = 1.0f - (vertices[counter][4] * vertices[counter][4]);
191
192 // Bring particles back if they escape
193 if (!counter) {
194 if ((vertices[0][0] > 10000.0f)
195 || (vertices[0][0] < -10000.0f)
196 || (vertices[0][1] > 10000.0f)
197 || (vertices[0][1] < -10000.0f)
198 || (vertices[2][2] > 10000.0f)
199 || (vertices[0][2] < -10000.0f)) {
200 vertices[0][0] = rsRandf (2.0f) - 1.0f;
201 vertices[0][1] = rsRandf (2.0f) - 1.0f;
202 vertices[0][2] = rsRandf (2.0f) - 1.0f;
203 }
204 }
205 // Draw every vertex in particle trail
206 p = counter;
207 growth = 0;
208 luminosity = lumdiff;
209 for (i = 0; i < dTrail; i++) {
210 p++;
211 if (p >= dTrail)
212 p = 0;
213 growth++;
214
215 // assign color to particle
216 hsl2rgb (vertices[p][3], vertices[p][4], luminosity, rgb[0], rgb[1], rgb[2]);
217 glColor3fv (rgb);
218
219 glPushMatrix ();
220 if (dGeometry == 1) // Spheres
221 glTranslatef (vertices[p][0], vertices[p][1], vertices[p][2]);
222 else { // Points or lights
223 depth = cosCameraAngle * vertices[p][2] - sinCameraAngle * vertices[p][0];
224 glTranslatef (cosCameraAngle * vertices[p][0] + sinCameraAngle * vertices[p][2], vertices[p][1], depth);
225 }
226 if (dGeometry) { // Spheres or lights
227 switch (dTrail - growth) {
228 case 0:
229 glScalef (0.259f, 0.259f, 0.259f);
230 break;
231 case 1:
232 glScalef (0.5f, 0.5f, 0.5f);
233 break;
234 case 2:
235 glScalef (0.707f, 0.707f, 0.707f);
236 break;
237 case 3:
238 glScalef (0.866f, 0.866f, 0.866f);
239 break;
240 case 4:
241 glScalef (0.966f, 0.966f, 0.966f);
242 }
243 }
244 switch (dGeometry) {
245 case 0: // Points
246 switch (dTrail - growth) {
247 case 0:
248 glPointSize (float
249 (dSize * (depth + 200.0f) * 0.001036f));
250
251 break;
252 case 1:
253 glPointSize (float
254 (dSize * (depth + 200.0f) * 0.002f));
255
256 break;
257 case 2:
258 glPointSize (float
259 (dSize * (depth + 200.0f) * 0.002828f));
260
261 break;
262 case 3:
263 glPointSize (float
264 (dSize * (depth + 200.0f) * 0.003464f));
265
266 break;
267 case 4:
268 glPointSize (float
269 (dSize * (depth + 200.0f) * 0.003864f));
270
271 break;
272 default:
273 glPointSize (float
274 (dSize * (depth + 200.0f) * 0.004f));
275 }
276 glBegin (GL_POINTS);
277 glVertex3f (0.0f, 0.0f, 0.0f);
278 glEnd ();
279 break;
280 case 1: // Spheres
281 case 2: // Lights
282 glCallList (1);
283 }
284 glPopMatrix ();
285 vertices[p][0] *= expander;
286 vertices[p][1] *= expander;
287 vertices[p][2] *= expander;
288 vertices[p][2] += blower;
289 luminosity += lumdiff;
290 }
291
292 // Find distance between new position and old position and return it
293 oldpos[0] -= vertices[counter][0];
294 oldpos[1] -= vertices[counter][1];
295 oldpos[2] -= vertices[counter][2];
296 return (float (sqrt (oldpos[0] * oldpos[0] + oldpos[1] * oldpos[1] + oldpos[2] * oldpos[2])));
297 }
298
299 // This class is a set of particle trails and constants that enter
300 // into their equations of motion.
301 class flux {
302 public:
303 particle * particles;
304 int randomize;
305 float c[NUMCONSTS]; // constants
306 float cv[NUMCONSTS]; // constants' change velocities
307 int currentSmartConstant;
308 float oldDistance;
309
310 flux ();
311 ~flux ();
312 void update ();
313 };
314
flux()315 flux::flux ()
316 {
317 int i;
318
319 whichparticle = 0;
320
321 particles = new particle[dParticles];
322 randomize = 1;
323 for (i = 0; i < NUMCONSTS; i++) {
324 c[i] = rsRandf (2.0f) - 1.0f;
325 cv[i] = rsRandf (0.000005f * float (dInstability) * float (dInstability))
326 + 0.000001f * float (dInstability) * float (dInstability);
327 }
328
329 currentSmartConstant = 0;
330 oldDistance = 0.0f;
331 }
332
~flux()333 flux::~flux ()
334 {
335 delete[]particles;
336 }
337
338 void
update()339 flux::update ()
340 {
341 int i;
342
343 // randomize constants
344 if (dRandomize) {
345 randomize--;
346 if (randomize <= 0) {
347 for (i = 0; i < NUMCONSTS; i++)
348 c[i] = rsRandf (2.0f) - 1.0f;
349 int temp = 101 - dRandomize;
350
351 temp = temp * temp;
352 randomize = temp + rsRandi (temp);
353 }
354 }
355 // update constants
356 for (i = 0; i < NUMCONSTS; i++) {
357 c[i] += cv[i];
358 if (c[i] >= 1.0f) {
359 c[i] = 1.0f;
360 cv[i] = -cv[i];
361 }
362 if (c[i] <= -1.0f) {
363 c[i] = -1.0f;
364 cv[i] = -cv[i];
365 }
366 }
367
368 prevOrbitiness = orbitiness;
369 orbitiness = 0.0f;
370
371 // update all particles in this flux field
372 float dist;
373
374 for (i = 0; i < dParticles; i++)
375 dist = particles[i].update (c);
376
377 // use dist from last particle to activate smart constants
378 dSmart = 0;
379 if (dSmart) {
380 const float upper = 0.4f;
381 const float lower = 0.2f;
382 int beSmart = 0;
383
384 if (dist > upper && dist > oldDistance)
385 beSmart = 1;
386 if (dist < lower && dist < oldDistance)
387 beSmart = 1;
388 if (beSmart) {
389 cv[currentSmartConstant] = -cv[currentSmartConstant];
390 currentSmartConstant++;
391 if (currentSmartConstant >= dSmart)
392 currentSmartConstant = 0;
393 }
394 oldDistance = dist;
395 }
396
397 if (orbitiness < prevOrbitiness) {
398 i = rsRandi(NUMCONSTS - 1);
399 cv[i] = -cv[i];
400 }
401 }
402
hack_draw(xstuff_t * XStuff,double currentTime,float frameTime)403 void hack_draw (xstuff_t * XStuff, double currentTime, float frameTime)
404 {
405
406 int i;
407 static float cameraAngle = 0.0f;
408
409 // clear the screen
410 glLoadIdentity ();
411 if (dBlur) { // partially
412 glMatrixMode(GL_PROJECTION);
413 glPushMatrix();
414 glLoadIdentity();
415 glOrtho(0.0, 1.0, 0.0, 1.0, 1.0, -1.0);
416 glMatrixMode(GL_MODELVIEW);
417 glPushMatrix();
418 glLoadIdentity();
419 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
420 glEnable(GL_BLEND);
421 glDisable(GL_DEPTH_TEST);
422 glColor4f(0.0f, 0.0f, 0.0f, 0.5f - (float(sqrtf(sqrtf(float(dBlur)))) * 0.15495f));
423 glBegin(GL_TRIANGLE_STRIP);
424 glVertex3f(0.0f, 0.0f, 0.0f);
425 glVertex3f(1.0f, 0.0f, 0.0f);
426 glVertex3f(0.0f, 1.0f, 0.0f);
427 glVertex3f(1.0f, 1.0f, 0.0f);
428 glEnd();
429 glPopMatrix();
430 glMatrixMode(GL_PROJECTION);
431 glPopMatrix();
432 } else // completely
433 glClear (GL_COLOR_BUFFER_BIT);
434
435 cameraAngle += 0.01f * float (dRotation);
436
437 if (cameraAngle >= 360.0f)
438 cameraAngle -= 360.0f;
439 if (dGeometry == 1) // Only rotate for spheres
440 glRotatef (cameraAngle, 0.0f, 1.0f, 0.0f);
441 else {
442 cosCameraAngle = cos (cameraAngle * DEG2RAD);
443 sinCameraAngle = sin (cameraAngle * DEG2RAD);
444 }
445
446 // set up state for rendering particles
447 switch (dGeometry) {
448 case 0: // Blending for points
449 glBlendFunc (GL_SRC_ALPHA, GL_ONE);
450 glEnable (GL_BLEND);
451 glEnable (GL_POINT_SMOOTH);
452 glHint (GL_POINT_SMOOTH_HINT, GL_NICEST);
453 break;
454 case 1: // No blending for spheres, but we need
455 // z-buffering
456 glDisable (GL_BLEND);
457 glEnable (GL_DEPTH_TEST);
458 glClear (GL_DEPTH_BUFFER_BIT);
459 break;
460 case 2: // Blending for lights
461 glBlendFunc (GL_ONE, GL_ONE);
462 glEnable (GL_BLEND);
463 glBindTexture(GL_TEXTURE_2D, tex);
464 glEnable(GL_TEXTURE_2D);
465 }
466
467 // Update particles
468 glMatrixMode(GL_MODELVIEW);
469 for (i = 0; i < dFluxes; i++)
470 fluxes[i].update ();
471
472 glFlush ();
473 }
474
hack_reshape(xstuff_t * XStuff)475 void hack_reshape (xstuff_t * XStuff)
476 {
477 int i, j;
478 float x, y, temp;
479
480 glViewport (0, 0, XStuff->windowWidth, XStuff->windowHeight);
481
482 glMatrixMode (GL_PROJECTION);
483 glLoadIdentity ();
484
485 aspectRatio = float (XStuff->windowWidth) / float (XStuff->windowHeight);
486 gluPerspective (100.0, aspectRatio, 0.01, 200);
487
488 glMatrixMode (GL_MODELVIEW);
489 glLoadIdentity ();
490
491 glTranslatef (0.0, 0.0, -2.5);
492
493 if (dGeometry == 0) {
494 glEnable (GL_POINT_SMOOTH);
495 // glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
496 }
497
498 glFrontFace (GL_CCW);
499 glEnable (GL_CULL_FACE);
500 glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
501 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
502
503 if (dGeometry == 1) { // Spheres and their lighting
504 glNewList (1, GL_COMPILE);
505 GLUquadricObj *qobj = gluNewQuadric ();
506 gluSphere (qobj, 0.005f * float (dSize), dComplexity + 2, dComplexity + 1);
507
508 gluDeleteQuadric (qobj);
509 glEndList ();
510
511 glEnable (GL_LIGHTING);
512 glEnable (GL_LIGHT0);
513 float ambient[4] = {
514 0.0f,
515 0.0f,
516 0.0f,
517 0.0f
518 };
519 float diffuse[4] = {
520 1.0f,
521 1.0f,
522 1.0f,
523 0.0f
524 };
525 float specular[4] = {
526 1.0f,
527 1.0f,
528 1.0f,
529 0.0f
530 };
531 float position[4] = {
532 500.0f,
533 500.0f,
534 500.0f,
535 0.0f
536 };
537
538 glLightfv (GL_LIGHT0, GL_AMBIENT, ambient);
539 glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse);
540 glLightfv (GL_LIGHT0, GL_SPECULAR, specular);
541 glLightfv (GL_LIGHT0, GL_POSITION, position);
542 glEnable (GL_COLOR_MATERIAL);
543 glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
544 } else if (dGeometry == 2) { // Init lights
545 for (i = 0; i < LIGHTSIZE; i++) {
546 for (j = 0; j < LIGHTSIZE; j++) {
547 x = float (i - LIGHTSIZE / 2) / float (LIGHTSIZE / 2);
548 y = float (j - LIGHTSIZE / 2) / float (LIGHTSIZE / 2);
549 temp = 1.0f - float (sqrt ((x * x) + (y * y)));
550
551 if (temp > 1.0f)
552 temp = 1.0f;
553 if (temp < 0.0f)
554 temp = 0.0f;
555 lightTexture[i][j] = char (255.0f * temp * temp);
556 }
557 }
558 glGenTextures(1, &tex);
559 glBindTexture(GL_TEXTURE_2D, tex);
560 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
561 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
562 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
563 glTexImage2D (GL_TEXTURE_2D, 0, 1, LIGHTSIZE, LIGHTSIZE, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, lightTexture);
564
565 temp = float (dSize) * 0.005f;
566
567 glNewList (1, GL_COMPILE);
568 glBegin (GL_TRIANGLES);
569 glTexCoord2f (0.0f, 0.0f);
570 glVertex3f (-temp, -temp, 0.0f);
571 glTexCoord2f (1.0f, 0.0f);
572 glVertex3f (temp, -temp, 0.0f);
573 glTexCoord2f (1.0f, 1.0f);
574 glVertex3f (temp, temp, 0.0f);
575 glTexCoord2f (0.0f, 0.0f);
576 glVertex3f (-temp, -temp, 0.0f);
577 glTexCoord2f (1.0f, 1.0f);
578 glVertex3f (temp, temp, 0.0f);
579 glTexCoord2f (0.0f, 1.0f);
580 glVertex3f (-temp, temp, 0.0f);
581 glEnd ();
582 glEndList ();
583 }
584 // Initialize luminosity difference
585 lumdiff = 1.0f / float (dTrail);
586 }
587
hack_init(xstuff_t * XStuff)588 void hack_init (xstuff_t * XStuff)
589 {
590 hack_reshape (XStuff);
591
592 // Initialize flux fields
593 fluxes = new flux[dFluxes];
594 }
595
hack_cleanup(xstuff_t * XStuff)596 void hack_cleanup (xstuff_t * XStuff)
597 {
598 if ((dGeometry == 1) || (dGeometry == 2)) {
599 glDeleteLists (1, 1);
600 }
601 }
602
setDefaults(int which)603 void setDefaults (int which)
604 {
605 switch (which) {
606 case DEFAULTS1: // Regular
607 dFluxes = 1;
608 dParticles = 20;
609 dTrail = 40;
610 dGeometry = 2;
611 dSize = 15;
612 dComplexity = 3;
613 dRandomize = 0;
614 dExpansion = 40;
615 dRotation = 30;
616 dWind = 20;
617 dInstability = 20;
618 dBlur = 0;
619 break;
620 case DEFAULTS2: // Hypnotic
621 dFluxes = 2;
622 dParticles = 10;
623 dTrail = 40;
624 dGeometry = 2;
625 dSize = 15;
626 dComplexity = 3;
627 dRandomize = 80;
628 dExpansion = 20;
629 dRotation = 0;
630 dWind = 40;
631 dInstability = 10;
632 dBlur = 30;
633 break;
634 case DEFAULTS3: // Insane
635 dFluxes = 4;
636 dParticles = 30;
637 dTrail = 8;
638 dGeometry = 2;
639 dSize = 25;
640 dComplexity = 3;
641 dRandomize = 0;
642 dExpansion = 80;
643 dRotation = 60;
644 dWind = 40;
645 dInstability = 100;
646 dBlur = 10;
647 break;
648 case DEFAULTS4: // Sparklers
649 dFluxes = 3;
650 dParticles = 20;
651 dTrail = 6;
652 dGeometry = 1;
653 dSize = 20;
654 dComplexity = 3;
655 dRandomize = 85;
656 dExpansion = 60;
657 dRotation = 30;
658 dWind = 20;
659 dInstability = 30;
660 dBlur = 0;
661 break;
662 case DEFAULTS5: // Paradigm
663 dFluxes = 1;
664 dParticles = 40;
665 dTrail = 40;
666 dGeometry = 2;
667 dSize = 5;
668 dComplexity = 3;
669 dRandomize = 90;
670 dExpansion = 30;
671 dRotation = 20;
672 dWind = 10;
673 dInstability = 5;
674 dBlur = 10;
675 break;
676 case DEFAULTS6: // Galactic
677 dFluxes = 1;
678 dParticles = 2;
679 dTrail = 1500;
680 dGeometry = 2;
681 dSize = 10;
682 dComplexity = 3;
683 dRandomize = 0;
684 dExpansion = 5;
685 dRotation = 25;
686 dWind = 0;
687 dInstability = 5;
688 dBlur = 0;
689 }
690 }
691
hack_handle_opts(int argc,char ** argv)692 void hack_handle_opts (int argc, char **argv)
693 {
694 int change_flag = 0;
695
696 setDefaults (DEFAULTS1);
697
698 while (1) {
699 int c;
700
701 #ifdef HAVE_GETOPT_H
702 static struct option long_options[] = {
703 {"help", 0, 0, 'h'},
704 DRIVER_OPTIONS_LONG
705 {"fluxes", 1, 0, 'f'},
706 {"particles", 1, 0, 'p'},
707 {"trail", 1, 0, 't'},
708 {"geometry", 1, 0, 'g'},
709 {"points", 0, 0, 20},
710 {"spheres", 0, 0, 21},
711 {"lights", 0, 0, 22},
712 {"size", 1, 0, 's'},
713 {"complexity", 1, 0, 'c'},
714 {"randomize", 1, 0, 'R'},
715 {"expansion", 1, 0, 'e'},
716 {"rotation", 1, 0, 'o'},
717 {"wind", 1, 0, 'w'},
718 {"instability", 1, 0, 'i'},
719 {"blur", 1, 0, 'b'},
720 {"preset", 1, 0, 'P'},
721 {"regular", 0, 0, 10},
722 {"hypnotic", 0, 0, 11},
723 {"insane", 0, 0, 12},
724 {"sparklers", 0, 0, 13},
725 {"paradigm", 0, 0, 14},
726 {"fusion", 0, 0, 15},
727 {0, 0, 0, 0}
728 };
729
730 c = getopt_long (argc, argv, DRIVER_OPTIONS_SHORT "hf:p:t:g:s:c:R:e:o:w:i:b:P:", long_options, NULL);
731 #else
732 c = getopt (argc, argv, DRIVER_OPTIONS_SHORT "hf:p:t:g:s:c:R:e:o:w:i:b:P:");
733 #endif
734 if (c == -1)
735 break;
736
737 switch (c) {
738 DRIVER_OPTIONS_CASES
739 case 'h':
740 printf ("%s:"
741 #ifndef HAVE_GETOPT_H
742 " Not built with GNU getopt.h, long options *NOT* enabled."
743 #endif
744 "\n" DRIVER_OPTIONS_HELP
745 "\t--preset <arg>\n" "\t--regular\n" "\t--hypnotic\n" "\t--insane\n" "\t--sparklers\n" "\t--paradigm\n" "\t--fusion\n"
746 "\t--fluxes <arg>\n" "\t--particles <arg>\n" "\t--trail <arg>\n"
747 "\t--geometry <arg>\n" "\t--points\n" "\t--spheres\n" "\t--lights\n"
748 "\t--size <arg>\n" "\t--complexity <arg>\n" "\t--randomize <arg>\n" "\t--expansion <arg>\n"
749 "\t--rotation <arg>\n" "\t--wind <arg>\n" "\t--instability <arg>\n" "\t--blur <arg>\n", argv[0]);
750 exit (1);
751 case 'f':
752 change_flag = 1;
753 dFluxes = strtol_minmaxdef (optarg, 10, 1, 100, 1, 1, "--fluxes: ");
754 break;
755 case 'p':
756 change_flag = 1;
757 dParticles = strtol_minmaxdef (optarg, 10, 1, 1000, 1, 1, "--particles: ");
758 break;
759 case 't':
760 change_flag = 1;
761 dTrail = strtol_minmaxdef (optarg, 10, 3, 10000, 1, 40, "--trail: ");
762 break;
763 case 'g':
764 change_flag = 1;
765 dGeometry = strtol_minmaxdef (optarg, 10, 0, 2, 0, 0, "--geometry: ");
766 break;
767 case 20:
768 case 21:
769 case 22:
770 change_flag = 1;
771 dGeometry = c - 20;
772 break;
773 case 's':
774 change_flag = 1;
775 dSize = strtol_minmaxdef (optarg, 10, 1, 100, 1, 15, "--size: ");
776 break;
777 case 'c':
778 change_flag = 1;
779 dComplexity = strtol_minmaxdef (optarg, 10, 0, 100, 1, 3, "--complexity: ");
780 break;
781 case 'R':
782 change_flag = 1;
783 dRandomize = strtol_minmaxdef (optarg, 10, 0, 100, 1, 0, "--randomize: ");
784 break;
785 case 'e':
786 change_flag = 1;
787 dExpansion = strtol_minmaxdef (optarg, 10, 0, 100, 1, 40, "--expansion: ");
788 break;
789 case 'o':
790 change_flag = 1;
791 dRotation = strtol_minmaxdef (optarg, 10, 0, 100, 1, 30, "--rotation: ");
792 break;
793 case 'w':
794 change_flag = 1;
795 dWind = strtol_minmaxdef (optarg, 10, 0, 100, 1, 20, "--wind: ");
796 break;
797 case 'i':
798 change_flag = 1;
799 dInstability = strtol_minmaxdef (optarg, 10, 0, 100, 1, 20, "--instability: ");
800 break;
801 case 'b':
802 change_flag = 1;
803 dBlur = strtol_minmaxdef (optarg, 10, 0, 100, 1, 0, "--blur: ");
804 break;
805 case 'P':
806 change_flag = 1;
807 setDefaults (strtol_minmaxdef (optarg, 10, 1, 6, 0, 1, "--preset: "));
808 break;
809 case 10:
810 case 11:
811 case 12:
812 case 13:
813 case 14:
814 case 15:
815 change_flag = 1;
816 setDefaults(c - 9);
817 break;
818 }
819 }
820
821 if (!change_flag) {
822 setDefaults (rsRandi (6) + 1);
823 }
824 }
825