1 /*
2 * Copyright (C) 2002 Terence M. Welsh
3 * Ported to Linux by Tugrul Galatali <tugrul@galatali.com>
4 *
5 * Skyrocket 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 * Skyrocket 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 // Skyrocket screen saver
20
21 #include <math.h>
22 #include <stdio.h>
23 #include <GL/gl.h>
24 #include <GL/glu.h>
25
26 #include <list>
27
28 #include "driver.h"
29 #include "rsDefines.h"
30 #include "rsRand.h"
31 #include "rsMath/rsVec.h"
32 #include "skyrocket_flare.h"
33 #include "skyrocket_particle.h"
34 #include "skyrocket_smoke.h"
35 #include "skyrocket_sound.h"
36 #include "skyrocket_shockwave.h"
37 #include "skyrocket_world.h"
38
39 const char *hack_name = "skyrocket";
40
41 double modelMat[16], projMat[16];
42 int viewport[4];
43 extern double billboardMat[16];
44
45 // Global variables
46 int readyToDraw = 0;
47
48 // list of particles
49 std::list < particle > particles;
50 // Time from one frame to the next
51 float elapsedTime = 0.0f;
52
53 // Window variables
54 int xsize, ysize, centerx, centery;
55 float aspectRatio;
56
57 // Camera variables
58 rsVec lookFrom[3]; // 3 = position, target position, last position
59 rsVec lookAt[3] // 3 = position, target position, last position
60 = { rsVec (0.0f, 1200.0f, 0.0f),
61 rsVec (0.0f, 1200.0f, 0.0f),
62 rsVec (0.0f, 1200.0f, 0.0f)
63 };
64 rsVec cameraPos; // used for positioning sounds (same as lookFrom[0])
65 rsVec cameraVel; // used for doppler shift
66
67 // Mouse variables
68 float mouseIdleTime;
69 int mouseButtons, mousex, mousey;
70 float mouseSpeed;
71
72 int numRockets = 0;
73
74 #define MAXFLARES 110 // Required 100 and 10 extra for good measure
75 float allflares[MAXFLARES][7]; // type, x, y, r, g, b, alpha
76 int numFlares = 0;
77
78 // Parameters edited in the dialog box
79 int dMaxrockets;
80 int dSmoke;
81 int dExplosionsmoke;
82 int dWind;
83 int dAmbient;
84 int dStardensity;
85 int dFlare;
86 int dMoonglow;
87 int dMoon;
88 int dClouds;
89 int dEarth;
90 int dIllumination;
91 int dSound;
92 int dPriority;
93
94 // Commands given from keyboard
95 int kAction = 1;
96 int kCamera = 1; // 0 = paused, 1 = autonomous, 2 = mouse control
97 int kNewCamera = 0;
98 int kSlowMotion = 0;
99 int userDefinedExplosion = -1;
100
addParticle()101 particle *addParticle ()
102 {
103 static particle *tempPart;
104
105 particles.push_back (particle ());
106 tempPart = &(particles.back ());
107 tempPart->depth = 10000;
108
109 return tempPart;
110 }
111
112 // Makes list of lens flares. Must be a called even when action is paused
113 // because camera might still be moving.
makeFlareList()114 void makeFlareList ()
115 {
116 rsVec cameraDir, partDir;
117
118 cameraDir = lookAt[0] - lookFrom[0];
119 cameraDir.normalize ();
120 std::list < particle >::iterator curlight = particles.begin ();
121 while (curlight != particles.end () && numFlares < MAXFLARES) {
122 if (curlight->type == EXPLOSION) {
123 double winx, winy, winz;
124
125 gluProject (curlight->xyz[0], curlight->xyz[1], curlight->xyz[2], modelMat, projMat, viewport, &winx, &winy, &winz);
126 partDir = curlight->xyz - cameraPos;
127 if (partDir.dot (cameraDir) > 1.0f) { // is light source in front of camera?
128 allflares[numFlares][0] = 0;
129 allflares[numFlares][1] = (float (winx) / float (xsize))*aspectRatio;
130 allflares[numFlares][2] = float (winy) / float (ysize);
131
132 allflares[numFlares][3] = curlight->rgb[0];
133 allflares[numFlares][4] = curlight->rgb[1];
134 allflares[numFlares][5] = curlight->rgb[2];
135 rsVec vector = curlight->xyz - cameraPos; // find distance attenuation factor
136 float distatten = (10000.0f - vector.length ()) * 0.0001f;
137
138 if (distatten < 0.0f)
139 distatten = 0.0f;
140 allflares[numFlares][6] = curlight->bright * float (dFlare) * 0.01f * distatten;
141
142 numFlares++;
143 }
144 }
145 if (curlight->type == SUCKER || curlight->type == SHOCKWAVE || curlight->type == STRETCHER || curlight->type == BIGMAMA) {
146 double winx, winy, winz;
147 float temp;
148
149 gluProject (curlight->xyz[0], curlight->xyz[1], curlight->xyz[2], modelMat, projMat, viewport, &winx, &winy, &winz);
150 partDir = curlight->xyz - cameraPos;
151 if (partDir.dot (cameraDir) > 1.0f) { // is light source in front of camera?
152 allflares[numFlares][0] = 1; // superFlare
153 allflares[numFlares][1] = (float (winx) / float (xsize))*aspectRatio;
154 allflares[numFlares][2] = float (winy) / float (ysize);
155
156 allflares[numFlares][3] = curlight->rgb[0];
157 allflares[numFlares][4] = curlight->rgb[1];
158 allflares[numFlares][5] = curlight->rgb[2];
159 rsVec vector = curlight->xyz - cameraPos; // find distance attenuation factor
160 float distatten = (20000.0f - vector.length ()) * 0.00005f;
161
162 if (distatten < 0.0f)
163 distatten = 0.0f;
164 temp = 1.0f - (curlight->bright - 0.5f) * float (dFlare) * 0.02f;
165
166 allflares[numFlares][6] = (1.0f - temp * temp * temp * temp) * distatten;
167 numFlares++;
168 }
169 }
170 curlight++;
171 }
172 }
173
draw()174 void draw ()
175 {
176 int i, j;
177 static int lastCameraMode = kCamera;
178 // time, elapsed time, step (1.0 - 0.0)
179 static float cameraTime[3] = { 20.0f, 0.0f, 0.0f };
180
181 // super fast easter egg
182 if (!rsRandi (2000))
183 elapsedTime *= 5.0f;
184
185 // build viewing matrix
186 glMatrixMode (GL_PROJECTION);
187 glLoadIdentity ();
188 gluPerspective (60.0f, aspectRatio, 1.0f, 40000.0f);
189 glGetDoublev (GL_PROJECTION_MATRIX, projMat);
190
191 if (kNewCamera) { // Make new random camera view
192 cameraTime[0] = rsRandf (25.0f) + 5.0f;
193 cameraTime[1] = 0.0f;
194 cameraTime[2] = 0.0f;
195 // choose new positions
196 lookFrom[1][0] = rsRandf (6000.0f) - 3000.0f; // new target position
197 lookFrom[1][1] = rsRandf (1700.0f) + 5.0f;
198 lookFrom[1][2] = rsRandf (6000.0f) - 3000.0f;
199 lookAt[1][0] = rsRandf (1000.0f) - 500.0f; // new target position
200 lookAt[1][1] = rsRandf (1100.0f) + 200.0f;
201 lookAt[1][2] = rsRandf (1000.0f) - 500.0f;
202 // cut to a new view
203 lookFrom[2][0] = rsRandf (6000.0f) - 3000.0f; // new last position
204 lookFrom[2][1] = rsRandf (1700.0f) + 5.0f;
205 lookFrom[2][2] = rsRandf (6000.0f) - 3000.0f;
206 lookAt[2][0] = rsRandf (1000.0f) - 500.0f; // new last position
207 lookAt[2][1] = rsRandf (1100.0f) + 200.0f;
208 lookAt[2][2] = rsRandf (1000.0f) - 500.0f;
209 kNewCamera = 0;
210 }
211
212 if (kCamera == 1) { // if the camera is active
213 if (lastCameraMode == 2) { // camera was controlled by mouse last frame
214 cameraTime[0] = 10.0f;
215 cameraTime[1] = 0.0f;
216 cameraTime[2] = 0.0f;
217 lookFrom[2] = lookFrom[0];
218 lookFrom[1][0] = rsRandf (6000.0f) - 3000.0f; // new target position
219 lookFrom[1][1] = rsRandf (1700.0f) + 5.0f;
220 lookFrom[1][2] = rsRandf (6000.0f) - 3000.0f;
221 lookAt[2] = lookAt[0];
222 lookAt[1][0] = rsRandf (1000.0f) - 500.0f; // new target position
223 lookAt[1][1] = rsRandf (1100.0f) + 200.0f;
224 lookAt[1][2] = rsRandf (1000.0f) - 500.0f;
225 }
226
227 cameraTime[1] += elapsedTime;
228 cameraTime[2] = cameraTime[1] / cameraTime[0];
229 if (cameraTime[2] >= 1.0f) { // reset camera sequence
230 // reset timer
231 cameraTime[0] = rsRandf (25.0f) + 5.0f;
232 cameraTime[1] = 0.0f;
233 cameraTime[2] = 0.0f;
234 // choose new positions
235 lookFrom[2] = lookFrom[1]; // last = target
236 lookFrom[1][0] = rsRandf (6000.0f) - 3000.0f; // new target position
237 lookFrom[1][1] = rsRandf (1700.0f) + 5.0f;
238 lookFrom[1][2] = rsRandf (6000.0f) - 3000.0f;
239 lookAt[2] = lookAt[1]; // last = target
240 lookAt[1][0] = rsRandf (1000.0f) - 500.0f; // new target position
241 lookAt[1][1] = rsRandf (1100.0f) + 200.0f;
242 lookAt[1][2] = rsRandf (1000.0f) - 500.0f;
243 if (!rsRandi (3)) { // cut to a new view
244 lookFrom[2][0] = rsRandf (6000.0f) - 3000.0f; // new last position
245 lookFrom[2][1] = rsRandf (1700.0f) + 5.0f;
246 lookFrom[2][2] = rsRandf (6000.0f) - 3000.0f;
247 lookAt[2][0] = rsRandf (1000.0f) - 500.0f; // new last position
248 lookAt[2][1] = rsRandf (1100.0f) + 200.0f;
249 lookAt[2][2] = rsRandf (1000.0f) - 500.0f;
250 }
251 }
252
253 // change camera position and angle
254 float cameraStep = 0.5f * (1.0f - cos (cameraTime[2] * PI));
255
256 lookFrom[0] = lookFrom[2] + ((lookFrom[1] - lookFrom[2]) * cameraStep);
257 lookAt[0] = lookAt[2] + ((lookAt[1] - lookAt[2]) * cameraStep);
258 // update variables used for sound and lens flares
259 cameraVel = lookFrom[0] - cameraPos;
260 cameraPos = lookFrom[0];
261 }
262
263 // Build modelview matrix
264 // Don't use gluLookAt() because it's easier to find the billboard matrix
265 // if we know the heading and pitch
266 glMatrixMode (GL_MODELVIEW);
267 glLoadIdentity ();
268 static float heading, pitch;
269
270 // Control camera with the mouse
271 if (kCamera == 2) {
272 heading += 100.0f * elapsedTime * aspectRatio * float (centerx - mousex) / float (xsize);
273 pitch += 100.0f * elapsedTime * float (centery - mousey) / float (ysize);
274
275 if (heading > 180.0f)
276 heading -= 360.0f;
277 if (heading < -180.0f)
278 heading += 360.0f;
279 if (pitch > 90.0f)
280 pitch = 90.0f;
281 if (pitch < -90.0f)
282 pitch = -90.0f;
283 /*
284 if(mouseButtons & MK_LBUTTON)
285 mouseSpeed += 400.0f * elapsedTime;
286 if(mouseButtons & MK_RBUTTON)
287 mouseSpeed -= 400.0f * elapsedTime;
288 if((mouseButtons & MK_MBUTTON) || ((mouseButtons & MK_LBUTTON) && (mouseButtons & MK_RBUTTON)))
289 mouseSpeed = 0.0f;
290 if(mouseSpeed > 4000.0f)
291 mouseSpeed = 4000.0f;
292 if(mouseSpeed < -4000.0f)
293 mouseSpeed = -4000.0f;
294 */
295 float ch = cos (DEG2RAD * heading);
296 float sh = sin (DEG2RAD * heading);
297 float cp = cos (DEG2RAD * pitch);
298 float sp = sin (DEG2RAD * pitch);
299
300 lookFrom[0][0] -= mouseSpeed * sh * cp * elapsedTime;
301 lookFrom[0][1] += mouseSpeed * sp * elapsedTime;
302 lookFrom[0][2] -= mouseSpeed * ch * cp * elapsedTime;
303 cameraPos = lookFrom[0];
304 // Calculate new lookAt position so that lens flares will be computed correctly
305 // and so that transition back to autonomous camera mode is smooth
306 lookAt[0][0] = lookFrom[0][0] - 500.0f * sh * cp;
307 lookAt[0][1] = lookFrom[0][1] + 500.0f * sp;
308 lookAt[0][2] = lookFrom[0][2] - 500.0f * ch * cp;
309 } else {
310 float radius = sqrt ((lookAt[0][0] - lookFrom[0][0]) * (lookAt[0][0] - lookFrom[0][0])
311 + (lookAt[0][2] - lookFrom[0][2]) * (lookAt[0][2] - lookFrom[0][2]));
312
313 pitch = RAD2DEG * atan2 (lookAt[0][1] - lookFrom[0][1], radius);
314 heading = RAD2DEG * atan2 (lookFrom[0][0] - lookAt[0][0], lookFrom[0][2] - lookAt[0][2]);
315 }
316
317 glRotatef (-pitch, 1, 0, 0);
318 glRotatef (-heading, 0, 1, 0);
319 glTranslatef (-lookFrom[0][0], -lookFrom[0][1], -lookFrom[0][2]);
320 // get modelview matrix for flares
321 glGetDoublev (GL_MODELVIEW_MATRIX, modelMat);
322
323 // store this frame's camera mode for next frame
324 lastCameraMode = kCamera;
325
326 // Update mouse idle time
327 if (kCamera == 2) {
328 mouseIdleTime += elapsedTime;
329 if (mouseIdleTime > 300.0f) // return to autonomous camera mode after 5 minutes
330 kCamera = 1;
331 }
332
333 // update billboard rotation matrix for particles
334 glPushMatrix ();
335 glLoadIdentity ();
336 glRotatef (heading, 0, 1, 0);
337 glRotatef (pitch, 1, 0, 0);
338 glGetDoublev (GL_MODELVIEW_MATRIX, billboardMat);
339 glPopMatrix ();
340
341 // clear the screen
342 glClear (GL_COLOR_BUFFER_BIT);
343
344 // Slows fireworks, but not camera
345 if (kSlowMotion)
346 elapsedTime *= 0.5f;
347
348 // Pause the animation?
349 if (kAction) {
350 // update world
351 updateWorld ();
352
353 // darken smoke
354 std::list < particle >::iterator darkener = particles.begin ();
355 static float ambientlight = float (dAmbient) * 0.01f;
356
357 while (darkener != particles.end ()) {
358 if (darkener->type == SMOKE)
359 darkener->rgb[0] = darkener->rgb[1] = darkener->rgb[2] = ambientlight;
360 darkener++;
361 }
362
363 // Change rocket firing rate
364 static float rocketTimer = 0.0f;
365 static float rocketTimeConst = 10.0f / float (dMaxrockets);
366 static float changeRocketTimeConst = 20.0f;
367
368 changeRocketTimeConst -= elapsedTime;
369 if (changeRocketTimeConst <= 0.0f) {
370 float temp = rsRandf (4.0f);
371
372 rocketTimeConst = (temp * temp) + (10.0f / float (dMaxrockets));
373 changeRocketTimeConst = rsRandf (30.0f) + 10.0f;
374 }
375
376 // add new rocket to list
377 rocketTimer -= elapsedTime;
378 if ((rocketTimer <= 0.0f) || (userDefinedExplosion >= 0)) {
379 if (numRockets < dMaxrockets) {
380 particle *rock = addParticle ();
381
382 if (rsRandi (30) || (userDefinedExplosion >= 0)) { // Usually launch a rocket
383 rock->initRocket ();
384 if (userDefinedExplosion >= 0)
385 rock->explosiontype = userDefinedExplosion;
386 else {
387 if (!rsRandi (3000)) { // big one!
388 if (rsRandi (2))
389 rock->explosiontype = 19; // sucker and shockwave
390 else
391 rock->explosiontype = 20; // stretcher and bigmama
392 } else {
393 // Distribution of regular explosions
394 if (rsRandi (2)) { // 0 - 2 (all types of spheres)
395 if (!rsRandi (10))
396 rock->explosiontype = 2;
397 else
398 rock->explosiontype = rsRandi (2);
399 } else {
400 if (!rsRandi (3)) // ring, double sphere, sphere and ring
401 rock->explosiontype = rsRandi (3) + 3;
402 else {
403 if (rsRandi (2)) { // 6, 7, 8, 9, 10, 11
404 if (rsRandi (2))
405 rock->explosiontype = rsRandi (2) + 6;
406 else
407 rock->explosiontype = rsRandi (4) + 8;
408 } else {
409 if (rsRandi (2)) // 12, 13, 14
410 rock->explosiontype = rsRandi (3) + 12;
411 else // 15 - 18
412 rock->explosiontype = rsRandi (4) + 15;
413 }
414 }
415 }
416 }
417 }
418 numRockets++;
419 } else { // sometimes make fountains and spinners instead of rockets
420 rock->initFountain ();
421 i = rsRandi (2);
422 for (j = 0; j < i; j++) {
423 rock = addParticle ();
424 rock->initFountain ();
425 }
426 }
427 }
428
429 if (dMaxrockets)
430 rocketTimer = rsRandf (rocketTimeConst);
431 else
432 rocketTimer = 60.0f; // arbitrary number since no rockets ever fire
433
434 if (userDefinedExplosion >= 0) {
435 userDefinedExplosion = -1;
436 rocketTimer = 20.0f; // Wait 20 seconds after user launches a rocket before launching any more
437 }
438 }
439
440 // update particles
441 numRockets = 0;
442 std::list < particle >::iterator curpart = particles.begin ();
443 while (curpart != particles.end ()) {
444 curpart->update ();
445
446 if (curpart->type == ROCKET)
447 numRockets++;
448
449 curpart->findDepth ();
450 if (curpart->life <= 0.0f || curpart->xyz[1] < 0.0f) {
451 if (curpart->type == ROCKET) { // become explosion
452 if (curpart->xyz[1] <= 0.0f) { // move above ground for explosion
453 curpart->xyz[1] = 0.1f;
454 curpart->vel[1] *= -0.7f;
455 }
456 if (curpart->explosiontype == 18)
457 curpart->initSpinner ();
458 else
459 curpart->initExplosion ();
460 } else if (curpart->type == POPPER) {
461 switch (curpart->explosiontype) {
462 case STAR:
463 curpart->explosiontype = 100;
464 curpart->initExplosion ();
465 break;
466 case STREAMER:
467 curpart->explosiontype = 101;
468 curpart->initExplosion ();
469 break;
470 case METEOR:
471 curpart->explosiontype = 102;
472 curpart->initExplosion ();
473 break;
474 case POPPER:
475 curpart->type = STAR;
476 curpart->rgb.set (1.0f, 0.8f, 0.6f);
477 curpart->t = curpart->tr = 0.2f;
478 }
479 } else if (curpart->type == SUCKER) {
480 curpart->initShockwave ();
481 } else if (curpart->type == STRETCHER) { // become big explosion
482 curpart->initBigmama ();
483 } else // remove particles from list
484 curpart = particles.erase(curpart)--;
485 }
486
487 curpart++;
488 }
489 } else {
490 // Only sort particles if they're not being updated (the camera could still be moving)
491 std::list < particle >::iterator curpart = particles.begin ();
492 while (curpart != particles.end ()) {
493 curpart->findDepth ();
494 curpart++;
495 }
496 }
497
498 // the world
499 drawWorld ();
500
501 // draw particles
502 glEnable (GL_BLEND);
503 std::list < particle >::iterator drawer = particles.begin ();
504 while (drawer != particles.end ()) {
505 drawer->draw ();
506 drawer++;
507 }
508
509 // draw lens flares
510 if (dFlare) {
511 makeFlareList ();
512 for (i = 0; i < numFlares; i++) {
513 if (allflares[i][0] == 0)
514 flare (allflares[i][1], allflares[i][2], allflares[i][3], allflares[i][4], allflares[i][5], allflares[i][6]);
515 else
516 superFlare (allflares[i][1], allflares[i][2], allflares[i][3], allflares[i][4], allflares[i][5], allflares[i][6]);
517 }
518 numFlares = 0;
519 }
520
521 #ifdef HAVE_OPENAL
522 // do sound stuff
523 if (dSound) {
524 float listenerOri[6];
525 listenerOri[0] = float (-modelMat[2]);
526 listenerOri[1] = float (-modelMat[6]);
527 listenerOri[2] = float (-modelMat[10]);
528 listenerOri[3] = float (modelMat[1]);
529 listenerOri[4] = float (modelMat[5]);
530 listenerOri[5] = float (modelMat[9]);
531
532 updateSound (cameraPos.v, cameraVel.v, listenerOri);
533 }
534 #endif
535
536 glFlush ();
537 }
538
hack_draw(xstuff_t * XStuff,double currentTime,float frameTime)539 void hack_draw (xstuff_t * XStuff, double currentTime, float frameTime)
540 {
541 static float times[5] = { 0.03f, 0.03f, 0.03f, 0.03f, 0.03f };
542 static int timeindex = 0;
543 #ifdef BENCHMARK
544 static int a = 1;
545 #endif
546
547 if (frameTime > 0) {
548 times[timeindex] = frameTime;
549 } else { // else use elapsedTime from last frame
550 times[timeindex] = elapsedTime;
551 }
552
553 #ifdef BENCHMARK
554 times[timeindex] = 0.03f;
555 #endif
556
557 // average last 5 frame times together
558 elapsedTime = 0.2f * (times[0] + times[1] + times[2] + times[3] + times[4]);
559
560 timeindex++;
561 if (timeindex >= 5)
562 timeindex = 0;
563
564 if (elapsedTime > 0.0f)
565 draw ();
566
567 #ifdef BENCHMARK
568 if (a++ == 1000)
569 exit(0);
570 #endif
571 }
572
hack_reshape(xstuff_t * XStuff)573 void hack_reshape (xstuff_t * XStuff)
574 {
575 xsize = XStuff->windowWidth;
576 ysize = XStuff->windowHeight;
577
578 centerx = xsize / 2;
579 centery = ysize / 2;
580
581 glViewport (0, 0, xsize, ysize);
582 glGetIntegerv (GL_VIEWPORT, viewport);
583 aspectRatio = float (xsize) / float (ysize);
584 }
585
hack_init(xstuff_t * XStuff)586 void hack_init (xstuff_t * XStuff)
587 {
588 hack_reshape (XStuff);
589
590 // Set OpenGL state
591 glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
592 glDisable (GL_DEPTH_TEST);
593 glEnable (GL_TEXTURE_2D);
594 glFrontFace (GL_CCW);
595 glEnable (GL_CULL_FACE);
596
597 // Initialize data structures
598 initFlares ();
599 if (dSmoke)
600 initSmoke ();
601 initWorld ();
602 initShockwave ();
603
604 lookFrom[1] = rsVec (rsRandf (3000.0f) - 1500.0f, 400.0f, rsRandf (3000.0f) - 1500.0f);
605 lookFrom[2] = rsVec (rsRandf (1000.0f) + 5000.0f, 5.0f, rsRandf (4000.0f) - 2000.0f);
606
607 #ifdef HAVE_OPENAL
608 if (dSound)
609 initSound ();
610 #endif
611 }
612
hack_cleanup(xstuff_t * XStuff)613 void hack_cleanup (xstuff_t * XStuff)
614 {
615 cleanupFlares ();
616 cleanupSmoke ();
617 cleanupWorld ();
618 #ifdef HAVE_OPENAL
619 cleanupSound ();
620 #endif
621 }
622
hack_handle_opts(int argc,char ** argv)623 void hack_handle_opts (int argc, char **argv)
624 {
625 dMaxrockets = 8;
626 dSmoke = 5;
627 dExplosionsmoke = 0;
628 dWind = 20;
629 dAmbient = 10;
630 dStardensity = 20;
631 dFlare = 20;
632 dMoonglow = 20;
633 dSound = 0;
634 dMoon = 1;
635 dClouds = 1;
636 dEarth = 1;
637 dIllumination = 1;
638
639 while (1) {
640 int c;
641
642 #ifdef HAVE_GETOPT_H
643 static struct option long_options[] = {
644 {"help", 0, 0, 'h'},
645 DRIVER_OPTIONS_LONG {"maxrockets", 1, 0, 'm'},
646 {"smoke", 1, 0, 's'},
647 {"explosionsmoke", 1, 0, 'S'},
648 {"wind", 1, 0, 'w'},
649 {"ambient", 1, 0, 'a'},
650 {"stardensity", 1, 0, 'd'},
651 {"flare", 1, 0, 'f'},
652 {"moonglow", 1, 0, 'g'},
653 {"volume", 1, 0, 'v'},
654 {"moon", 0, 0, 'o'},
655 {"no-moon", 0, 0, 'O'},
656 {"clouds", 0, 0, 'c'},
657 {"no-clouds", 0, 0, 'C'},
658 {"earth", 0, 0, 'e'},
659 {"no-earth", 0, 0, 'E'},
660 {"illumination", 0, 0, 'i'},
661 {"no-illumination", 0, 0, 'I'},
662 {0, 0, 0, 0}
663 };
664
665 c = getopt_long (argc, argv, DRIVER_OPTIONS_SHORT "hm:s:S:a:d:f:g:v:oOcCeEiI", long_options, NULL);
666 #else
667 c = getopt (argc, argv, DRIVER_OPTIONS_SHORT "hm:s:S:a:d:f:g:v:oOcCeEiI");
668 #endif
669 if (c == -1)
670 break;
671
672 switch (c) {
673 DRIVER_OPTIONS_CASES case 'h':printf ("%s:"
674 #ifndef HAVE_GETOPT_H
675 " Not built with GNU getopt.h, long options *NOT* enabled."
676 #endif
677 "\n" DRIVER_OPTIONS_HELP "\t--maxrockets/-m <arg>\n" "\t--smoke/-s <arg>\n" "\t--explosionsmoke/-S <arg>\n"
678 "\t--wind/-w <arg>\n" "\t--ambient/-a <arg>\n" "\t--stardensity/-d <arg>\n" "\t--flare/-f <arg>\n"
679 "\t--moonglow/-g <arg>\n" "\t--volume/-v <arg>\n" "\t--moon/-o\n" "\t--no-moon/-O\n" "\t--clouds/-c\n"
680 "\t--no-clouds/-C\n" "\t--earth/-e\n" "\t--no-earth/-E\n" "\t--illumination/-i\n" "\t--no-illumination/-I\n",
681 argv[0]);
682 exit (1);
683 case 'm':
684 dMaxrockets = strtol_minmaxdef (optarg, 10, 1, 100, 1, 8, "--maxrockets: ");
685 break;
686 case 's':
687 dSmoke = strtol_minmaxdef (optarg, 10, 0, 60, 1, 5, "--smoke: ");
688 break;
689 case 'S':
690 dExplosionsmoke = strtol_minmaxdef (optarg, 10, 0, 100, 1, 0, "--explosionsmoke: ");
691 break;
692 case 'w':
693 dWind = strtol_minmaxdef (optarg, 10, 0, 100, 1, 20, "--wind: ");
694 break;
695 case 'a':
696 dAmbient = strtol_minmaxdef (optarg, 10, 0, 100, 1, 10, "--ambient: ");
697 break;
698 case 'd':
699 dStardensity = strtol_minmaxdef (optarg, 10, 0, 100, 1, 20, "--stardensity: ");
700 break;
701 case 'f':
702 dFlare = strtol_minmaxdef (optarg, 10, 0, 100, 1, 20, "--flare: ");
703 break;
704 case 'g':
705 dMoonglow = strtol_minmaxdef (optarg, 10, 0, 100, 1, 20, "--moonglow: ");
706 break;
707 case 'v':
708 dSound = strtol_minmaxdef (optarg, 10, 0, 100, 1, 0, "--volume: ");
709 break;
710 case 'o':
711 dMoon = 1;
712 break;
713 case 'O':
714 dMoon = 0;
715 break;
716 case 'c':
717 dClouds = 1;
718 break;
719 case 'C':
720 dClouds = 0;
721 break;
722 case 'e':
723 dEarth = 1;
724 break;
725 case 'E':
726 dEarth = 0;
727 break;
728 case 'i':
729 dIllumination = 1;
730 break;
731 case 'I':
732 dIllumination = 0;
733 break;
734 }
735 }
736 }
737
738 /*
739 LONG ScreenSaverProc(HWND hwnd, UINT msg, WPARAM wpm, LPARAM lpm){
740 switch(msg){
741 case WM_CREATE:
742 readRegistry();
743 initSaver(hwnd);
744 switch(dPriority){
745 case 0:
746 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
747 break;
748 case 1:
749 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
750 break;
751 case 2:
752 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
753 }
754 readyToDraw = 1;
755 break;
756 case WM_KEYDOWN:
757 switch(int(wpm)){
758 // pause the motion of the fireworks
759 case 'a':
760 case 'A':
761 if(kAction)
762 kAction = 0;
763 else
764 kAction = 1;
765 if(kSlowMotion)
766 kSlowMotion = 0;
767 return(0);
768 // pause the motion of the camera
769 case 'c':
770 case 'C':
771 if(kCamera == 0)
772 kCamera = 1;
773 else{
774 if(kCamera == 1)
775 kCamera = 0;
776 else{
777 if(kCamera == 2)
778 kCamera = 1;
779 }
780 }
781 return(0);
782 // toggle mouse camera control
783 case 'm':
784 case 'M':
785 if(kCamera == 2)
786 kCamera = 1;
787 else{
788 kCamera = 2;
789 mouseSpeed = 0.0f;
790 mouseIdleTime = 0.0f;
791 }
792 return(0);
793 // new camera view
794 case 'n':
795 case 'N':
796 kNewCamera = 1;
797 return(0);
798 // slow the motion of the fireworks
799 case 's':
800 case 'S':
801 if(kSlowMotion)
802 kSlowMotion = 0;
803 else
804 kSlowMotion = 1;
805 if(!kAction)
806 kAction = 1;
807 return(0);
808 // choose which type of rocket explosion
809 case '1':
810 case '2':
811 case '3':
812 case '4':
813 case '5':
814 case '6':
815 case '7':
816 case '8':
817 case '9':
818 userDefinedExplosion = int(wpm) - 49; // explosions 0 - 8
819 return(0);
820 case '0':
821 userDefinedExplosion = 9;
822 return(0);
823 case 'q':
824 case 'Q':
825 userDefinedExplosion = 10;
826 return(0);
827 case 'w':
828 case 'W':
829 userDefinedExplosion = 11;
830 return(0);
831 case 'e':
832 case 'E':
833 userDefinedExplosion = 12;
834 return(0);
835 case 'r':
836 case 'R':
837 userDefinedExplosion = 13;
838 return(0);
839 case 't':
840 case 'T':
841 userDefinedExplosion = 14;
842 return(0);
843 case 'y':
844 case 'Y':
845 userDefinedExplosion = 15;
846 return(0);
847 case 'u':
848 case 'U':
849 userDefinedExplosion = 16;
850 return(0);
851 case 'i':
852 case 'I':
853 userDefinedExplosion = 17;
854 return(0);
855 case 'o':
856 case 'O':
857 userDefinedExplosion = 18; // spinner
858 return(0);
859 case 'b':
860 case 'B':
861 case 'd':
862 case 'D':
863 case 'f':
864 case 'F':
865 case 'g':
866 case 'G':
867 case 'h':
868 case 'H':
869 case 'j':
870 case 'J':
871 case 'k':
872 case 'K':
873 case 'l':
874 case 'L':
875 case 'p':
876 case 'P':
877 case 'v':
878 case 'V':
879 case 'x':
880 case 'X':
881 case 'z':
882 case 'Z':
883 // These letters do nothing
884 // Disabling them makes it harder to make mistakes
885 return(0);
886 }
887 break;
888 case WM_MOUSEMOVE:
889 case WM_LBUTTONDOWN:
890 case WM_LBUTTONUP:
891 case WM_MBUTTONDOWN:
892 case WM_MBUTTONUP:
893 case WM_RBUTTONDOWN:
894 case WM_RBUTTONUP:
895 if(kCamera == 2){
896 mouseButtons = wpm; // key flags
897 mousex = LOWORD(lpm); // horizontal position of cursor
898 mousey = HIWORD(lpm);
899 mouseIdleTime = 0.0f;
900 return(0);
901 }
902 break;
903 case WM_DESTROY:
904 readyToDraw = 0;
905 cleanup(hwnd);
906 break;
907 }
908 return DefScreenSaverProc(hwnd, msg, wpm, lpm);
909 }
910 */
911