summaryrefslogtreecommitdiffhomepage
path: root/Stars45/Particles.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Stars45/Particles.cpp')
-rw-r--r--Stars45/Particles.cpp288
1 files changed, 288 insertions, 0 deletions
diff --git a/Stars45/Particles.cpp b/Stars45/Particles.cpp
new file mode 100644
index 0000000..a8efbec
--- /dev/null
+++ b/Stars45/Particles.cpp
@@ -0,0 +1,288 @@
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ All Rights Reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name "Destroyer Studios" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ SUBSYSTEM: nGenEx.lib
+ FILE: Particles.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Particle Burst class
+*/
+
+#include "MemDebug.h"
+#include "Particles.h"
+#include "Projector.h"
+#include "Light.h"
+#include "Bitmap.h"
+#include "Game.h"
+#include "Random.h"
+
+// +--------------------------------------------------------------------+
+
+inline float randf() { return (rand()-16384.0f)/32768.0f; }
+
+// +--------------------------------------------------------------------+
+
+Particles::Particles(Bitmap* bitmap, int np, const Vec3& base_loc, const Vec3& vel,
+float bspeed, float dr, float s, float bloom, float dec, float rate,
+bool cont, bool trail, bool rise, int a, int nframes)
+: nparts(np), base_speed(bspeed), max_speed(bspeed*3.0f),
+drag(dr), min_scale(s), max_scale(bloom), decay(dec),
+release_rate(rate), continuous(cont), trailing(trail), rising(rise),
+blend(a), extra(0.0f), point_sprite(0), emitting(true)
+{
+ MoveTo(base_loc);
+ ref_loc = base_loc;
+
+ trans = true;
+ luminous = true;
+ shadow = false;
+ nverts = nparts;
+
+ if (max_scale < min_scale)
+ max_scale = min_scale;
+
+ velocity = new(__FILE__,__LINE__) Point[nverts];
+ part_loc = new(__FILE__,__LINE__) Point[nverts];
+ release = new(__FILE__,__LINE__) Point[nverts];
+ intensity = new(__FILE__,__LINE__) float[nverts];
+ timestamp = new(__FILE__,__LINE__) float[nverts];
+ scale = new(__FILE__,__LINE__) float[nverts];
+ angle = new(__FILE__,__LINE__) float[nverts];
+ frame = new(__FILE__,__LINE__) BYTE[nverts];
+
+ float speed = base_speed;
+
+ for (int i = 0; i < nverts; i++) {
+ intensity[i] = 1.0f;
+ timestamp[i] = (float) (Game::GameTime() / 1000.0);
+ scale[i] = (float) (min_scale);
+ angle[i] = (float) (Random(0, 2*PI));
+ frame[i] = 0;
+
+ part_loc[i] = Point();
+ release[i] = ref_loc;
+ velocity[i] = RandomVector(speed);
+ velocity[i] += vel;
+
+ if (speed < max_speed)
+ speed += (float) Random(max_speed/15.0, max_speed/5.0);
+ else
+ speed = base_speed;
+ }
+
+ radius = 15000.0f;
+
+ if (decay > 2)
+ decay /= 256.0f;
+
+ if (nparts < 8) {
+ nverts = 1;
+ }
+
+ else if (nparts > 50 || continuous) {
+ nverts = (int) (nparts * 0.125 * release_rate);
+ }
+
+ point_sprite = new(__FILE__,__LINE__) Sprite(bitmap, nframes);
+ point_sprite->Scale(s);
+ point_sprite->SetBlendMode(blend);
+ point_sprite->SetFrameRate(nframes * decay);
+}
+
+Particles::~Particles()
+{
+ delete point_sprite;
+ delete [] velocity;
+ delete [] part_loc;
+ delete [] release;
+ delete [] timestamp;
+ delete [] intensity;
+ delete [] scale;
+ delete [] angle;
+ delete [] frame;
+}
+
+// +--------------------------------------------------------------------+
+
+void Particles::ExecFrame(double seconds)
+{
+ point_sprite->Update();
+
+ ref_loc = loc;
+ radius += max_speed * (float) seconds;
+
+ float scaled_drag = (float) exp(-drag * seconds);
+ float scale_inc = (float) ((max_scale-min_scale)*seconds*2);
+
+ for (int i = 0; i < nverts; i++) {
+ part_loc[i] += velocity[i] * (float) seconds;
+
+ if (rising) {
+ part_loc[i].y += (float) ((randf() + 1) * scale[i] * 80 * seconds);
+ }
+
+ // do the (chunky) blooming effect:
+ if (max_scale > 0 && scale[i] < max_scale) {
+ scale[i] += scale_inc * (float) ((i%3)/3.0);
+ }
+
+ double rho = angle[i];
+ int rot = i%4;
+ switch (rot) {
+ case 0: rho += seconds * 0.13; break;
+ case 1: rho -= seconds * 0.11; break;
+ case 2: rho += seconds * 0.09; break;
+ case 3: rho -= seconds * 0.07; break;
+ default: break;
+ }
+
+ angle[i] = (float) rho;
+ intensity[i] -= (float) (decay * seconds);
+
+ if (point_sprite->NumFrames() > 1) {
+ double age = Game::GameTime()/1000.0 - timestamp[i];
+ int n = (int) (age * point_sprite->FrameRate());
+
+ if (n >= point_sprite->NumFrames())
+ n = point_sprite->NumFrames() - 1;
+
+ frame[i] = n;
+ }
+
+ velocity[i] *= scaled_drag;
+ }
+
+ if (nverts < nparts && emitting) {
+ int nv = nverts;
+ double delta = nparts * release_rate * seconds;
+ int new_parts = (int) (delta + extra);
+ extra = (float) (delta + extra - new_parts);
+ nverts += new_parts;
+
+ if (nverts > nparts)
+ nverts = nparts;
+
+ for (int i = nv; i < nverts; i++) {
+ intensity[i] = 1;
+ timestamp[i] = (float) (Game::GameTime() / 1000.0);
+ scale[i] = (float) (min_scale);
+ angle[i] = (float) (Random(0, 2*PI));
+ frame[i] = 0;
+ part_loc[i] = Point();
+ release[i] = ref_loc;
+ }
+ }
+
+ if (nverts > nparts)
+ nverts = nparts;
+
+ // recycle dead particles:
+ if (continuous) {
+ float speed = base_speed;
+
+ for (int i = 0; i < nverts; i++) {
+ if (intensity[i] <= 0) {
+ part_loc[i] = Point();
+ release[i] = ref_loc;
+
+ intensity[i] = 1;
+ timestamp[i] = (float) (Game::GameTime() / 1000.0);
+ scale[i] = (float) (min_scale);
+ angle[i] = (float) (PI * rand() / 16384.0);
+ frame[i] = 0;
+ velocity[i] = RandomVector(speed);
+
+ if (speed < max_speed)
+ speed += (float) Random(max_speed/25.0, max_speed/18.0);
+ else
+ speed = base_speed;
+ }
+ }
+ }
+}
+
+// +--------------------------------------------------------------------+
+
+bool
+Particles::CheckVisibility(Projector& projector)
+{
+ float base = 256;
+
+ if (point_sprite && point_sprite->Frame())
+ base = (float) point_sprite->Frame()->Width();
+
+ float particle_radius = base * max_scale;
+
+ if (projector.IsVisible( Location(), Radius()) &&
+ projector.ApparentRadius(Location(), particle_radius) > 1) {
+
+ visible = true;
+ }
+ else {
+ visible = false;
+ }
+
+ return visible;
+}
+
+// +--------------------------------------------------------------------+
+
+void
+Particles::Render(Video* video, DWORD flags)
+{
+ if (hidden || !visible || !video || !point_sprite)
+ return;
+
+ if (blend == 2 && !(flags & Graphic::RENDER_ALPHA))
+ return;
+
+ if (blend == 4 && !(flags & Graphic::RENDER_ADDITIVE))
+ return;
+
+ for (int i = 0; i < nverts; i++) {
+ Point vloc;
+
+ if (trailing) {
+ vloc = part_loc[i] + release[i] - offset;
+ }
+ else {
+ vloc = part_loc[i] + loc;
+ }
+
+ point_sprite->MoveTo(vloc);
+ point_sprite->SetShade(intensity[i]);
+ point_sprite->Rescale(scale[i]);
+ point_sprite->SetAngle(angle[i]);
+ point_sprite->SetFrameIndex(frame[i]);
+
+ point_sprite->Render(video, flags);
+ }
+}