Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Particles.cpp
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: nGenEx.lib
6  FILE: Particles.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Particle Burst class
13 */
14 
15 #include "MemDebug.h"
16 #include "Particles.h"
17 #include "Projector.h"
18 #include "Light.h"
19 #include "Bitmap.h"
20 #include "Game.h"
21 #include "Random.h"
22 
23 // +--------------------------------------------------------------------+
24 
25 inline float randf() { return (rand()-16384.0f)/32768.0f; }
26 
27 // +--------------------------------------------------------------------+
28 
29 Particles::Particles(Bitmap* bitmap, int np, const Vec3& base_loc, const Vec3& vel,
30 float bspeed, float dr, float s, float bloom, float dec, float rate,
31 bool cont, bool trail, bool rise, int a, int nframes)
32 : nparts(np), base_speed(bspeed), max_speed(bspeed*3.0f),
33 drag(dr), min_scale(s), max_scale(bloom), decay(dec),
34 release_rate(rate), continuous(cont), trailing(trail), rising(rise),
35 blend(a), extra(0.0f), point_sprite(0), emitting(true)
36 {
37  MoveTo(base_loc);
38  ref_loc = base_loc;
39 
40  trans = true;
41  luminous = true;
42  shadow = false;
43  nverts = nparts;
44 
45  if (max_scale < min_scale)
47 
48  velocity = new(__FILE__,__LINE__) Point[nverts];
49  part_loc = new(__FILE__,__LINE__) Point[nverts];
50  release = new(__FILE__,__LINE__) Point[nverts];
51  intensity = new(__FILE__,__LINE__) float[nverts];
52  timestamp = new(__FILE__,__LINE__) float[nverts];
53  scale = new(__FILE__,__LINE__) float[nverts];
54  angle = new(__FILE__,__LINE__) float[nverts];
55  frame = new(__FILE__,__LINE__) BYTE[nverts];
56 
57  float speed = base_speed;
58 
59  for (int i = 0; i < nverts; i++) {
60  intensity[i] = 1.0f;
61  timestamp[i] = (float) (Game::GameTime() / 1000.0);
62  scale[i] = (float) (min_scale);
63  angle[i] = (float) (Random(0, 2*PI));
64  frame[i] = 0;
65 
66  part_loc[i] = Point();
67  release[i] = ref_loc;
68  velocity[i] = RandomVector(speed);
69  velocity[i] += vel;
70 
71  if (speed < max_speed)
72  speed += (float) Random(max_speed/15.0, max_speed/5.0);
73  else
74  speed = base_speed;
75  }
76 
77  radius = 15000.0f;
78 
79  if (decay > 2)
80  decay /= 256.0f;
81 
82  if (nparts < 8) {
83  nverts = 1;
84  }
85 
86  else if (nparts > 50 || continuous) {
87  nverts = (int) (nparts * 0.125 * release_rate);
88  }
89 
90  point_sprite = new(__FILE__,__LINE__) Sprite(bitmap, nframes);
91  point_sprite->Scale(s);
93  point_sprite->SetFrameRate(nframes * decay);
94 }
95 
97 {
98  delete point_sprite;
99  delete [] velocity;
100  delete [] part_loc;
101  delete [] release;
102  delete [] timestamp;
103  delete [] intensity;
104  delete [] scale;
105  delete [] angle;
106  delete [] frame;
107 }
108 
109 // +--------------------------------------------------------------------+
110 
111 void Particles::ExecFrame(double seconds)
112 {
113  point_sprite->Update();
114 
115  ref_loc = loc;
116  radius += max_speed * (float) seconds;
117 
118  float scaled_drag = (float) exp(-drag * seconds);
119  float scale_inc = (float) ((max_scale-min_scale)*seconds*2);
120 
121  for (int i = 0; i < nverts; i++) {
122  part_loc[i] += velocity[i] * (float) seconds;
123 
124  if (rising) {
125  part_loc[i].y += (float) ((randf() + 1) * scale[i] * 80 * seconds);
126  }
127 
128  // do the (chunky) blooming effect:
129  if (max_scale > 0 && scale[i] < max_scale) {
130  scale[i] += scale_inc * (float) ((i%3)/3.0);
131  }
132 
133  double rho = angle[i];
134  int rot = i%4;
135  switch (rot) {
136  case 0: rho += seconds * 0.13; break;
137  case 1: rho -= seconds * 0.11; break;
138  case 2: rho += seconds * 0.09; break;
139  case 3: rho -= seconds * 0.07; break;
140  default: break;
141  }
142 
143  angle[i] = (float) rho;
144  intensity[i] -= (float) (decay * seconds);
145 
146  if (point_sprite->NumFrames() > 1) {
147  double age = Game::GameTime()/1000.0 - timestamp[i];
148  int n = (int) (age * point_sprite->FrameRate());
149 
150  if (n >= point_sprite->NumFrames())
151  n = point_sprite->NumFrames() - 1;
152 
153  frame[i] = n;
154  }
155 
156  velocity[i] *= scaled_drag;
157  }
158 
159  if (nverts < nparts && emitting) {
160  int nv = nverts;
161  double delta = nparts * release_rate * seconds;
162  int new_parts = (int) (delta + extra);
163  extra = (float) (delta + extra - new_parts);
164  nverts += new_parts;
165 
166  if (nverts > nparts)
167  nverts = nparts;
168 
169  for (int i = nv; i < nverts; i++) {
170  intensity[i] = 1;
171  timestamp[i] = (float) (Game::GameTime() / 1000.0);
172  scale[i] = (float) (min_scale);
173  angle[i] = (float) (Random(0, 2*PI));
174  frame[i] = 0;
175  part_loc[i] = Point();
176  release[i] = ref_loc;
177  }
178  }
179 
180  if (nverts > nparts)
181  nverts = nparts;
182 
183  // recycle dead particles:
184  if (continuous) {
185  float speed = base_speed;
186 
187  for (int i = 0; i < nverts; i++) {
188  if (intensity[i] <= 0) {
189  part_loc[i] = Point();
190  release[i] = ref_loc;
191 
192  intensity[i] = 1;
193  timestamp[i] = (float) (Game::GameTime() / 1000.0);
194  scale[i] = (float) (min_scale);
195  angle[i] = (float) (PI * rand() / 16384.0);
196  frame[i] = 0;
197  velocity[i] = RandomVector(speed);
198 
199  if (speed < max_speed)
200  speed += (float) Random(max_speed/25.0, max_speed/18.0);
201  else
202  speed = base_speed;
203  }
204  }
205  }
206 }
207 
208 // +--------------------------------------------------------------------+
209 
210 bool
212 {
213  float base = 256;
214 
215  if (point_sprite && point_sprite->Frame())
216  base = (float) point_sprite->Frame()->Width();
217 
218  float particle_radius = base * max_scale;
219 
220  if (projector.IsVisible( Location(), Radius()) &&
221  projector.ApparentRadius(Location(), particle_radius) > 1) {
222 
223  visible = true;
224  }
225  else {
226  visible = false;
227  }
228 
229  return visible;
230 }
231 
232 // +--------------------------------------------------------------------+
233 
234 void
235 Particles::Render(Video* video, DWORD flags)
236 {
237  if (hidden || !visible || !video || !point_sprite)
238  return;
239 
240  if (blend == 2 && !(flags & Graphic::RENDER_ALPHA))
241  return;
242 
243  if (blend == 4 && !(flags & Graphic::RENDER_ADDITIVE))
244  return;
245 
246  for (int i = 0; i < nverts; i++) {
247  Point vloc;
248 
249  if (trailing) {
250  vloc = part_loc[i] + release[i] - offset;
251  }
252  else {
253  vloc = part_loc[i] + loc;
254  }
255 
256  point_sprite->MoveTo(vloc);
261 
262  point_sprite->Render(video, flags);
263  }
264 }