2
* Copyright (C) 2002 Terence M. Welsh
3
* Ported to Linux by Tugrul Galatali <tugrul@galatali.com>
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.
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.
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
25
#include "rsDefines.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"
37
extern std::list < particle > particles;
38
extern particle *addParticle ();
41
extern int dExplosionsmoke;
45
extern int dIllumination;
47
extern float elapsedTime;
48
extern rsVec cameraPos; // used for positioning sounds
50
// skyrocket_world.cpp
51
extern float clouds[CLOUDMESH + 1][CLOUDMESH + 1][9];
53
// skyrocket_flare.cpp
54
extern unsigned int flarelist[4];
56
// skyrocket_smoke.cpp
57
extern float smokeTime[SMOKETIMES];
58
extern int whichSmoke[WHICHSMOKES];
59
extern unsigned int smokelist[5];
61
double billboardMat[16];
66
displayList = flarelist[0];
67
drag = 0.612f; // terminal velocity of 20 ft/s
76
smokeTrailLength = 0.0f;
77
sparkTrailLength = 0.0f;
81
rsVec particle::randomColor ()
83
int i = 0, j = 0, k = 0;
86
switch (rsRandi (6)) {
113
color[j] = rsRandf (1.0f);
114
color[k] = rsRandf (0.2f);
119
void particle::initRocket ()
122
//displayList = rocketlist;
123
xyz[0] = rsRandf (200.0f) - 100.0f;
125
xyz[2] = rsRandf (200.0f) - 100.0f;
129
vel.set (0.0f, 60.0f, 0.0f);
130
rgb.set (rsRandf (0.7f) + 0.3f, rsRandf (0.7f) + 0.3f, 0.3f);
132
drag = 0.281f; // terminal velocity of 50 ft/s
133
t = rsRandf (2.0f) + 5.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)));
141
tiltvec.set (cos (spin), 0.0f, sin (spin));
142
if (!rsRandi (200)) { // crash the occasional rocket
144
tilt = rsRandf (100.0f) + 75.0f;
145
float temp = rsRandf (PIx2);
147
tiltvec.set (cos (temp), 0.0f, sin (temp));
151
smokeTrailLength = 0.0f;
152
sparkTrailLength = 0.0f;
158
insertSoundNode (LAUNCH1SOUND, xyz, cameraPos);
160
insertSoundNode (LAUNCH2SOUND, xyz, cameraPos);
165
void particle::initFountain ()
168
displayList = flarelist[0];
170
// position can be defined here because these are always on the ground
171
xyz[0] = rsRandf (300.0f) - 150.0f;
173
xyz[2] = rsRandf (300.0f) - 150.0f;
174
rgb = randomColor ();
175
t = rsRandf (5.0f) + 10.0f;
183
insertSoundNode (LAUNCH1SOUND, xyz, cameraPos);
185
insertSoundNode (LAUNCH2SOUND, xyz, cameraPos);
190
void particle::initSpinner ()
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;
205
sparkTrailLength = 0.0f;
210
insertSoundNode (LAUNCH1SOUND, xyz, cameraPos);
212
insertSoundNode (LAUNCH2SOUND, xyz, cameraPos);
217
void particle::initSmoke (rsVec pos, rsVec speed)
220
displayList = smokelist[rsRandi (5)];
223
rgb[0] = rgb[1] = rgb[2] = 0.01f * float (dAmbient);
226
// time for each smoke particle varies and must be assigned by the particle that produces the smoke
231
void particle::initStar ()
234
displayList = flarelist[0];
235
drag = 0.612f; // terminal velocity of 20 ft/s
237
t = rsRandf (1.0f) + 2.0f;
239
static int someSmoke = 0;
241
makeSmoke = whichSmoke[someSmoke];
242
smokeTrailLength = 0.0f;
244
if (someSmoke >= WHICHSMOKES)
248
void particle::initStreamer ()
251
displayList = flarelist[0];
252
drag = 0.612f; // terminal velocity of 20 ft/s
254
t = rsRandf (1.0f) + 3.0f;
256
sparkTrailLength = 0.0f;
259
void particle::initMeteor ()
262
displayList = flarelist[0];
263
drag = 0.612f; // terminal velocity of 20 ft/s
264
t = rsRandf (1.0f) + 3.0f;
267
sparkTrailLength = 0.0f;
270
void particle::initStarPopper ()
273
displayList = flarelist[0];
275
t = rsRandf (1.5f) + 3.0f;
278
explosiontype = STAR;
280
smokeTrailLength = 0.0f;
283
void particle::initStreamerPopper ()
286
displayList = flarelist[0];
289
t = rsRandf (1.5f) + 3.0f;
292
explosiontype = STREAMER;
293
smokeTrailLength = 0.0f;
296
void particle::initMeteorPopper ()
299
displayList = flarelist[0];
302
t = rsRandf (1.5f) + 3.0f;
305
explosiontype = METEOR;
306
smokeTrailLength = 0.0f;
309
void particle::initLittlePopper ()
312
displayList = flarelist[0];
314
t = 4.0f * (0.5f - sin (rsRandf (PI))) + 4.5f;
316
size = rsRandf (3.0f) + 7.0f;
318
explosiontype = POPPER;
321
void particle::initBee ()
324
displayList = flarelist[0];
327
t = rsRandf (1.0f) + 2.5f;
330
sparkTrailLength = 0.0f;
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));
339
void particle::initSucker ()
344
float temp1, temp2, ch, sh, cp, sp;
347
drag = 0.612f; // terminal velocity of 20 ft/s
348
displayList = flarelist[2];
349
rgb.set (1.0f, 1.0f, 1.0f);
355
newp = addParticle ();
356
newp->type = EXPLOSION;
359
newp->rgb.set (1.0f, 1.0f, 1.0f);
361
newp->t = newp->tr = 4.0f;
363
// Make double ring to go along with sucker
364
color = randomColor ();
365
temp1 = rsRandf (PI); // heading
366
temp2 = rsRandf (PI); // pitch
371
for (i = 0; i < 90; i++) {
372
newp = addParticle ();
375
newp->vel[0] = rsRandf (1.0f) - 0.5f;
377
newp->vel[2] = rsRandf (1.0f) - 0.5f;
378
newp->vel.normalize ();
380
newp->vel[1] = sp * newp->vel[2];
381
newp->vel[2] = cp * newp->vel[2];
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];
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];
394
newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
397
color = randomColor ();
398
temp1 = rsRandf (PI); // heading
399
temp2 = rsRandf (PI); // pitch
404
for (i = 0; i < 90; i++) {
405
newp = addParticle ();
408
newp->vel[0] = rsRandf (1.0f) - 0.5f;
410
newp->vel[2] = rsRandf (1.0f) - 0.5f;
411
newp->vel.normalize ();
413
newp->vel[1] = sp * newp->vel[2];
414
newp->vel[2] = cp * newp->vel[2];
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];
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];
427
newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
433
insertSoundNode (SUCKSOUND, xyz, cameraPos);
437
void particle::initShockwave ()
444
drag = 0.612f; // terminal velocity of 20 ft/s
445
rgb.set (1.0f, 1.0f, 1.0f);
450
newp = addParticle ();
451
newp->type = EXPLOSION;
454
newp->rgb.set (1.0f, 1.0f, 1.0f);
456
newp->t = newp->tr = 3.0f;
459
// Little sphere without smoke
460
color = randomColor ();
461
for (i = 0; i < 75; i++) {
462
newp = addParticle ();
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);
473
newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
477
// Disk of stars without smoke
478
color = randomColor ();
479
for (i = 0; i < 150; i++) {
480
newp = addParticle ();
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 ();
489
newp->vel *= (rsRandf (30.0f) + 500.0f);
493
newp->t = newp->tr = rsRandf (2.0f) + 3.0f;
499
insertSoundNode (NUKESOUND, xyz, cameraPos);
503
void particle::initStretcher ()
510
drag = 0.612f; // terminal velocity of 20 ft/s
511
displayList = flarelist[3];
512
rgb.set (1.0f, 1.0f, 1.0f);
518
newp = addParticle ();
519
newp->type = EXPLOSION;
520
newp->displayList = flarelist[0];
523
newp->rgb.set (1.0f, 0.8f, 0.6f);
525
newp->t = newp->tr = 4.0f;
528
// Make triple ring to go along with stretcher
529
color = randomColor ();
530
for (i = 0; i < 80; i++) {
531
newp = addParticle ();
534
newp->vel[0] = rsRandf (1.0f) - 0.5f;
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];
545
newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
548
color = randomColor ();
549
for (i = 0; i < 80; i++) {
550
newp = addParticle ();
553
newp->vel[0] = rsRandf (1.0f) - 0.5f;
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];
564
newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
567
color = randomColor ();
568
for (i = 0; i < 80; i++) {
569
newp = addParticle ();
572
newp->vel[0] = rsRandf (1.0f) - 0.5f;
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];
583
newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
589
insertSoundNode (SUCKSOUND, xyz, cameraPos);
593
void particle::initBigmama ()
601
drag = 0.612f; // terminal velocity of 20 ft/s
602
displayList = flarelist[2];
603
rgb.set (0.6f, 0.6f, 1.0f);
609
newp = addParticle ();
610
newp->type = EXPLOSION;
614
newp->rgb.set (0.8f, 0.8f, 1.0f);
616
newp->t = newp->tr = 2.5f;
620
newp = addParticle ();
625
newp->vel[1] += 15.0f;
626
newp->rgb.set (1.0f, 1.0f, 0.9f);
628
newp->t = newp->tr = 3.0f;
630
newp = addParticle ();
635
newp->vel[1] -= 15.0f;
636
newp->rgb.set (1.0f, 1.0f, 0.9f);
638
newp->t = newp->tr = 3.0f;
640
newp = addParticle ();
645
newp->vel[1] += 45.0f;
646
newp->rgb.set (1.0f, 1.0f, 0.6f);
648
newp->t = newp->tr = 3.5f;
650
newp = addParticle ();
655
newp->vel[1] -= 45.0f;
656
newp->rgb.set (1.0f, 1.0f, 0.6f);
658
newp->t = newp->tr = 3.5f;
660
newp = addParticle ();
665
newp->vel[1] += 75.0f;
666
newp->rgb.set (1.0f, 0.5f, 0.3f);
668
newp->t = newp->tr = 4.0f;
670
newp = addParticle ();
675
newp->vel[1] -= 75.0f;
676
newp->rgb.set (1.0f, 0.5f, 0.3f);
678
newp->t = newp->tr = 4.0f;
680
newp = addParticle ();
685
newp->vel[1] += 105.0f;
686
newp->rgb.set (1.0f, 0.0f, 0.0f);
688
newp->t = newp->tr = 4.5f;
690
newp = addParticle ();
695
newp->vel[1] -= 105.0f;
696
newp->rgb.set (1.0f, 0.0f, 0.0f);
698
newp->t = newp->tr = 4.5f;
701
// Sphere without smoke
702
color = randomColor ();
703
for (i = 0; i < 75; i++) {
704
newp = addParticle ();
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];
719
newp->t = newp->tr = rsRandf (2.0f) + 2.0f;
723
// disk of big streamers
724
color = randomColor ();
725
for (i = 0; i < 50; i++) {
726
newp = addParticle ();
727
newp->initStreamer ();
730
newp->vel[0] = rsRandf (1.0f) - 0.5f;
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];
742
newp->t = newp->tr = rsRandf (6.0f) + 3.0f;
748
insertSoundNode (NUKESOUND, xyz, cameraPos);
752
void particle::initExplosion ()
755
displayList = flarelist[0];
764
// Don't do massive explosions too close to the ground
765
if ((explosiontype == 19 || explosiontype == 20) && (xyz[1] < 1000.0f))
768
switch (explosiontype) {
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);
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);
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);
791
rgb = randomColor ();
792
popRing (70, rsRandf (100.0f) + 400.0f, rgb);
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);
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);
804
case 6: // Sphere of streamers
805
rgb = randomColor ();
806
popStreamers (40, rsRandf (100.0f) + 400.0f, rgb);
808
case 7: // Sphere of meteors
809
rgb = randomColor ();
810
popMeteors (40, rsRandf (100.0f) + 400.0f, rgb);
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 ());
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 ());
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 ());
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 ());
832
case 12: // a few bombs that fall and explode into stars
833
rgb = randomColor ();
834
popStarPoppers (8, rsRandf (100.0f) + 300.0f, rgb);
836
case 13: // a few bombs that fall and explode into streamers
837
rgb = randomColor ();
838
popStreamerPoppers (8, rsRandf (100.0f) + 300.0f, rgb);
840
case 14: // a few bombs that fall and explode into meteors
841
rgb = randomColor ();
842
popMeteorPoppers (8, rsRandf (100.0f) + 300.0f, rgb);
844
case 15: // lots of little falling firecrackers
845
popLittlePoppers (250, rsRandf (50.0f) + 150.0f);
848
rgb = randomColor ();
849
popBees (30, 10.0f, rgb);
851
case 17: // Boom! (loud noise and flash of light)
852
rgb.set (1.0f, 1.0f, 1.0f);
855
// 18 is a spinner, which doesn't require explosion
857
rgb.set (1.0f, 1.0f, 1.0f);
861
rgb.set (1.0f, 1.0f, 1.0f);
864
case 100: // these three are little explosions for poppers
865
popSphere (30, 100.0f, rgb);
868
popStreamers (10, 100.0f, rgb);
871
popMeteors (10, 100.0f, rgb);
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)
881
insertSoundNode (WHISTLESOUND, xyz, cameraPos);
883
if (explosiontype <= 16 || explosiontype >= 100)
884
insertSoundNode (BOOM1SOUND + rsRandi (3), xyz, cameraPos);
885
// sucker and stretcher take care of their own sounds
890
void particle::popSphere (int numParts, float v0, rsVec color)
892
particle *newp = NULL;
895
for (int i = 0; i < numParts; i++) {
896
newp = addParticle ();
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);
910
newp->t = newp->tr = rsRandf (20.0f) + 5.0f;
913
void particle::popSplitSphere (int numParts, float v0, rsVec color1)
915
particle *newp = NULL;
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 ();
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)
937
temp = v0 + rsRandf (50.0f);
943
newp->t = newp->tr = rsRandf (20.0f) + 5.0f;
946
void particle::popMultiColorSphere (int numParts, float v0)
949
particle *newp = NULL;
953
color[0] = randomColor ();
954
color[1] = randomColor ();
955
color[2] = randomColor ();
957
for (int i = 0; i < numParts; i++) {
958
newp = addParticle ();
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);
968
newp->rgb = color[j];
975
newp->t = newp->tr = rsRandf (20.0f) + 5.0f;
978
void particle::popRing (int numParts, float v0, rsVec color)
980
particle *newp = NULL;
982
float ch, sh, cp, sp;
984
temp1 = rsRandf (PI); // heading
985
temp2 = rsRandf (PI); // pitch
990
for (int i = 0; i < numParts; i++) {
991
newp = addParticle ();
994
newp->vel[0] = rsRandf (1.0f) - 0.5f;
996
newp->vel[2] = rsRandf (1.0f) - 0.5f;
997
newp->vel.normalize ();
999
newp->vel[1] = sp * newp->vel[2];
1000
newp->vel[2] = cp * newp->vel[2];
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);
1014
newp->t = newp->tr = rsRandf (20.0f) + 5.0f;
1017
void particle::popStreamers (int numParts, float v0, rsVec color)
1019
particle *newp = NULL;
1022
for (int i = 0; i < numParts; i++) {
1023
newp = addParticle ();
1024
newp->initStreamer ();
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);
1037
void particle::popMeteors (int numParts, float v0, rsVec color)
1039
particle *newp = NULL;
1042
for (int i = 0; i < numParts; i++) {
1043
newp = addParticle ();
1044
newp->initMeteor ();
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);
1057
void particle::popStarPoppers (int numParts, float v0, rsVec color)
1059
particle *newp = NULL;
1060
float v0x2 = v0 * 2;
1062
for (int i = 0; i < numParts; i++) {
1063
newp = addParticle ();
1064
newp->initStarPopper ();
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;
1073
void particle::popStreamerPoppers (int numParts, float v0, rsVec color)
1075
particle *newp = NULL;
1076
float v0x2 = v0 * 2;
1078
for (int i = 0; i < numParts; i++) {
1079
newp = addParticle ();
1080
newp->initStreamerPopper ();
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;
1089
void particle::popMeteorPoppers (int numParts, float v0, rsVec color)
1093
float v0x2 = v0 * 2;
1095
for (i = 0; i < numParts; i++) {
1096
newp = addParticle ();
1097
newp->initMeteorPopper ();
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;
1106
void particle::popLittlePoppers (int numParts, float v0)
1108
particle *newp = NULL;
1109
float v0x2 = v0 * 2;
1111
for (int i = 0; i < numParts; i++) {
1112
newp = addParticle ();
1113
newp->initLittlePopper ();
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;
1122
insertSoundNode (POPPERSOUND, xyz, cameraPos);
1126
void particle::popBees (int numParts, float v0, rsVec color)
1128
particle *newp = NULL;
1130
for (int i = 0; i < numParts; i++) {
1131
newp = addParticle ();
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;
1143
void particle::findDepth ()
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]);
1156
// Rockets and explosions illuminate smoke
1157
// Only explosions illuminate clouds
1158
void illuminate (particle * ill)
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 };
1164
// Smoke illumination
1165
if ((ill->type == ROCKET) || (ill->type == FOUNTAIN)) {
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)
1180
smk->rgb[1] += temp * newrgb[1];
1181
if (smk->rgb[1] > 1.0f)
1183
smk->rgb[2] += temp * newrgb[2];
1184
if (smk->rgb[2] > 1.0f)
1190
} else if (ill->type == EXPLOSION) {
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)
1205
smk->rgb[1] += temp * newrgb[1];
1206
if (smk->rgb[1] > 1.0f)
1208
smk->rgb[2] += temp * newrgb[2];
1209
if (smk->rgb[2] > 1.0f)
1216
// cloud illumination
1218
int north, south, west, east; // limits of cloud indices to inspect
1219
int halfmesh = CLOUDMESH / 2;
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;
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;
1253
// pulling of other particles
1254
void pulling (particle * suck)
1257
float pulldistsquared;
1258
float pullconst = (1.0f - suck->life) * 0.01f * elapsedTime;
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) {
1266
puller->vel += diff * ((250000.0f - pulldistsquared) * pullconst);
1273
// pushing of other particles
1274
void pushing (particle * shock)
1277
float pushdistsquared;
1278
float pushconst = (1.0f - shock->life) * 0.002f * elapsedTime;
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) {
1286
pusher->vel += diff * ((640000.0f - pushdistsquared) * pushconst);
1293
// vertical stretching of other particles (x, z sucking; y pushing)
1294
void stretching (particle * stretch)
1297
float stretchdistsquared, temp;
1298
float stretchconst = (1.0f - stretch->life) * 0.002f * elapsedTime;
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) {
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;
1316
//******************************************
1318
//******************************************
1319
void particle::update ()
1323
static rsVec dir, crossvec, velvec, rocketEjection;
1324
static rsQuat spinquat;
1325
static rsMatrix spinmat;
1328
// update velocities
1329
if (type == ROCKET && life > endthrust) {
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
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;
1349
vel[1] -= elapsedTime * 32.0f; // gravity
1351
// apply air resistance
1352
temp = 1.0f / (1.0f + drag * elapsedTime);
1353
//temp = temp * temp;
1357
// (Fountains don't move)
1358
if (type != FOUNTAIN) {
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;
1367
// brightness and life
1372
if (life > endthrust) { // Light up rocket gradually after it is launched
1373
bright += 2.0f * elapsedTime;
1376
} else { // Darken rocket after it stops thrusting
1377
bright -= elapsedTime;
1384
bright = life * 0.7f;
1385
size += (30.0f - size) * (1.2f * elapsedTime);
1390
bright = life * life;
1391
// dim newborn fountains and spinners
1394
bright *= temp * 2.0f;
1398
bright = life * life;
1403
temp = (t - tr) / t;
1405
bright = 1.0f - (temp * temp);
1412
temp = (t - tr) / t;
1414
bright = 1.0f - (temp * temp);
1416
// Update bee acceleration (tiltvec) using misused variables
1417
tiltvec[0] += thrust * elapsedTime;
1418
tiltvec[1] += endthrust * elapsedTime;
1419
tiltvec[2] += spin * elapsedTime;
1424
size = 250.0f * life;
1429
rgb[2] = life * 0.5f + 0.5f; // get a little yellow
1430
size += 400.0f * elapsedTime;
1434
bright = 1.0f - ((1.0f - life) * (1.0f - life));
1435
size = 400.0f * bright;
1439
bright = life * 2.0f - 1.0f;
1442
size += 1500.0f * elapsedTime;
1445
if (makeSmoke && dSmoke) {
1446
rsVec diff = xyz - lastxyz;
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;
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];
1470
if (smokeTimeIndex >= SMOKETIMES)
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];
1483
if (smokeTimeIndex >= SMOKETIMES)
1491
// Sparks thrusting from rockets
1492
if (life > endthrust) {
1493
rsVec diff = xyz - lastxyz;
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;
1502
rocketEjection = vel;
1503
rocketEjection.normalize ();
1504
rocketEjection *= -thrust * (life - endthrust);
1505
for (i = 0; i < sparks; i++) { // make sparks
1506
newp = addParticle ();
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;
1513
newp->t = rsRandf (0.2f) + 0.1f;
1515
newp->size = 8.0f * life;
1516
newp->displayList = flarelist[3];
1517
newp->makeSmoke = 0;
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);
1529
for (i = 0; i < stars; i++) {
1530
newp = addParticle ();
1532
newp->drag = 0.342f; // terminal velocity is 40 ft/s
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);
1540
newp->makeSmoke = 0;
1547
// Stars shooting out from spinner
1548
dir.set (1.0f, 0.0f, 0.0f);
1549
crossvec.cross (dir, tiltvec);
1550
crossvec.normalize ();
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);
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 ();
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);
1569
newp->makeSmoke = 0;
1570
newp->t = newp->tr = rsRandf (0.5f) + 1.5f;
1578
// trail from streamers
1579
rsVec diff = xyz - lastxyz;
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;
1587
for (i = 0; i < sparks; i++) {
1588
newp = addParticle ();
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);
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;
1597
newp->makeSmoke = 0;
1604
// trail from meteors
1605
rsVec diff = xyz - lastxyz;
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;
1613
// release star every 10 feet
1614
float multiplier = 10.0f / sparkTrailLength;
1616
for (i = 0; i < stars; i++) {
1617
smkpos += diff * multiplier;
1618
newp = addParticle ();
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);
1624
newp->t = newp->tr = rsRandf (0.5f) + 1.5f;
1626
newp->makeSmoke = 0;
1628
sparkTrailLength -= float (stars) * 10.0f;
1635
rsVec diff = xyz - lastxyz;
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;
1643
// release star every 10 feet
1644
float multiplier = 10.0f / sparkTrailLength;
1646
for (i = 0; i < stars; i++) {
1647
smkpos += diff * multiplier;
1648
newp = addParticle ();
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);
1653
newp->t = newp->tr = rsRandf (0.1f) + 0.15f;
1655
newp->displayList = flarelist[3];
1656
newp->makeSmoke = 0;
1658
sparkTrailLength -= float (stars) * 10.0f;
1664
// pulling of particles by suckers
1669
// pushing of particles by shockwaves
1674
// stretching of particles by stretchers
1678
// smoke and cloud illumination from rockets and explosions
1679
if (dIllumination && ((type == ROCKET) || (type == FOUNTAIN) || (type == EXPLOSION)))
1683
void particle::draw ()
1686
return; // don't draw dead particles
1688
// cull small particles that are behind camera
1689
if (depth < 0.0f && type != SHOCKWAVE)
1692
// don't draw invisible particles
1697
glTranslatef (xyz[0], xyz[1], xyz[2]);
1699
if (type == SHOCKWAVE) {
1700
glScalef (size, size, size);
1701
drawShockwave (life, float (sqrt (size)) * 0.08f);
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]);
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);
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);
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);