~ubuntu-branches/ubuntu/precise/rss-glx/precise

« back to all changes in this revision

Viewing changes to reallyslick/cpp_src/skyrocket_particle.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2009-06-03 18:41:32 UTC
  • mfrom: (1.1.5 upstream) (2.2.1 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090603184132-znjy66pq9xom7hac
Tags: 0.9.0-2ubuntu1
* Merge from debian unstable, remaining changes:
  - Drop dependency on openal. It is not enabled by default anyway, and
    allows openal to migrate to universe.
  - src/skyrocket.{cpp,xml}: Disable sound by default.
  - Add --disable-sound configure flag to debian/rules, as we don't keep 
    the dependencies on openal nor freeglut (both universe packages).
* Dropped changes, merged upstream:
  - other_src/Makefile.am: fix the upstream build rules to actually use
    the ImageMagick CFLAGS returned by pkg-config.
  - Move the unconditional ImageMagick check up in configure.in so that
    our first PKG_CHECK_MODULES() call isn't hidden behind a shell
    conditional.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
#include <math.h>
20
 
#include <GL/gl.h>
21
 
#include <GL/glu.h>
22
 
 
23
 
#include <list>
24
 
 
25
 
#include "rsDefines.h"
26
 
#include "rsRand.h"
27
 
#include "rsMath/rsMatrix.h"
28
 
#include "rsMath/rsQuat.h"
29
 
#include "skyrocket_smoke.h"
30
 
#include "skyrocket_flare.h"
31
 
#include "skyrocket_particle.h"
32
 
#include "skyrocket_world.h"
33
 
#include "skyrocket_shockwave.h"
34
 
#include "skyrocket_sound.h"
35
 
 
36
 
// skyrocket.cpp
37
 
extern std::list < particle > particles;
38
 
extern particle *addParticle ();
39
 
extern int dAmbient;
40
 
extern int dSmoke;
41
 
extern int dExplosionsmoke;
42
 
extern int dWind;
43
 
extern int dFlare;
44
 
extern int dClouds;
45
 
extern int dIllumination;
46
 
extern int dSound;
47
 
extern float elapsedTime;
48
 
extern rsVec cameraPos;         // used for positioning sounds
49
 
 
50
 
// skyrocket_world.cpp
51
 
extern float clouds[CLOUDMESH + 1][CLOUDMESH + 1][9];
52
 
 
53
 
// skyrocket_flare.cpp
54
 
extern unsigned int flarelist[4];
55
 
 
56
 
// skyrocket_smoke.cpp
57
 
extern float smokeTime[SMOKETIMES];
58
 
extern int whichSmoke[WHICHSMOKES];
59
 
extern unsigned int smokelist[5];
60
 
 
61
 
double billboardMat[16];
62
 
 
63
 
particle::particle ()
64
 
{
65
 
        type = STAR;
66
 
        displayList = flarelist[0];
67
 
        drag = 0.612f;          // terminal velocity of 20 ft/s
68
 
        t = 2.0f;
69
 
        tr = t;
70
 
        bright = 1.0f;
71
 
        life = bright;
72
 
        size = 30.0f;
73
 
        makeSmoke = 0;
74
 
 
75
 
        smokeTimeIndex = 0;
76
 
        smokeTrailLength = 0.0f;
77
 
        sparkTrailLength = 0.0f;
78
 
        depth = 0.0f;
79
 
}
80
 
 
81
 
rsVec particle::randomColor ()
82
 
{
83
 
        int i = 0, j = 0, k = 0;
84
 
        rsVec color;
85
 
 
86
 
        switch (rsRandi (6)) {
87
 
        case 0:
88
 
                i = 0;
89
 
                j = 1, k = 2;
90
 
                break;
91
 
        case 1:
92
 
                i = 0;
93
 
                j = 2, k = 1;
94
 
                break;
95
 
        case 2:
96
 
                i = 1;
97
 
                j = 0, k = 2;
98
 
                break;
99
 
        case 3:
100
 
                i = 1;
101
 
                j = 2, k = 0;
102
 
                break;
103
 
        case 4:
104
 
                i = 2;
105
 
                j = 0, k = 1;
106
 
                break;
107
 
        case 5:
108
 
                i = 2;
109
 
                j = 1, k = 0;
110
 
        }
111
 
 
112
 
        color[i] = 1.0f;
113
 
        color[j] = rsRandf (1.0f);
114
 
        color[k] = rsRandf (0.2f);
115
 
 
116
 
        return (color);
117
 
}
118
 
 
119
 
void particle::initRocket ()
120
 
{
121
 
        type = ROCKET;
122
 
        //displayList = rocketlist;
123
 
        xyz[0] = rsRandf (200.0f) - 100.0f;
124
 
        xyz[1] = 5.0f;
125
 
        xyz[2] = rsRandf (200.0f) - 100.0f;
126
 
        lastxyz[0] = xyz[0];
127
 
        lastxyz[1] = 4.0f;
128
 
        lastxyz[2] = xyz[2];
129
 
        vel.set (0.0f, 60.0f, 0.0f);
130
 
        rgb.set (rsRandf (0.7f) + 0.3f, rsRandf (0.7f) + 0.3f, 0.3f);
131
 
        size = 1.0f;
132
 
        drag = 0.281f;          // terminal velocity of 50 ft/s
133
 
        t = rsRandf (2.0f) + 5.0f;
134
 
        tr = t;
135
 
        bright = 0.0f;
136
 
        thrust = rsRandf (100.0f) + 200.0f;
137
 
        endthrust = rsRandf (0.1f) + 0.3f;
138
 
        spin = rsRandf (40.0f) - 20.0f;
139
 
        tilt = rsRandf (30.0f * float (fabs (spin)));
140
 
 
141
 
        tiltvec.set (cos (spin), 0.0f, sin (spin));
142
 
        if (!rsRandi (200)) {   // crash the occasional rocket
143
 
                spin = 0.0f;
144
 
                tilt = rsRandf (100.0f) + 75.0f;
145
 
                float temp = rsRandf (PIx2);
146
 
 
147
 
                tiltvec.set (cos (temp), 0.0f, sin (temp));
148
 
        }
149
 
 
150
 
        makeSmoke = 1;
151
 
        smokeTrailLength = 0.0f;
152
 
        sparkTrailLength = 0.0f;
153
 
        explosiontype = 0;
154
 
 
155
 
#ifdef HAVE_OPENAL
156
 
        if (dSound) {
157
 
                if (rsRandi (2))
158
 
                        insertSoundNode (LAUNCH1SOUND, xyz, cameraPos);
159
 
                else
160
 
                        insertSoundNode (LAUNCH2SOUND, xyz, cameraPos);
161
 
        }
162
 
#endif
163
 
}
164
 
 
165
 
void particle::initFountain ()
166
 
{
167
 
        type = FOUNTAIN;
168
 
        displayList = flarelist[0];
169
 
        size = 30.0f;
170
 
        // position can be defined here because these are always on the ground
171
 
        xyz[0] = rsRandf (300.0f) - 150.0f;
172
 
        xyz[1] = 5.0f;
173
 
        xyz[2] = rsRandf (300.0f) - 150.0f;
174
 
        rgb = randomColor ();
175
 
        t = rsRandf (5.0f) + 10.0f;
176
 
        tr = t;
177
 
        bright = 0.0f;
178
 
        makeSmoke = 0;
179
 
 
180
 
#ifdef HAVE_OPENAL
181
 
        if (dSound) {
182
 
                if (rsRandi (2))
183
 
                        insertSoundNode (LAUNCH1SOUND, xyz, cameraPos);
184
 
                else
185
 
                        insertSoundNode (LAUNCH2SOUND, xyz, cameraPos);
186
 
        }
187
 
#endif
188
 
}
189
 
 
190
 
void particle::initSpinner ()
191
 
{
192
 
        type = SPINNER;
193
 
        displayList = flarelist[0];
194
 
        drag = 0.612f;          // terminal velocity of 20 ft/s
195
 
        rgb = randomColor ();
196
 
        spin = rsRandf (3.0f) + 12.0f;  // radial velocity
197
 
        tilt = rsRandf (PIx2);  // original rotation
198
 
        tiltvec.set (rsRandf (2.0f) - 1.0f, rsRandf (2.0f) - 1.0f, rsRandf (2.0f) - 1.0f);
199
 
        tiltvec.normalize ();   // vector around which this spinner spins
200
 
        t = rsRandf (2.0f) + 6.0f;
201
 
        tr = t;
202
 
        bright = 0.0f;
203
 
        size = 20.0f;
204
 
        makeSmoke = 1;
205
 
        sparkTrailLength = 0.0f;
206
 
 
207
 
#ifdef HAVE_OPENAL
208
 
        if (dSound) {
209
 
                if (rsRandi (2))
210
 
                        insertSoundNode (LAUNCH1SOUND, xyz, cameraPos);
211
 
                else
212
 
                        insertSoundNode (LAUNCH2SOUND, xyz, cameraPos);
213
 
        }
214
 
#endif
215
 
}
216
 
 
217
 
void particle::initSmoke (rsVec pos, rsVec speed)
218
 
{
219
 
        type = SMOKE;
220
 
        displayList = smokelist[rsRandi (5)];
221
 
        xyz = pos;
222
 
        vel = speed;
223
 
        rgb[0] = rgb[1] = rgb[2] = 0.01f * float (dAmbient);
224
 
 
225
 
        drag = 2.0f;
226
 
        // time for each smoke particle varies and must be assigned by the particle that produces the smoke
227
 
        size = 0.1f;
228
 
        makeSmoke = 0;
229
 
}
230
 
 
231
 
void particle::initStar ()
232
 
{
233
 
        type = STAR;
234
 
        displayList = flarelist[0];
235
 
        drag = 0.612f;          // terminal velocity of 20 ft/s
236
 
        size = 30.0f;
237
 
        t = rsRandf (1.0f) + 2.0f;
238
 
        tr = t;
239
 
        static int someSmoke = 0;
240
 
 
241
 
        makeSmoke = whichSmoke[someSmoke];
242
 
        smokeTrailLength = 0.0f;
243
 
        someSmoke++;
244
 
        if (someSmoke >= WHICHSMOKES)
245
 
                someSmoke = 0;
246
 
}
247
 
 
248
 
void particle::initStreamer ()
249
 
{
250
 
        type = STREAMER;
251
 
        displayList = flarelist[0];
252
 
        drag = 0.612f;          // terminal velocity of 20 ft/s
253
 
        size = 30.0f;
254
 
        t = rsRandf (1.0f) + 3.0f;
255
 
        tr = t;
256
 
        sparkTrailLength = 0.0f;
257
 
}
258
 
 
259
 
void particle::initMeteor ()
260
 
{
261
 
        type = METEOR;
262
 
        displayList = flarelist[0];
263
 
        drag = 0.612f;          // terminal velocity of 20 ft/s
264
 
        t = rsRandf (1.0f) + 3.0f;
265
 
        tr = t;
266
 
        size = 20.0f;
267
 
        sparkTrailLength = 0.0f;
268
 
}
269
 
 
270
 
void particle::initStarPopper ()
271
 
{
272
 
        type = POPPER;
273
 
        displayList = flarelist[0];
274
 
        drag = 0.4f;
275
 
        t = rsRandf (1.5f) + 3.0f;
276
 
        tr = t;
277
 
        makeSmoke = 1;
278
 
        explosiontype = STAR;
279
 
        size = 0.0f;
280
 
        smokeTrailLength = 0.0f;
281
 
}
282
 
 
283
 
void particle::initStreamerPopper ()
284
 
{
285
 
        type = POPPER;
286
 
        displayList = flarelist[0];
287
 
        size = 0.0f;
288
 
        drag = 0.4f;
289
 
        t = rsRandf (1.5f) + 3.0f;
290
 
        tr = t;
291
 
        makeSmoke = 1;
292
 
        explosiontype = STREAMER;
293
 
        smokeTrailLength = 0.0f;
294
 
}
295
 
 
296
 
void particle::initMeteorPopper ()
297
 
{
298
 
        type = POPPER;
299
 
        displayList = flarelist[0];
300
 
        size = 0.0f;
301
 
        drag = 0.4f;
302
 
        t = rsRandf (1.5f) + 3.0f;
303
 
        tr = t;
304
 
        makeSmoke = 1;
305
 
        explosiontype = METEOR;
306
 
        smokeTrailLength = 0.0f;
307
 
}
308
 
 
309
 
void particle::initLittlePopper ()
310
 
{
311
 
        type = POPPER;
312
 
        displayList = flarelist[0];
313
 
        drag = 0.4f;
314
 
        t = 4.0f * (0.5f - sin (rsRandf (PI))) + 4.5f;
315
 
        tr = t;
316
 
        size = rsRandf (3.0f) + 7.0f;
317
 
        makeSmoke = 0;
318
 
        explosiontype = POPPER;
319
 
}
320
 
 
321
 
void particle::initBee ()
322
 
{
323
 
        type = BEE;
324
 
        displayList = flarelist[0];
325
 
        size = 10.0f;
326
 
        drag = 0.3f;
327
 
        t = rsRandf (1.0f) + 2.5f;
328
 
        tr = t;
329
 
        makeSmoke = 0;
330
 
        sparkTrailLength = 0.0f;
331
 
 
332
 
        // these variables will be misused to describe bee acceleration vector
333
 
        thrust = rsRandf (PIx2) + PI;
334
 
        endthrust = rsRandf (PIx2) + PI;
335
 
        spin = rsRandf (PIx2) + PI;
336
 
        tiltvec.set (rsRandf (PIx2), rsRandf (PIx2), rsRandf (PIx2));
337
 
}
338
 
 
339
 
void particle::initSucker ()
340
 
{
341
 
        int i;
342
 
        particle *newp;
343
 
        rsVec color;
344
 
        float temp1, temp2, ch, sh, cp, sp;
345
 
 
346
 
        type = SUCKER;
347
 
        drag = 0.612f;          // terminal velocity of 20 ft/s
348
 
        displayList = flarelist[2];
349
 
        rgb.set (1.0f, 1.0f, 1.0f);
350
 
        size = 300.0f;
351
 
        t = tr = 4.0f;
352
 
        makeSmoke = 0;
353
 
 
354
 
        // make explosion
355
 
        newp = addParticle ();
356
 
        newp->type = EXPLOSION;
357
 
        newp->xyz = xyz;
358
 
        newp->vel = vel;
359
 
        newp->rgb.set (1.0f, 1.0f, 1.0f);
360
 
        newp->size = 200.0f;
361
 
        newp->t = newp->tr = 4.0f;
362
 
 
363
 
        // Make double ring to go along with sucker
364
 
        color = randomColor ();
365
 
        temp1 = rsRandf (PI);   // heading
366
 
        temp2 = rsRandf (PI);   // pitch
367
 
        ch = cos (temp1);
368
 
        sh = sin (temp1);
369
 
        cp = cos (temp2);
370
 
        sp = sin (temp2);
371
 
        for (i = 0; i < 90; i++) {
372
 
                newp = addParticle ();
373
 
                newp->initStar ();
374
 
                newp->xyz = xyz;
375
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
376
 
                newp->vel[1] = 0.0f;
377
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
378
 
                newp->vel.normalize ();
379
 
                // pitch
380
 
                newp->vel[1] = sp * newp->vel[2];
381
 
                newp->vel[2] = cp * newp->vel[2];
382
 
                // heading
383
 
                temp1 = newp->vel[0];
384
 
                newp->vel[0] = ch * temp1 + sh * newp->vel[1];
385
 
                newp->vel[1] = -sh * temp1 + ch * newp->vel[1];
386
 
                // multiply velocity
387
 
                newp->vel[0] *= 350.0f + rsRandf (30.0f);
388
 
                newp->vel[1] *= 350.0f + rsRandf (30.0f);
389
 
                newp->vel[2] *= 350.0f + rsRandf (30.0f);
390
 
                newp->vel[0] += vel[0];
391
 
                newp->vel[1] += vel[1];
392
 
                newp->vel[2] += vel[2];
393
 
                newp->rgb = color;
394
 
                newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
395
 
                newp->makeSmoke = 0;
396
 
        }
397
 
        color = randomColor ();
398
 
        temp1 = rsRandf (PI);   // heading
399
 
        temp2 = rsRandf (PI);   // pitch
400
 
        ch = cos (temp1);
401
 
        sh = sin (temp1);
402
 
        cp = cos (temp2);
403
 
        sp = sin (temp2);
404
 
        for (i = 0; i < 90; i++) {
405
 
                newp = addParticle ();
406
 
                newp->initStar ();
407
 
                newp->xyz = xyz;
408
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
409
 
                newp->vel[1] = 0.0f;
410
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
411
 
                newp->vel.normalize ();
412
 
                // pitch
413
 
                newp->vel[1] = sp * newp->vel[2];
414
 
                newp->vel[2] = cp * newp->vel[2];
415
 
                // heading
416
 
                temp1 = newp->vel[0];
417
 
                newp->vel[0] = ch * temp1 + sh * newp->vel[1];
418
 
                newp->vel[1] = -sh * temp1 + ch * newp->vel[1];
419
 
                // multiply velocity
420
 
                newp->vel[0] *= 600.0f + rsRandf (50.0f);
421
 
                newp->vel[1] *= 600.0f + rsRandf (50.0f);
422
 
                newp->vel[2] *= 600.0f + rsRandf (50.0f);
423
 
                newp->vel[0] += vel[0];
424
 
                newp->vel[1] += vel[1];
425
 
                newp->vel[2] += vel[2];
426
 
                newp->rgb = color;
427
 
                newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
428
 
                newp->makeSmoke = 0;
429
 
        }
430
 
 
431
 
#ifdef HAVE_OPENAL
432
 
        if (dSound)
433
 
                insertSoundNode (SUCKSOUND, xyz, cameraPos);
434
 
#endif
435
 
}
436
 
 
437
 
void particle::initShockwave ()
438
 
{
439
 
        int i;
440
 
        particle *newp;
441
 
        rsVec color;
442
 
 
443
 
        type = SHOCKWAVE;
444
 
        drag = 0.612f;          // terminal velocity of 20 ft/s
445
 
        rgb.set (1.0f, 1.0f, 1.0f);
446
 
        size = 0.0f;
447
 
        t = tr = 5.0f;
448
 
 
449
 
        // make explosion
450
 
        newp = addParticle ();
451
 
        newp->type = EXPLOSION;
452
 
        newp->xyz = xyz;
453
 
        newp->vel = vel;
454
 
        newp->rgb.set (1.0f, 1.0f, 1.0f);
455
 
        newp->size = 300.0f;
456
 
        newp->t = newp->tr = 3.0f;
457
 
        makeSmoke = 0;
458
 
 
459
 
        // Little sphere without smoke
460
 
        color = randomColor ();
461
 
        for (i = 0; i < 75; i++) {
462
 
                newp = addParticle ();
463
 
                newp->initStar ();
464
 
                newp->xyz = xyz;
465
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
466
 
                newp->vel[1] = rsRandf (1.0f) - 0.5f;
467
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
468
 
                newp->vel.normalize ();
469
 
                newp->vel *= (rsRandf (10.0f) + 100.0f);
470
 
                newp->vel += vel;
471
 
                newp->rgb = color;
472
 
                newp->size = 100.0f;
473
 
                newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
474
 
                newp->makeSmoke = 0;
475
 
        }
476
 
 
477
 
        // Disk of stars without smoke
478
 
        color = randomColor ();
479
 
        for (i = 0; i < 150; i++) {
480
 
                newp = addParticle ();
481
 
                newp->initStar ();
482
 
                newp->drag = 0.2f;
483
 
                newp->xyz = xyz;
484
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
485
 
                newp->vel[1] = rsRandf (0.03f) - 0.005f;
486
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
487
 
                newp->vel.normalize ();
488
 
                // multiply velocity
489
 
                newp->vel *= (rsRandf (30.0f) + 500.0f);
490
 
                newp->vel += vel;
491
 
                newp->rgb = color;
492
 
                newp->size = 50.0f;
493
 
                newp->t = newp->tr = rsRandf (2.0f) + 3.0f;
494
 
                newp->makeSmoke = 0;
495
 
        }
496
 
 
497
 
#ifdef HAVE_OPENAL
498
 
        if (dSound)
499
 
                insertSoundNode (NUKESOUND, xyz, cameraPos);
500
 
#endif
501
 
}
502
 
 
503
 
void particle::initStretcher ()
504
 
{
505
 
        int i;
506
 
        particle *newp;
507
 
        rsVec color;
508
 
 
509
 
        type = STRETCHER;
510
 
        drag = 0.612f;          // terminal velocity of 20 ft/s
511
 
        displayList = flarelist[3];
512
 
        rgb.set (1.0f, 1.0f, 1.0f);
513
 
        size = 0.0f;
514
 
        t = tr = 4.0f;
515
 
        makeSmoke = 0;
516
 
 
517
 
        // explosion
518
 
        newp = addParticle ();
519
 
        newp->type = EXPLOSION;
520
 
        newp->displayList = flarelist[0];
521
 
        newp->xyz = xyz;
522
 
        newp->vel = vel;
523
 
        newp->rgb.set (1.0f, 0.8f, 0.6f);
524
 
        newp->size = 400.0f;
525
 
        newp->t = newp->tr = 4.0f;
526
 
        newp->makeSmoke = 0;
527
 
 
528
 
        // Make triple ring to go along with stretcher
529
 
        color = randomColor ();
530
 
        for (i = 0; i < 80; i++) {
531
 
                newp = addParticle ();
532
 
                newp->initStar ();
533
 
                newp->xyz = xyz;
534
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
535
 
                newp->vel[1] = 0.0f;
536
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
537
 
                newp->vel.normalize ();
538
 
                newp->vel[0] *= 400.0f + rsRandf (30.0f);
539
 
                newp->vel[1] += rsRandf (70.0f) - 35.0f;
540
 
                newp->vel[2] *= 400.0f + rsRandf (30.0f);
541
 
                newp->vel[0] += vel[0];
542
 
                newp->vel[1] += vel[1];
543
 
                newp->vel[2] += vel[2];
544
 
                newp->rgb = color;
545
 
                newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
546
 
                newp->makeSmoke = 0;
547
 
        }
548
 
        color = randomColor ();
549
 
        for (i = 0; i < 80; i++) {
550
 
                newp = addParticle ();
551
 
                newp->initStar ();
552
 
                newp->xyz = xyz;
553
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
554
 
                newp->vel[1] = 0.0f;
555
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
556
 
                newp->vel.normalize ();
557
 
                newp->vel[0] *= 550.0f + rsRandf (40.0f);
558
 
                newp->vel[1] += rsRandf (70.0f) - 35.0f;
559
 
                newp->vel[2] *= 550.0f + rsRandf (40.0f);
560
 
                newp->vel[0] += vel[0];
561
 
                newp->vel[1] += vel[1];
562
 
                newp->vel[2] += vel[2];
563
 
                newp->rgb = color;
564
 
                newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
565
 
                newp->makeSmoke = 0;
566
 
        }
567
 
        color = randomColor ();
568
 
        for (i = 0; i < 80; i++) {
569
 
                newp = addParticle ();
570
 
                newp->initStar ();
571
 
                newp->xyz = xyz;
572
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
573
 
                newp->vel[1] = 0.0f;
574
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
575
 
                newp->vel.normalize ();
576
 
                newp->vel[0] *= 700.0f + rsRandf (50.0f);
577
 
                newp->vel[1] += rsRandf (70.0f) - 35.0f;
578
 
                newp->vel[2] *= 700.0f + rsRandf (50.0f);
579
 
                newp->vel[0] += vel[0];
580
 
                newp->vel[1] += vel[1];
581
 
                newp->vel[2] += vel[2];
582
 
                newp->rgb = color;
583
 
                newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
584
 
                newp->makeSmoke = 0;
585
 
        }
586
 
 
587
 
#ifdef HAVE_OPENAL
588
 
        if (dSound)
589
 
                insertSoundNode (SUCKSOUND, xyz, cameraPos);
590
 
#endif
591
 
}
592
 
 
593
 
void particle::initBigmama ()
594
 
{
595
 
        int i;
596
 
        particle *newp;
597
 
        rsVec color;
598
 
        float temp;
599
 
 
600
 
        type = BIGMAMA;
601
 
        drag = 0.612f;          // terminal velocity of 20 ft/s
602
 
        displayList = flarelist[2];
603
 
        rgb.set (0.6f, 0.6f, 1.0f);
604
 
        size = 0.0f;
605
 
        t = tr = 5.0f;
606
 
        makeSmoke = 0;
607
 
 
608
 
        // explosion
609
 
        newp = addParticle ();
610
 
        newp->type = EXPLOSION;
611
 
        newp->xyz = xyz;
612
 
        newp->vel = vel;
613
 
        newp->drag = 0.0f;
614
 
        newp->rgb.set (0.8f, 0.8f, 1.0f);
615
 
        newp->size = 200.0f;
616
 
        newp->t = newp->tr = 2.5f;
617
 
        newp->makeSmoke = 0;
618
 
 
619
 
        // vertical stars
620
 
        newp = addParticle ();
621
 
        newp->initStar ();
622
 
        newp->xyz = xyz;
623
 
        newp->vel = vel;
624
 
        newp->drag = 0.0f;
625
 
        newp->vel[1] += 15.0f;
626
 
        newp->rgb.set (1.0f, 1.0f, 0.9f);
627
 
        newp->size = 400.0f;
628
 
        newp->t = newp->tr = 3.0f;
629
 
        newp->makeSmoke = 0;
630
 
        newp = addParticle ();
631
 
        newp->initStar ();
632
 
        newp->xyz = xyz;
633
 
        newp->vel = vel;
634
 
        newp->drag = 0.0f;
635
 
        newp->vel[1] -= 15.0f;
636
 
        newp->rgb.set (1.0f, 1.0f, 0.9f);
637
 
        newp->size = 400.0f;
638
 
        newp->t = newp->tr = 3.0f;
639
 
        newp->makeSmoke = 0;
640
 
        newp = addParticle ();
641
 
        newp->initStar ();
642
 
        newp->xyz = xyz;
643
 
        newp->vel = vel;
644
 
        newp->drag = 0.0f;
645
 
        newp->vel[1] += 45.0f;
646
 
        newp->rgb.set (1.0f, 1.0f, 0.6f);
647
 
        newp->size = 400.0f;
648
 
        newp->t = newp->tr = 3.5f;
649
 
        newp->makeSmoke = 0;
650
 
        newp = addParticle ();
651
 
        newp->initStar ();
652
 
        newp->xyz = xyz;
653
 
        newp->vel = vel;
654
 
        newp->drag = 0.0f;
655
 
        newp->vel[1] -= 45.0f;
656
 
        newp->rgb.set (1.0f, 1.0f, 0.6f);
657
 
        newp->size = 400.0f;
658
 
        newp->t = newp->tr = 3.5f;
659
 
        newp->makeSmoke = 0;
660
 
        newp = addParticle ();
661
 
        newp->initStar ();
662
 
        newp->xyz = xyz;
663
 
        newp->vel = vel;
664
 
        newp->drag = 0.0f;
665
 
        newp->vel[1] += 75.0f;
666
 
        newp->rgb.set (1.0f, 0.5f, 0.3f);
667
 
        newp->size = 400.0f;
668
 
        newp->t = newp->tr = 4.0f;
669
 
        newp->makeSmoke = 0;
670
 
        newp = addParticle ();
671
 
        newp->initStar ();
672
 
        newp->xyz = xyz;
673
 
        newp->vel = vel;
674
 
        newp->drag = 0.0f;
675
 
        newp->vel[1] -= 75.0f;
676
 
        newp->rgb.set (1.0f, 0.5f, 0.3f);
677
 
        newp->size = 400.0f;
678
 
        newp->t = newp->tr = 4.0f;
679
 
        newp->makeSmoke = 0;
680
 
        newp = addParticle ();
681
 
        newp->initStar ();
682
 
        newp->xyz = xyz;
683
 
        newp->vel = vel;
684
 
        newp->drag = 0.0f;
685
 
        newp->vel[1] += 105.0f;
686
 
        newp->rgb.set (1.0f, 0.0f, 0.0f);
687
 
        newp->size = 400.0f;
688
 
        newp->t = newp->tr = 4.5f;
689
 
        newp->makeSmoke = 0;
690
 
        newp = addParticle ();
691
 
        newp->initStar ();
692
 
        newp->xyz = xyz;
693
 
        newp->vel = vel;
694
 
        newp->drag = 0.0f;
695
 
        newp->vel[1] -= 105.0f;
696
 
        newp->rgb.set (1.0f, 0.0f, 0.0f);
697
 
        newp->size = 400.0f;
698
 
        newp->t = newp->tr = 4.5f;
699
 
        newp->makeSmoke = 0;
700
 
 
701
 
        // Sphere without smoke
702
 
        color = randomColor ();
703
 
        for (i = 0; i < 75; i++) {
704
 
                newp = addParticle ();
705
 
                newp->initStar ();
706
 
                newp->xyz = xyz;
707
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
708
 
                newp->vel[1] = rsRandf (1.0f) - 0.5f;
709
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
710
 
                newp->vel.normalize ();
711
 
                temp = 600.0f + rsRandf (100.0f);
712
 
                newp->vel[0] *= temp;
713
 
                newp->vel[1] *= temp;
714
 
                newp->vel[2] *= temp;
715
 
                newp->vel[0] += vel[0];
716
 
                newp->vel[1] += vel[1];
717
 
                newp->vel[2] += vel[2];
718
 
                newp->rgb = color;
719
 
                newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
720
 
                newp->makeSmoke = 0;
721
 
        }
722
 
 
723
 
        // disk of big streamers
724
 
        color = randomColor ();
725
 
        for (i = 0; i < 50; i++) {
726
 
                newp = addParticle ();
727
 
                newp->initStreamer ();
728
 
                newp->drag = 0.3f;
729
 
                newp->xyz = xyz;
730
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
731
 
                newp->vel[1] = 0.0f;
732
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
733
 
                newp->vel.normalize ();
734
 
                newp->vel[0] *= 1000.0f + rsRandf (100.0f);
735
 
                newp->vel[1] += rsRandf (100.0f) - 50.0f;
736
 
                newp->vel[2] *= 1000.0f + rsRandf (100.0f);
737
 
                newp->vel[0] += vel[0];
738
 
                newp->vel[1] += vel[1];
739
 
                newp->vel[2] += vel[2];
740
 
                newp->rgb = color;
741
 
                newp->size = 100.0f;
742
 
                newp->t = newp->tr = rsRandf (6.0f) + 3.0f;
743
 
                newp->makeSmoke = 0;
744
 
        }
745
 
 
746
 
#ifdef HAVE_OPENAL
747
 
        if (dSound)
748
 
                insertSoundNode (NUKESOUND, xyz, cameraPos);
749
 
#endif
750
 
}
751
 
 
752
 
void particle::initExplosion ()
753
 
{
754
 
        type = EXPLOSION;
755
 
        displayList = flarelist[0];
756
 
        drag = 0.612f;
757
 
        t = 0.5f;
758
 
        tr = t;
759
 
        bright = 1.0f;
760
 
        life = bright;
761
 
        size = 100.0f;
762
 
        makeSmoke = 0;
763
 
 
764
 
        // Don't do massive explosions too close to the ground
765
 
        if ((explosiontype == 19 || explosiontype == 20) && (xyz[1] < 1000.0f))
766
 
                explosiontype = 0;
767
 
 
768
 
        switch (explosiontype) {
769
 
        case 0:
770
 
                rgb = randomColor ();
771
 
                if (!rsRandi (10))      // big sphere
772
 
                        popSphere (225, 1000.0f, rgb);
773
 
                else            // regular sphere
774
 
                        popSphere (175, rsRandf (100.0f) + 400.0f, rgb);
775
 
                break;
776
 
        case 1:
777
 
                rgb = randomColor ();
778
 
                if (!rsRandi (10))      // big split sphere
779
 
                        popSplitSphere (225, 1000.0f, rgb);
780
 
                else            // regular split sphere
781
 
                        popSplitSphere (175, rsRandf (100.0f) + 400.0f, rgb);
782
 
                break;
783
 
        case 2:
784
 
                rgb.set (1.0f, 1.0f, 1.0f);
785
 
                if (!rsRandi (10))      // big multicolored sphere
786
 
                        popMultiColorSphere (225, 1000.0f);
787
 
                else            // regular multicolored sphere
788
 
                        popMultiColorSphere (175, rsRandf (100.0f) + 400.0f);
789
 
                break;
790
 
        case 3:         // ring
791
 
                rgb = randomColor ();
792
 
                popRing (70, rsRandf (100.0f) + 400.0f, rgb);
793
 
                break;
794
 
        case 4:         // double sphere
795
 
                rgb = randomColor ();
796
 
                popSphere (90, rsRandf (50.0f) + 200.0f, randomColor ());
797
 
                popSphere (150, rsRandf (100.0f) + 500.0f, rgb);
798
 
                break;
799
 
        case 5:         // sphere and ring
800
 
                rgb = randomColor ();
801
 
                popRing (70, rsRandf (100.0f) + 500.0f, randomColor ());
802
 
                popSphere (150, rsRandf (50.0f) + 200.0f, rgb);
803
 
                break;
804
 
        case 6:         // Sphere of streamers
805
 
                rgb = randomColor ();
806
 
                popStreamers (40, rsRandf (100.0f) + 400.0f, rgb);
807
 
                break;
808
 
        case 7:         // Sphere of meteors
809
 
                rgb = randomColor ();
810
 
                popMeteors (40, rsRandf (100.0f) + 400.0f, rgb);
811
 
                break;
812
 
        case 8:         // Small sphere of stars and large sphere of streamers
813
 
                rgb = randomColor ();
814
 
                popStreamers (25, rsRandf (100.0f) + 500.0f, rgb);
815
 
                popSphere (90, rsRandf (50.0f) + 200.0f, randomColor ());
816
 
                break;
817
 
        case 9:         // Small sphere of stars and large sphere of meteors
818
 
                rgb = randomColor ();
819
 
                popMeteors (25, rsRandf (100.0f) + 500.0f, rgb);
820
 
                popSphere (90, rsRandf (50.0f) + 200.0f, randomColor ());
821
 
                break;
822
 
        case 10:                // Sphere of streamers inside sphere of stars
823
 
                rgb = randomColor ();
824
 
                popStreamers (20, rsRandf (100.0f) + 450.0f, rgb);
825
 
                popSphere (150, rsRandf (50.0f) + 500.0f, randomColor ());
826
 
                break;
827
 
        case 11:                // Sphere of meteors inside sphere of stars
828
 
                rgb = randomColor ();
829
 
                popMeteors (20, rsRandf (100.0f) + 450.0f, rgb);
830
 
                popSphere (150, rsRandf (50.0f) + 500.0f, randomColor ());
831
 
                break;
832
 
        case 12:                // a few bombs that fall and explode into stars
833
 
                rgb = randomColor ();
834
 
                popStarPoppers (8, rsRandf (100.0f) + 300.0f, rgb);
835
 
                break;
836
 
        case 13:                // a few bombs that fall and explode into streamers
837
 
                rgb = randomColor ();
838
 
                popStreamerPoppers (8, rsRandf (100.0f) + 300.0f, rgb);
839
 
                break;
840
 
        case 14:                // a few bombs that fall and explode into meteors
841
 
                rgb = randomColor ();
842
 
                popMeteorPoppers (8, rsRandf (100.0f) + 300.0f, rgb);
843
 
                break;
844
 
        case 15:                // lots of little falling firecrackers
845
 
                popLittlePoppers (250, rsRandf (50.0f) + 150.0f);
846
 
                break;
847
 
        case 16:
848
 
                rgb = randomColor ();
849
 
                popBees (30, 10.0f, rgb);
850
 
                break;
851
 
        case 17:                // Boom!  (loud noise and flash of light)
852
 
                rgb.set (1.0f, 1.0f, 1.0f);
853
 
                size = 150.0f;
854
 
                break;
855
 
                // 18 is a spinner, which doesn't require explosion
856
 
        case 19:
857
 
                rgb.set (1.0f, 1.0f, 1.0f);
858
 
                initSucker ();
859
 
                break;
860
 
        case 20:
861
 
                rgb.set (1.0f, 1.0f, 1.0f);
862
 
                initStretcher ();
863
 
                break;
864
 
        case 100:               // these three are little explosions for poppers
865
 
                popSphere (30, 100.0f, rgb);
866
 
                break;
867
 
        case 101:
868
 
                popStreamers (10, 100.0f, rgb);
869
 
                break;
870
 
        case 102:
871
 
                popMeteors (10, 100.0f, rgb);
872
 
        }
873
 
 
874
 
#ifdef HAVE_OPENAL
875
 
        if (dSound) {
876
 
                if (explosiontype == 17)        // extra resounding boom
877
 
                        insertSoundNode (BOOM4SOUND, xyz, cameraPos);
878
 
                // make bees and big booms whistle sometimes
879
 
                if (explosiontype == 16 || explosiontype == 17)
880
 
                        if (rsRandi (2))
881
 
                                insertSoundNode (WHISTLESOUND, xyz, cameraPos);
882
 
                // regular booms
883
 
                if (explosiontype <= 16 || explosiontype >= 100)
884
 
                        insertSoundNode (BOOM1SOUND + rsRandi (3), xyz, cameraPos);
885
 
                // sucker and stretcher take care of their own sounds
886
 
        }
887
 
#endif
888
 
}
889
 
 
890
 
void particle::popSphere (int numParts, float v0, rsVec color)
891
 
{
892
 
        particle *newp = NULL;
893
 
        float temp;
894
 
 
895
 
        for (int i = 0; i < numParts; i++) {
896
 
                newp = addParticle ();
897
 
                newp->initStar ();
898
 
                newp->xyz = xyz;
899
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
900
 
                newp->vel[1] = rsRandf (1.0f) - 0.5f;
901
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
902
 
                newp->vel.normalize ();
903
 
                temp = v0 + rsRandf (50.0f);
904
 
                newp->vel *= temp;
905
 
                newp->vel += vel;
906
 
                newp->rgb = color;
907
 
        }
908
 
 
909
 
        if (!rsRandi (100))
910
 
                newp->t = newp->tr = rsRandf (20.0f) + 5.0f;
911
 
}
912
 
 
913
 
void particle::popSplitSphere (int numParts, float v0, rsVec color1)
914
 
{
915
 
        particle *newp = NULL;
916
 
        rsVec color2;
917
 
        rsVec planeNormal;
918
 
        float temp;
919
 
 
920
 
        color2 = randomColor ();
921
 
        planeNormal[0] = rsRandf (1.0f) - 0.5f;
922
 
        planeNormal[1] = rsRandf (1.0f) - 0.5f;
923
 
        planeNormal[2] = rsRandf (1.0f) - 0.5f;
924
 
        planeNormal.normalize ();
925
 
        for (int i = 0; i < numParts; i++) {
926
 
                newp = addParticle ();
927
 
                newp->initStar ();
928
 
                newp->xyz = xyz;
929
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
930
 
                newp->vel[1] = rsRandf (1.0f) - 0.5f;
931
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
932
 
                newp->vel.normalize ();
933
 
                if (planeNormal.dot (newp->vel) > 0.0f)
934
 
                        newp->rgb = color1;
935
 
                else
936
 
                        newp->rgb = color2;
937
 
                temp = v0 + rsRandf (50.0f);
938
 
                newp->vel *= temp;
939
 
                newp->vel += vel;
940
 
        }
941
 
 
942
 
        if (!rsRandi (100))
943
 
                newp->t = newp->tr = rsRandf (20.0f) + 5.0f;
944
 
}
945
 
 
946
 
void particle::popMultiColorSphere (int numParts, float v0)
947
 
{
948
 
        int j;
949
 
        particle *newp = NULL;
950
 
        float temp;
951
 
        rsVec color[3];;
952
 
 
953
 
        color[0] = randomColor ();
954
 
        color[1] = randomColor ();
955
 
        color[2] = randomColor ();
956
 
        j = 0;
957
 
        for (int i = 0; i < numParts; i++) {
958
 
                newp = addParticle ();
959
 
                newp->initStar ();
960
 
                newp->xyz = xyz;
961
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
962
 
                newp->vel[1] = rsRandf (1.0f) - 0.5f;
963
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
964
 
                newp->vel.normalize ();
965
 
                temp = v0 + rsRandf (30.0f);
966
 
                newp->vel *= temp;
967
 
                newp->vel += vel;
968
 
                newp->rgb = color[j];
969
 
                j++;
970
 
                if (j >= 3)
971
 
                        j = 0;
972
 
        }
973
 
 
974
 
        if (!rsRandi (100))
975
 
                newp->t = newp->tr = rsRandf (20.0f) + 5.0f;
976
 
}
977
 
 
978
 
void particle::popRing (int numParts, float v0, rsVec color)
979
 
{
980
 
        particle *newp = NULL;
981
 
        float temp1, temp2;
982
 
        float ch, sh, cp, sp;
983
 
 
984
 
        temp1 = rsRandf (PI);   // heading
985
 
        temp2 = rsRandf (PI);   // pitch
986
 
        ch = cos (temp1);
987
 
        sh = sin (temp1);
988
 
        cp = cos (temp2);
989
 
        sp = sin (temp2);
990
 
        for (int i = 0; i < numParts; i++) {
991
 
                newp = addParticle ();
992
 
                newp->initStar ();
993
 
                newp->xyz = xyz;
994
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
995
 
                newp->vel[1] = 0.0f;
996
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
997
 
                newp->vel.normalize ();
998
 
                // pitch
999
 
                newp->vel[1] = sp * newp->vel[2];
1000
 
                newp->vel[2] = cp * newp->vel[2];
1001
 
                // heading
1002
 
                temp1 = newp->vel[0];
1003
 
                newp->vel[0] = ch * temp1 + sh * newp->vel[1];
1004
 
                newp->vel[1] = -sh * temp1 + ch * newp->vel[1];
1005
 
                // multiply velocity
1006
 
                newp->vel[0] *= v0 + rsRandf (50.0f);
1007
 
                newp->vel[1] *= v0 + rsRandf (50.0f);
1008
 
                newp->vel[2] *= v0 + rsRandf (50.0f);
1009
 
                newp->vel += vel;
1010
 
                newp->rgb = color;
1011
 
        }
1012
 
 
1013
 
        if (!rsRandi (100))
1014
 
                newp->t = newp->tr = rsRandf (20.0f) + 5.0f;
1015
 
}
1016
 
 
1017
 
void particle::popStreamers (int numParts, float v0, rsVec color)
1018
 
{
1019
 
        particle *newp = NULL;
1020
 
        float temp;
1021
 
 
1022
 
        for (int i = 0; i < numParts; i++) {
1023
 
                newp = addParticle ();
1024
 
                newp->initStreamer ();
1025
 
                newp->xyz = xyz;
1026
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
1027
 
                newp->vel[1] = rsRandf (1.0f) - 0.5f;
1028
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
1029
 
                newp->vel.normalize ();
1030
 
                temp = v0 + rsRandf (50.0f);
1031
 
                newp->vel *= temp;
1032
 
                newp->vel += vel;
1033
 
                newp->rgb = color;
1034
 
        }
1035
 
}
1036
 
 
1037
 
void particle::popMeteors (int numParts, float v0, rsVec color)
1038
 
{
1039
 
        particle *newp = NULL;
1040
 
        float temp;
1041
 
 
1042
 
        for (int i = 0; i < numParts; i++) {
1043
 
                newp = addParticle ();
1044
 
                newp->initMeteor ();
1045
 
                newp->xyz = xyz;
1046
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
1047
 
                newp->vel[1] = rsRandf (1.0f) - 0.5f;
1048
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
1049
 
                newp->vel.normalize ();
1050
 
                temp = v0 + rsRandf (50.0f);
1051
 
                newp->vel *= temp;
1052
 
                newp->vel += vel;
1053
 
                newp->rgb = color;
1054
 
        }
1055
 
}
1056
 
 
1057
 
void particle::popStarPoppers (int numParts, float v0, rsVec color)
1058
 
{
1059
 
        particle *newp = NULL;
1060
 
        float v0x2 = v0 * 2;
1061
 
 
1062
 
        for (int i = 0; i < numParts; i++) {
1063
 
                newp = addParticle ();
1064
 
                newp->initStarPopper ();
1065
 
                newp->xyz = xyz;
1066
 
                newp->vel[0] = vel[0] + rsRandf (v0x2) - v0;
1067
 
                newp->vel[1] = vel[1] + rsRandf (v0x2) - v0;
1068
 
                newp->vel[2] = vel[2] + rsRandf (v0x2) - v0;
1069
 
                newp->rgb = color;
1070
 
        }
1071
 
}
1072
 
 
1073
 
void particle::popStreamerPoppers (int numParts, float v0, rsVec color)
1074
 
{
1075
 
        particle *newp = NULL;
1076
 
        float v0x2 = v0 * 2;
1077
 
 
1078
 
        for (int i = 0; i < numParts; i++) {
1079
 
                newp = addParticle ();
1080
 
                newp->initStreamerPopper ();
1081
 
                newp->xyz = xyz;
1082
 
                newp->vel[0] = vel[0] + rsRandf (v0x2) - v0;
1083
 
                newp->vel[1] = vel[1] + rsRandf (v0x2) - v0;
1084
 
                newp->vel[2] = vel[2] + rsRandf (v0x2) - v0;
1085
 
                newp->rgb = color;
1086
 
        }
1087
 
}
1088
 
 
1089
 
void particle::popMeteorPoppers (int numParts, float v0, rsVec color)
1090
 
{
1091
 
        int i;
1092
 
        particle *newp;
1093
 
        float v0x2 = v0 * 2;
1094
 
 
1095
 
        for (i = 0; i < numParts; i++) {
1096
 
                newp = addParticle ();
1097
 
                newp->initMeteorPopper ();
1098
 
                newp->xyz = xyz;
1099
 
                newp->vel[0] = vel[0] + rsRandf (v0x2) - v0;
1100
 
                newp->vel[1] = vel[1] + rsRandf (v0x2) - v0;
1101
 
                newp->vel[2] = vel[2] + rsRandf (v0x2) - v0;
1102
 
                newp->rgb = color;
1103
 
        }
1104
 
}
1105
 
 
1106
 
void particle::popLittlePoppers (int numParts, float v0)
1107
 
{
1108
 
        particle *newp = NULL;
1109
 
        float v0x2 = v0 * 2;
1110
 
 
1111
 
        for (int i = 0; i < numParts; i++) {
1112
 
                newp = addParticle ();
1113
 
                newp->initLittlePopper ();
1114
 
                newp->xyz = xyz;
1115
 
                newp->vel[0] = vel[0] + rsRandf (v0x2) - v0;
1116
 
                newp->vel[1] = vel[1] + rsRandf (v0x2) - v0;
1117
 
                newp->vel[2] = vel[2] + rsRandf (v0x2) - v0;
1118
 
        }
1119
 
 
1120
 
#ifdef HAVE_OPENAL
1121
 
        if (dSound)
1122
 
                insertSoundNode (POPPERSOUND, xyz, cameraPos);
1123
 
#endif
1124
 
}
1125
 
 
1126
 
void particle::popBees (int numParts, float v0, rsVec color)
1127
 
{
1128
 
        particle *newp = NULL;
1129
 
 
1130
 
        for (int i = 0; i < numParts; i++) {
1131
 
                newp = addParticle ();
1132
 
                newp->initBee ();
1133
 
                newp->xyz = xyz;
1134
 
                newp->vel[0] = rsRandf (1.0f) - 0.5f;
1135
 
                newp->vel[1] = rsRandf (1.0f) - 0.5f;
1136
 
                newp->vel[2] = rsRandf (1.0f) - 0.5f;
1137
 
                newp->vel *= v0;
1138
 
                newp->vel += vel;
1139
 
                newp->rgb = color;
1140
 
        }
1141
 
}
1142
 
 
1143
 
void particle::findDepth ()
1144
 
{
1145
 
        // This isn't the actual distance from the camera.  It is the the
1146
 
        // distance along the view vector coming straight out of the camera.
1147
 
        // This is calculated with a simple dot product.  The billboards don't
1148
 
        // actually face the camera; they all face the same direction (straight
1149
 
        // down the view vector of the camera, so sorting is done a little
1150
 
        // differently than one might expect).
1151
 
        depth = (cameraPos[0] - xyz[0]) * float (billboardMat[8])
1152
 
        + (cameraPos[1] - xyz[1]) * float (billboardMat[9])
1153
 
        + (cameraPos[2] - xyz[2]) * float (billboardMat[10]);
1154
 
}
1155
 
 
1156
 
// Rockets and explosions illuminate smoke
1157
 
// Only explosions illuminate clouds
1158
 
void illuminate (particle * ill)
1159
 
{
1160
 
        float temp;
1161
 
        // desaturate illumination colors
1162
 
        float newrgb[3] = { ill->rgb[0] * 0.6f + 0.4f, ill->rgb[1] * 0.6f + 0.4f, ill->rgb[2] * 0.6f + 0.4f };
1163
 
 
1164
 
        // Smoke illumination
1165
 
        if ((ill->type == ROCKET) || (ill->type == FOUNTAIN)) {
1166
 
                float distsquared;
1167
 
 
1168
 
                std::list < particle >::iterator smk = particles.begin ();
1169
 
                while (smk != particles.end ()) {
1170
 
                        if (smk->type == SMOKE) {
1171
 
                                distsquared = (ill->xyz[0] - smk->xyz[0]) * (ill->xyz[0] - smk->xyz[0])
1172
 
                                        + (ill->xyz[1] - smk->xyz[1]) * (ill->xyz[1] - smk->xyz[1])
1173
 
                                        + (ill->xyz[2] - smk->xyz[2]) * (ill->xyz[2] - smk->xyz[2]);
1174
 
                                if (distsquared < 40000.0f) {
1175
 
                                        temp = (40000.0f - distsquared) * 0.000025f;
1176
 
                                        temp = temp * temp * ill->bright;
1177
 
                                        smk->rgb[0] += temp * newrgb[0];
1178
 
                                        if (smk->rgb[0] > 1.0f)
1179
 
                                                smk->rgb[0] = 1.0f;
1180
 
                                        smk->rgb[1] += temp * newrgb[1];
1181
 
                                        if (smk->rgb[1] > 1.0f)
1182
 
                                                smk->rgb[1] = 1.0f;
1183
 
                                        smk->rgb[2] += temp * newrgb[2];
1184
 
                                        if (smk->rgb[2] > 1.0f)
1185
 
                                                smk->rgb[2] = 1.0f;
1186
 
                                }
1187
 
                        }
1188
 
                        smk++;
1189
 
                }
1190
 
        } else if (ill->type == EXPLOSION) {
1191
 
                float distsquared;
1192
 
 
1193
 
                std::list < particle >::iterator smk = particles.begin ();
1194
 
                while (smk != particles.end ()) {
1195
 
                        if (smk->type == SMOKE) {
1196
 
                                distsquared = (ill->xyz[0] - smk->xyz[0]) * (ill->xyz[0] - smk->xyz[0])
1197
 
                                        + (ill->xyz[1] - smk->xyz[1]) * (ill->xyz[1] - smk->xyz[1])
1198
 
                                        + (ill->xyz[2] - smk->xyz[2]) * (ill->xyz[2] - smk->xyz[2]);
1199
 
                                if (distsquared < 640000.0f) {
1200
 
                                        temp = (640000.0f - distsquared) * 0.0000015625f;
1201
 
                                        temp = temp * temp * ill->bright;
1202
 
                                        smk->rgb[0] += temp * newrgb[0];
1203
 
                                        if (smk->rgb[0] > 1.0f)
1204
 
                                                smk->rgb[0] = 1.0f;
1205
 
                                        smk->rgb[1] += temp * newrgb[1];
1206
 
                                        if (smk->rgb[1] > 1.0f)
1207
 
                                                smk->rgb[1] = 1.0f;
1208
 
                                        smk->rgb[2] += temp * newrgb[2];
1209
 
                                        if (smk->rgb[2] > 1.0f)
1210
 
                                                smk->rgb[2] = 1.0f;
1211
 
                                }
1212
 
                        }
1213
 
                        smk++;
1214
 
                }
1215
 
 
1216
 
                // cloud illumination
1217
 
                if (dClouds) {
1218
 
                        int north, south, west, east;   // limits of cloud indices to inspect
1219
 
                        int halfmesh = CLOUDMESH / 2;
1220
 
                        float distsquared;
1221
 
 
1222
 
                        // remember clouds have 20000-foot radius from world.h, hence 0.00005
1223
 
                        // Hardcoded values like this are evil, but oh well
1224
 
                        south = int ((ill->xyz[2] - 1600.0f) * 0.00005f * float (halfmesh)) + halfmesh;
1225
 
                        north = int ((ill->xyz[2] + 1600.0f) * 0.00005f * float (halfmesh) + 0.5f) + halfmesh;
1226
 
                        west = int ((ill->xyz[0] - 1600.0f) * 0.00005f * float (halfmesh)) + halfmesh;
1227
 
                        east = int ((ill->xyz[0] + 1600.0f) * 0.00005f * float (halfmesh) + 0.5f) + halfmesh;
1228
 
 
1229
 
                        for (int i = west; i <= east; i++) {
1230
 
                                for (int j = south; j <= north; j++) {
1231
 
                                        distsquared = (clouds[i][j][0] - ill->xyz[0]) * (clouds[i][j][0] - ill->xyz[0])
1232
 
                                                + (clouds[i][j][1] - ill->xyz[1]) * (clouds[i][j][1] - ill->xyz[1])
1233
 
                                                + (clouds[i][j][2] - ill->xyz[2]) * (clouds[i][j][2] - ill->xyz[2]);
1234
 
                                        if (distsquared < 2560000.0f) {
1235
 
                                                temp = (2560000.0f - distsquared) * 0.000000390625f;
1236
 
                                                temp = temp * temp * ill->bright;
1237
 
                                                clouds[i][j][6] += temp * newrgb[0];
1238
 
                                                if (clouds[i][j][6] > 1.0f)
1239
 
                                                        clouds[i][j][6] = 1.0f;
1240
 
                                                clouds[i][j][7] += temp * newrgb[1];
1241
 
                                                if (clouds[i][j][7] > 1.0f)
1242
 
                                                        clouds[i][j][7] = 1.0f;
1243
 
                                                clouds[i][j][8] += temp * newrgb[2];
1244
 
                                                if (clouds[i][j][8] > 1.0f)
1245
 
                                                        clouds[i][j][8] = 1.0f;
1246
 
                                        }
1247
 
                                }
1248
 
                        }
1249
 
                }
1250
 
        }
1251
 
}
1252
 
 
1253
 
// pulling of other particles
1254
 
void pulling (particle * suck)
1255
 
{
1256
 
        rsVec diff;
1257
 
        float pulldistsquared;
1258
 
        float pullconst = (1.0f - suck->life) * 0.01f * elapsedTime;
1259
 
 
1260
 
        std::list < particle >::iterator puller = particles.begin ();
1261
 
        while (puller != particles.end ()) {
1262
 
                diff = suck->xyz - puller->xyz;
1263
 
                pulldistsquared = diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2];
1264
 
                if (pulldistsquared < 250000.0f && pulldistsquared != 0.0f && puller->type != SUCKER) {
1265
 
                        diff.normalize ();
1266
 
                        puller->vel += diff * ((250000.0f - pulldistsquared) * pullconst);
1267
 
                }
1268
 
 
1269
 
                puller++;
1270
 
        }
1271
 
}
1272
 
 
1273
 
// pushing of other particles
1274
 
void pushing (particle * shock)
1275
 
{
1276
 
        rsVec diff;
1277
 
        float pushdistsquared;
1278
 
        float pushconst = (1.0f - shock->life) * 0.002f * elapsedTime;
1279
 
 
1280
 
        std::list < particle >::iterator pusher = particles.begin ();
1281
 
        while (pusher != particles.end ()) {
1282
 
                diff = pusher->xyz - shock->xyz;
1283
 
                pushdistsquared = diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2];
1284
 
                if (pushdistsquared < 640000.0f && pushdistsquared != 0.0f && pusher->type != SHOCKWAVE) {
1285
 
                        diff.normalize ();
1286
 
                        pusher->vel += diff * ((640000.0f - pushdistsquared) * pushconst);
1287
 
                }
1288
 
 
1289
 
                pusher++;
1290
 
        }
1291
 
}
1292
 
 
1293
 
// vertical stretching of other particles (x, z sucking; y pushing)
1294
 
void stretching (particle * stretch)
1295
 
{
1296
 
        rsVec diff;
1297
 
        float stretchdistsquared, temp;
1298
 
        float stretchconst = (1.0f - stretch->life) * 0.002f * elapsedTime;
1299
 
 
1300
 
        std::list < particle >::iterator stretcher = particles.begin ();
1301
 
        while (stretcher != particles.end ()) {
1302
 
                diff = stretch->xyz - stretcher->xyz;
1303
 
                stretchdistsquared = diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2];
1304
 
                if (stretchdistsquared < 640000.0f && stretchdistsquared != 0.0f && stretcher->type != STRETCHER) {
1305
 
                        diff.normalize ();
1306
 
                        temp = (640000.0f - stretchdistsquared) * stretchconst;
1307
 
                        stretcher->vel[0] += diff[0] * temp * 5.0f;
1308
 
                        stretcher->vel[1] -= diff[1] * temp;
1309
 
                        stretcher->vel[2] += diff[2] * temp * 5.0f;
1310
 
                }
1311
 
 
1312
 
                stretcher++;
1313
 
        }
1314
 
}
1315
 
 
1316
 
//******************************************
1317
 
//  Update particles
1318
 
//******************************************
1319
 
void particle::update ()
1320
 
{
1321
 
        int i;
1322
 
        float temp;
1323
 
        static rsVec dir, crossvec, velvec, rocketEjection;
1324
 
        static rsQuat spinquat;
1325
 
        static rsMatrix spinmat;
1326
 
        particle *newp;
1327
 
 
1328
 
        // update velocities
1329
 
        if (type == ROCKET && life > endthrust) {
1330
 
                dir = vel;
1331
 
                dir.normalize ();
1332
 
                crossvec.cross (dir, tiltvec);  // correct sidevec
1333
 
                tiltvec.cross (crossvec, dir);
1334
 
                tiltvec.normalize ();
1335
 
                spinquat.make (spin * elapsedTime, dir[0], dir[1], dir[2]);     // twist tiltvec
1336
 
                spinmat.fromQuat (spinquat);
1337
 
                tiltvec.transVec (spinmat);
1338
 
                vel += dir * (thrust * elapsedTime);    // apply thrust
1339
 
                vel += tiltvec * (tilt * elapsedTime);  // apply tilt
1340
 
        }
1341
 
 
1342
 
        if (type == BEE) {
1343
 
                vel[0] += 800.0f * cos (tiltvec[0]) * elapsedTime;
1344
 
                vel[1] += 800.0f * (cos (tiltvec[1]) - 0.2f) * elapsedTime;
1345
 
                vel[2] += 800.0f * cos (tiltvec[2]) * elapsedTime;
1346
 
        } 
1347
 
 
1348
 
        if (type != SMOKE)
1349
 
                vel[1] -= elapsedTime * 32.0f;  // gravity
1350
 
 
1351
 
        // apply air resistance
1352
 
        temp = 1.0f / (1.0f + drag * elapsedTime);
1353
 
        //temp = temp * temp;
1354
 
        vel *= temp * temp;
1355
 
 
1356
 
        // update position
1357
 
        // (Fountains don't move)
1358
 
        if (type != FOUNTAIN) {
1359
 
                lastxyz = xyz;
1360
 
                xyz += vel * elapsedTime;
1361
 
                // Wind:  1/10 wind on ground; -1/2 wind at 500 feet; full wind at 2000 feet;
1362
 
                // This value is calculated to coincide with movement of the clouds in world.h
1363
 
                // Here's the polynomial wind equation that simulates windshear:
1364
 
                xyz[0] += (0.1f - 0.00175f * xyz[1] + 0.0000011f * xyz[1] * xyz[1]) * dWind * elapsedTime;
1365
 
        }
1366
 
 
1367
 
        // brightness and life
1368
 
        tr -= elapsedTime;
1369
 
        switch (type) {
1370
 
        case ROCKET:
1371
 
                life = tr / t;
1372
 
                if (life > endthrust) { // Light up rocket gradually after it is launched
1373
 
                        bright += 2.0f * elapsedTime;
1374
 
                        if (bright > 1.0f)
1375
 
                                bright = 1.0f;
1376
 
                } else {        // Darken rocket after it stops thrusting
1377
 
                        bright -= elapsedTime;
1378
 
                        if (bright < 0.0f)
1379
 
                                bright = 0.0f;
1380
 
                }
1381
 
                break;
1382
 
        case SMOKE:
1383
 
                life = tr / t;
1384
 
                bright = life * 0.7f;
1385
 
                size += (30.0f - size) * (1.2f * elapsedTime);
1386
 
                break;
1387
 
        case FOUNTAIN:
1388
 
        case SPINNER:
1389
 
                life = tr / t;
1390
 
                bright = life * life;
1391
 
                // dim newborn fountains and spinners
1392
 
                temp = t - tr;
1393
 
                if (temp < 0.5f)
1394
 
                        bright *= temp * 2.0f;
1395
 
                break;
1396
 
        case EXPLOSION:
1397
 
                life = tr / t;
1398
 
                bright = life * life;
1399
 
                break;
1400
 
        case STAR:
1401
 
        case STREAMER:
1402
 
        case METEOR:
1403
 
                temp = (t - tr) / t;
1404
 
                temp = temp * temp;
1405
 
                bright = 1.0f - (temp * temp);
1406
 
                life = bright;
1407
 
                break;
1408
 
        case POPPER:
1409
 
                life = tr;
1410
 
                break;
1411
 
        case BEE:
1412
 
                temp = (t - tr) / t;
1413
 
                temp = temp * temp;
1414
 
                bright = 1.0f - (temp * temp);
1415
 
                life = bright;
1416
 
                // Update bee acceleration (tiltvec) using misused variables
1417
 
                tiltvec[0] += thrust * elapsedTime;
1418
 
                tiltvec[1] += endthrust * elapsedTime;
1419
 
                tiltvec[2] += spin * elapsedTime;
1420
 
                break;
1421
 
        case SUCKER:
1422
 
                life = tr / t;
1423
 
                bright = life;
1424
 
                size = 250.0f * life;
1425
 
                break;
1426
 
        case SHOCKWAVE:
1427
 
                life = tr / t;
1428
 
                bright = life;
1429
 
                rgb[2] = life * 0.5f + 0.5f;    // get a little yellow
1430
 
                size += 400.0f * elapsedTime;
1431
 
                break;
1432
 
        case STRETCHER:
1433
 
                life = tr / t;
1434
 
                bright = 1.0f - ((1.0f - life) * (1.0f - life));
1435
 
                size = 400.0f * bright;
1436
 
                break;
1437
 
        case BIGMAMA:
1438
 
                life = tr / t;
1439
 
                bright = life * 2.0f - 1.0f;
1440
 
                if (bright < 0.0f)
1441
 
                        bright = 0.0f;
1442
 
                size += 1500.0f * elapsedTime;
1443
 
        }
1444
 
 
1445
 
        if (makeSmoke && dSmoke) {
1446
 
                rsVec diff = xyz - lastxyz;
1447
 
 
1448
 
                // distance rocket traveled since last frame
1449
 
                temp = diff.length ();
1450
 
                smokeTrailLength += temp;
1451
 
                // number of smoke puffs to release (1 every 2 feet)
1452
 
                int puffs = int (smokeTrailLength * 0.5f);
1453
 
                float multiplier = 2.0f / smokeTrailLength;
1454
 
                smokeTrailLength -= float (puffs) * 2.0f;
1455
 
                rsVec smkpos = lastxyz;
1456
 
 
1457
 
                if ((type == ROCKET) && (life > endthrust)) {   // eject the smoke forcefully
1458
 
                        rocketEjection = vel;
1459
 
                        rocketEjection.normalize ();
1460
 
                        rocketEjection *= -2.0f * thrust * (life - endthrust);
1461
 
                        for (i = 0; i < puffs; i++) {   // make puffs of smoke
1462
 
                                smkpos += diff * multiplier;
1463
 
                                newp = addParticle ();
1464
 
                                velvec[0] = rocketEjection[0] + rsRandf (20.0f) - 10.0f;
1465
 
                                velvec[1] = rocketEjection[1] + rsRandf (20.0f) - 10.0f;
1466
 
                                velvec[2] = rocketEjection[2] + rsRandf (20.0f) - 10.0f;
1467
 
                                newp->initSmoke (smkpos, velvec);
1468
 
                                newp->t = newp->tr = smokeTime[smokeTimeIndex];
1469
 
                                smokeTimeIndex++;
1470
 
                                if (smokeTimeIndex >= SMOKETIMES)
1471
 
                                        smokeTimeIndex = 0;
1472
 
                        }
1473
 
                } else {        // just form smoke in place
1474
 
                        for (i = 0; i < puffs; i++) {
1475
 
                                smkpos += diff * multiplier;
1476
 
                                newp = addParticle ();
1477
 
                                velvec[0] = rsRandf (20.0f) - 10.0f;
1478
 
                                velvec[1] = rsRandf (20.0f) - 10.0f;
1479
 
                                velvec[2] = rsRandf (20.0f) - 10.0f;
1480
 
                                newp->initSmoke (smkpos, velvec);
1481
 
                                newp->t = newp->tr = smokeTime[smokeTimeIndex];
1482
 
                                smokeTimeIndex++;
1483
 
                                if (smokeTimeIndex >= SMOKETIMES)
1484
 
                                        smokeTimeIndex = 0;
1485
 
                        }
1486
 
                }
1487
 
        }
1488
 
 
1489
 
        switch (type) {
1490
 
        case ROCKET:
1491
 
                // Sparks thrusting from rockets
1492
 
                if (life > endthrust) {
1493
 
                        rsVec diff = xyz - lastxyz;
1494
 
 
1495
 
                        // distance rocket traveled since last frame
1496
 
                        temp = diff.length ();
1497
 
                        sparkTrailLength += temp;
1498
 
                        // number of sparks to release
1499
 
                        int sparks = int (sparkTrailLength * 0.4f);
1500
 
                        sparkTrailLength -= float (sparks) * 2.5f;
1501
 
 
1502
 
                        rocketEjection = vel;
1503
 
                        rocketEjection.normalize ();
1504
 
                        rocketEjection *= -thrust * (life - endthrust);
1505
 
                        for (i = 0; i < sparks; i++) {  // make sparks
1506
 
                                newp = addParticle ();
1507
 
                                newp->initStar ();
1508
 
                                newp->xyz = xyz - (diff * rsRandf (1.0f));
1509
 
                                newp->vel[0] = rocketEjection[0] + rsRandf (60.0f) - 30.0f;
1510
 
                                newp->vel[1] = rocketEjection[1] + rsRandf (60.0f) - 30.0f;
1511
 
                                newp->vel[2] = rocketEjection[2] + rsRandf (60.0f) - 30.0f;
1512
 
                                newp->rgb = rgb;
1513
 
                                newp->t = rsRandf (0.2f) + 0.1f;
1514
 
                                newp->tr = newp->t;
1515
 
                                newp->size = 8.0f * life;
1516
 
                                newp->displayList = flarelist[3];
1517
 
                                newp->makeSmoke = 0;
1518
 
                        }
1519
 
                }
1520
 
                break;
1521
 
 
1522
 
        case FOUNTAIN: {
1523
 
                // Stars shooting up from fountain
1524
 
                // spew 10-20 particles per second at maximum brightness
1525
 
                sparkTrailLength += elapsedTime * bright * (rsRandf (10.0f) + 10.0f);
1526
 
                int stars = int (sparkTrailLength);
1527
 
                sparkTrailLength -= float(stars);
1528
 
 
1529
 
                for (i = 0; i < stars; i++) {
1530
 
                        newp = addParticle ();
1531
 
                        newp->initStar ();
1532
 
                        newp->drag = 0.342f;    // terminal velocity is 40 ft/s
1533
 
                        newp->xyz = xyz;
1534
 
                        newp->xyz[1] += rsRandf (elapsedTime * 100.0f);
1535
 
                        if (newp->xyz[1] > 50.0f)
1536
 
                                newp->xyz[1] = 50.0f;
1537
 
                        newp->vel.set (rsRandf (20.0f) - 10.0f, rsRandf (30.0f) + 100.0f, rsRandf (20.0f) - 10.0f);
1538
 
                        newp->size = 10.0f;
1539
 
                        newp->rgb = rgb;
1540
 
                        newp->makeSmoke = 0;
1541
 
                }
1542
 
 
1543
 
                }
1544
 
                break;
1545
 
 
1546
 
        case SPINNER: {
1547
 
                // Stars shooting out from spinner
1548
 
                dir.set (1.0f, 0.0f, 0.0f);
1549
 
                crossvec.cross (dir, tiltvec);
1550
 
                crossvec.normalize ();
1551
 
                crossvec *= 400.0f;
1552
 
                temp = spin * elapsedTime;      // radius of spin this frame
1553
 
                // spew 90-100 particles per second at maximum brightness
1554
 
                sparkTrailLength += elapsedTime * bright * (rsRandf (10.0f) + 90.0f);
1555
 
                int stars = int (sparkTrailLength);
1556
 
                sparkTrailLength -= float (stars);
1557
 
 
1558
 
                for (i = 0; i < stars; i++) {
1559
 
                        spinquat.make (tilt + rsRandf (temp), tiltvec[0], tiltvec[1], tiltvec[2]);
1560
 
                        spinquat.toMat (spinmat.m);
1561
 
                        newp = addParticle ();
1562
 
                        newp->initStar ();
1563
 
                        newp->xyz = xyz;
1564
 
                        newp->vel.set (vel[0] - (spinmat[0] * crossvec[0] + spinmat[4] * crossvec[1] + spinmat[8] * crossvec[2]) + rsRandf (20.0f) - 10.0f,
1565
 
                                       vel[1] - (spinmat[1] * crossvec[0] + spinmat[5] * crossvec[1] + spinmat[9] * crossvec[2]) + rsRandf (20.0f) - 10.0f,
1566
 
                                       vel[2] - (spinmat[2] * crossvec[0] + spinmat[6] * crossvec[1] + spinmat[10] * crossvec[2]) + rsRandf (20.0f) - 10.0f);
1567
 
                        newp->size = 15.0f;
1568
 
                        newp->rgb = rgb;
1569
 
                        newp->makeSmoke = 0;
1570
 
                        newp->t = newp->tr = rsRandf (0.5f) + 1.5f;
1571
 
                }
1572
 
                tilt += temp;
1573
 
 
1574
 
                }
1575
 
                break;
1576
 
 
1577
 
        case STREAMER: {
1578
 
                // trail from streamers
1579
 
                rsVec diff = xyz - lastxyz;
1580
 
 
1581
 
                // distance streamer traveled since last frame
1582
 
                sparkTrailLength += diff.length ();
1583
 
                // number of sparks to release each frame
1584
 
                int sparks = int (sparkTrailLength * 0.04f);
1585
 
                sparkTrailLength -= float (sparks) * 25.0f;
1586
 
 
1587
 
                for (i = 0; i < sparks; i++) {
1588
 
                        newp = addParticle ();
1589
 
                        newp->initStar ();
1590
 
                        newp->xyz = xyz - (diff * rsRandf (1.0f));
1591
 
                        newp->vel.set (vel[0] + rsRandf (80.0f) - 40.0f, vel[1] + rsRandf (80.0f) - 40.0f, vel[2] + rsRandf (80.0f) - 40.0f);
1592
 
                        newp->drag = 2.5f;
1593
 
                        newp->size = rsRandf (8.0f) + 4.0f;
1594
 
                        newp->rgb.set (1.0f, 0.8f, 0.6f);
1595
 
                        newp->t = rsRandf (2.0f) + 1.0f;
1596
 
                        newp->tr = newp->t;
1597
 
                        newp->makeSmoke = 0;
1598
 
                }
1599
 
 
1600
 
                }
1601
 
                break;
1602
 
 
1603
 
        case METEOR: {
1604
 
                // trail from meteors
1605
 
                rsVec diff = xyz - lastxyz;
1606
 
 
1607
 
                // distance rocket traveled since last frame
1608
 
                sparkTrailLength += diff.length ();
1609
 
                // number of smoke puffs to release
1610
 
                int stars = int (sparkTrailLength * 0.1f + 0.5f);
1611
 
                rsVec smkpos = lastxyz;
1612
 
 
1613
 
                // release star every 10 feet
1614
 
                float multiplier = 10.0f / sparkTrailLength;
1615
 
 
1616
 
                for (i = 0; i < stars; i++) {
1617
 
                        smkpos += diff * multiplier;
1618
 
                        newp = addParticle ();
1619
 
                        newp->initStar ();
1620
 
                        newp->xyz = smkpos;
1621
 
                        newp->vel.set (vel[0] + rsRandf (40.0f) - 20.0f, vel[1] + rsRandf (40.0f) - 20.0f, vel[2] + rsRandf (40.0f) - 20.0f);
1622
 
                        newp->rgb = rgb;
1623
 
                        newp->drag = 2.0f;
1624
 
                        newp->t = newp->tr = rsRandf (0.5f) + 1.5f;
1625
 
                        newp->size = 10.0f;
1626
 
                        newp->makeSmoke = 0;
1627
 
                }
1628
 
                sparkTrailLength -= float (stars) * 10.0f;
1629
 
 
1630
 
                }
1631
 
                break;
1632
 
 
1633
 
        case BEE: {
1634
 
                // trail from bees
1635
 
                rsVec diff = xyz - lastxyz;
1636
 
 
1637
 
                // distance rocket traveled since last frame
1638
 
                sparkTrailLength += diff.length ();
1639
 
                // number of smoke puffs to release
1640
 
                int stars = int (sparkTrailLength * 0.1f + 0.5f);
1641
 
                rsVec smkpos = lastxyz;
1642
 
 
1643
 
                // release star every 10 feet
1644
 
                float multiplier = 10.0f / sparkTrailLength;
1645
 
 
1646
 
                for (i = 0; i < stars; i++) {
1647
 
                        smkpos += diff * multiplier;
1648
 
                        newp = addParticle ();
1649
 
                        newp->initStar ();
1650
 
                        newp->xyz = smkpos;
1651
 
                        newp->vel.set (rsRandf (100.0f) - 50.0f - vel[0] * 0.5f, rsRandf (100.0f) - 50.0f - vel[1] * 0.5f, rsRandf (100.0f) - 50.0f - vel[2] * 0.5f);
1652
 
                        newp->rgb = rgb;
1653
 
                        newp->t = newp->tr = rsRandf (0.1f) + 0.15f;
1654
 
                        newp->size = 7.0f;
1655
 
                        newp->displayList = flarelist[3];
1656
 
                        newp->makeSmoke = 0;
1657
 
                }
1658
 
                sparkTrailLength -= float (stars) * 10.0f;
1659
 
 
1660
 
                }
1661
 
                break;
1662
 
 
1663
 
        case SUCKER:
1664
 
                // pulling of particles by suckers
1665
 
                pulling (this);
1666
 
                break;
1667
 
 
1668
 
        case SHOCKWAVE:
1669
 
                // pushing of particles by shockwaves
1670
 
                pushing (this);
1671
 
                break;
1672
 
 
1673
 
        case STRETCHER:
1674
 
                // stretching of particles by stretchers
1675
 
                stretching (this);
1676
 
        }
1677
 
 
1678
 
        // smoke and cloud illumination from rockets and explosions
1679
 
        if (dIllumination && ((type == ROCKET) || (type == FOUNTAIN) || (type == EXPLOSION)))
1680
 
                illuminate (this);
1681
 
}
1682
 
 
1683
 
void particle::draw ()
1684
 
{
1685
 
        if (life <= 0.0f)
1686
 
                return;         // don't draw dead particles
1687
 
 
1688
 
        // cull small particles that are behind camera
1689
 
        if (depth < 0.0f && type != SHOCKWAVE)
1690
 
                return;
1691
 
 
1692
 
        // don't draw invisible particles
1693
 
        if (type == POPPER)
1694
 
                return;
1695
 
 
1696
 
        glPushMatrix ();
1697
 
        glTranslatef (xyz[0], xyz[1], xyz[2]);
1698
 
 
1699
 
        if (type == SHOCKWAVE) {
1700
 
                glScalef (size, size, size);
1701
 
                drawShockwave (life, float (sqrt (size)) * 0.08f);
1702
 
 
1703
 
                if (life > 0.7f) {      // Big torus just for fun
1704
 
                        glMultMatrixd (billboardMat);
1705
 
                        glScalef (5.0f, 5.0f, 5.0f);
1706
 
                        glColor4f (1.0f, life, 1.0f, (life - 0.7f) * 3.333f);
1707
 
                        glCallList (flarelist[2]);
1708
 
                }
1709
 
                glPopMatrix ();
1710
 
                return;
1711
 
        }
1712
 
 
1713
 
        glScalef (size, size, size);
1714
 
        glMultMatrixd (billboardMat);
1715
 
        if (type == SMOKE) {
1716
 
                glColor4f (rgb[0], rgb[1], rgb[2], bright);
1717
 
                glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1718
 
                glCallList (displayList);
1719
 
        } else {
1720
 
                glBlendFunc (GL_SRC_ALPHA, GL_ONE);
1721
 
                if (type == EXPLOSION) {
1722
 
                        glColor4f (1.0f, 1.0f, 1.0f, bright);
1723
 
                        glScalef (bright, bright, bright);
1724
 
                        glCallList (displayList);
1725
 
                } else {
1726
 
                        glColor4f (rgb[0], rgb[1], rgb[2], bright);
1727
 
                        glCallList (displayList);
1728
 
                        glScalef (0.35f, 0.35f, 0.35f);
1729
 
                        glColor4f (1.0f, 1.0f, 1.0f, bright);
1730
 
                        glCallList (displayList);
1731
 
                }
1732
 
        }
1733
 
 
1734
 
        glPopMatrix ();
1735
 
}