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