Logo Search packages:      
Sourcecode: barrage version File versions  Download package

particle.c

/***************************************************************************
    copyright            : (C) 2003 by Michael Speck
    email                : http://lgames.sf.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "particle.h"

Particle particles[MAX_PARTICLES];
int particle_count = 0;
Emitter emitters[MAX_EMITTERS];
int emitter_count = 0;

extern SDL_Surface *img_particles;

static Vector wind = { -0.005, 0, 0 };
static Vector grav = { 0, 0, -GRAV };


static void particle_add( Particle *particle )
{
    if (particle_count >= MAX_PARTICLES) return;
    
    particles[particle_count] = *particle;
    particle_count++;
}

static void particle_delete( int index )
{
    if (particle_count == 0) return;
    
    particles[index] = particles[particle_count-1];
    particle_count--;
}

static void emitter_delete( int index )
{
    if (emitter_count == 0) return;
    
    emitters[index] = emitters[emitter_count-1];
    emitter_count--;
}

void particles_clear()
{
      emitter_count = 0;
      particle_count = 0;
}

void particles_draw( SDL_Surface *dest, int camera_x, int camera_y )
{
      Particle *part;
      SDL_Rect srect, drect;
      int i;

      for (i = 0; i < particle_count; i++) {
            part = &particles[i];
            
            srect.x = part->img_x_offset + part->frame_id*part->w;
            srect.y = part->img_y_offset;
            drect.x = (int)part->pos.x - camera_x;
            drect.y = (int)part->pos.y - ((int)part->pos.z>>1) - camera_y;
            srect.w = drect.w = part->w;
            srect.h = drect.h = part->h;

            /* add in camera check? */
            
            SDL_SetAlpha( part->img, SDL_SRCALPHA | SDL_RLEACCEL, (int)part->alpha );
            
            SDL_BlitSurface( part->img, &srect, dest, &drect );
      }
}

void particles_update( int ms )
{
      Emitter *emit;
      Particle *part;
      int i, dens;

      /* emitters */
      for ( i = 0; i < emitter_count; i++ ) {
            emit = &emitters[i];

            emit->count += emit->rate * ms;
            dens = emit->count;
            if ( dens > 0 ) {
                  emit->count -= dens;
                  switch (emit->type ) {
                        case PT_FIRE:
                              particles_set_fire( emit->x, emit->y, emit->radius, dens );
                              break;
                        case PT_SMOKE:
                              particles_set_smoke( emit->x, emit->y, emit->radius, dens );
                              break;
                  }
            }

            if ( emit->lifespan > 0 ) {
                  emit->lifespan -= ms;
                  if ( emit->lifespan <= 0 ) {
                        emitter_delete( i ); 
                        i--; /* last tile is copied to this one's position */
                  }
            }
      }
      
      /* particles */
      for (i = 0; i < particle_count; i++) {
            part = &particles[i];
      
            if ( part->type != PT_EXPLOSION && part->type != PT_FIRE  ) {
                  part->alpha += part->alpha_change * ms;
                  if ( part->alpha < 32.0 ) {
                        particle_delete( i );
                        i--; /* last tile is copied to this one's position */
                        continue;
                  }
            }

            part->pos.x += part->dir.x * ms;
            part->pos.y += part->dir.y * ms;
            part->pos.z += part->dir.z * ms;

            if ( part->frame_id < part->frame_count-1 ) {
                  part->frame += part->frame_change * ms;
                  part->frame_id = part->frame;
                  if ( part->frame_id >= part->frame_count-1 ) {
                        part->frame_id = part->frame_count-1;
                        /* explosion turns to smoke */
                        if ( part->type == PT_EXPLOSION ) {
                              part->dir.x = (double)RAND(-10,10)/1000;
                              part->dir.y = (double)RAND(-10,10)/1000;
                              part->dir.z = 0.0;
                              part->type = PT_SMOKE;
                        }
                        /* fire turns to smoke */
                        if ( part->type == PT_FIRE )
                              part->type = PT_SMOKE;
                  }
            }

            if ( part->wind )
            if ( part->type != PT_WASTE )
            if ( part->type != PT_EXPLOSION ) {
                  part->pos.x += part->wind->x * ms;
                  part->pos.y += part->wind->y * ms;
                  part->pos.z += part->wind->z * ms;
            }
            if ( part->grav && part->type == PT_BALLISTIC ) {
                  part->dir.x += part->grav->x * ms;
                  part->dir.y += part->grav->y * ms;
                  part->dir.z += part->grav->z * ms;
            }

            if ( part->type == PT_BALLISTIC && part->pos.z <= 0 ) {
                  part->dir.x = part->dir.y = part->dir.z = 0;
                  part->alpha_change = -0.20;
                  part->type = PT_WASTE;
            }

      }
}

static void vector_scale( Vector *vector, double scale )
{
      double norm;
      norm = sqrt(vector->x*vector->x + vector->y*vector->y + vector->z*vector->z);
      norm /= scale;
      vector->x /= norm; vector->y /= norm; vector->z /= norm;

}

void particles_explode_bomb( int x, int y )
{
      int i, yoff;
      Particle part;
      double energy;
      
      memset( &part, 0, sizeof( part ) );
      part.type = PT_BALLISTIC;
      part.img = img_particles;
      part.frame_count = 1;
      part.alpha = 200;
      part.grav = &grav;
      part.wind = &wind;
      part.pos.x = x;
      part.pos.y = y;
      for ( energy = 0.2, i = 0; i < 40; i++, energy += 0.01 ) {
            part.w = part.h = 4;
            part.dir.x = (double)RAND(-12,12);
            part.dir.y = (double)RAND(-12,12);
            part.dir.z = (double)RAND(100,400);
            vector_scale( &part.dir, energy );
            particle_add( &part );
      }
      for ( energy = 0.2, i = 0; i < 100; i++, energy += 0.004 ) {
            part.w = part.h = 2;
            part.img_x_offset = 4;
            part.dir.x = (double)RAND(-10,10);
            part.dir.y = (double)RAND(-10,10);
            part.dir.z = (double)RAND(100,400);
            vector_scale( &part.dir, energy );
            particle_add( &part );
      }
      
      memset( &part, 0, sizeof( part ) );
      part.type = PT_EXPLOSION;
      part.img = img_particles;
      part.frame_count = 8;
      part.frame_change = 0.1;
      part.alpha = 200;
      part.alpha_change = -0.2;
      part.wind = &wind;
      part.pos.x = x;
      part.pos.y = y;
      part.w = part.h = 6;
      for ( yoff = 0, energy = 0.4, i = 0; i < 100; i++, energy += 0.002, yoff += 6 ) {
            if ( yoff == 18 ) yoff = 0;
            part.img_y_offset = 18 + yoff;
            part.dir.x = (double)RAND(-80,80);
            part.dir.y = (double)RAND(-80,80);
            part.dir.z = (double)RAND(200,500);
            vector_scale( &part.dir, energy );
            particle_add( &part );
      }
}

void particles_explode_clusterbomb( int x, int y )
{
      int i, yoff;
      Particle part;
      
      memset( &part, 0, sizeof( part ) );
      part.type = PT_EXPLOSION;
      part.img = img_particles;
      part.frame_count = 8;
      part.frame_change = 0.1;
      part.alpha = 200;
      part.alpha_change = -0.2;
      part.wind = &wind;
      part.pos.x = x;
      part.pos.y = y;
      part.w = part.h = 6;
      for ( yoff = 0, i = 0; i < 100; i++, yoff += 6 ) {
            if ( yoff == 18 ) yoff = 0;
            part.img_y_offset = 18 + yoff;
            part.dir.x = (double)RAND(-80,80);
            part.dir.y = (double)RAND(-80,80);
            part.dir.z = (double)RAND(200,500);
            vector_scale( &part.dir, 0.4 );
            particle_add( &part );
      }
}

void particles_explode_grenade( int x, int y )
{
      int i;
      Particle part;
      double energy;
      
      memset( &part, 0, sizeof( part ) );
      part.type = PT_BALLISTIC;
      part.img = img_particles;
      part.frame_count = 1;
      part.alpha = 200;
      part.grav = &grav;
      part.wind = &wind;
      part.pos.x = x;
      part.pos.y = y;
      for ( energy = 0.2, i = 0; i < 10; i++, energy += 0.02 ) {
            part.w = part.h = 4;
            part.dir.x = (double)RAND(-10,10);
            part.dir.y = (double)RAND(-10,10);
            part.dir.z = (double)RAND(100,400);
            vector_scale( &part.dir, energy );
            particle_add( &part );
      }
      for ( energy = 0.2, i = 0; i < 50; i++, energy += 0.004 ) {
            part.w = part.h = 2;
            part.img_x_offset = 4;
            part.dir.x = (double)RAND(-10,10);
            part.dir.y = (double)RAND(-10,10);
            part.dir.z = (double)RAND(100,400);
            vector_scale( &part.dir, energy );
            particle_add( &part );
      }
      
      memset( &part, 0, sizeof( part ) );
      part.type = PT_EXPLOSION;
      part.img = img_particles;
      part.frame_count = 8;
      part.frame_change = 0.1;
      part.alpha = 200;
      part.alpha_change = -0.2;
      part.wind = &wind;
      part.pos.x = x;
      part.pos.y = y;
      part.w = part.h = 4;
      part.img_y_offset = 14;
      for ( energy = 0.2, i = 0; i < 40; i++, energy += 0.002 ) {
            part.dir.x = (double)RAND(-40,40);
            part.dir.y = (double)RAND(-40,40);
            part.dir.z = (double)RAND(200,500);
            vector_scale( &part.dir, energy );
            particle_add( &part );
      }
}

void particles_set_fire( int x, int y, int radius, int density )
{
      int i, frame;
      Particle part;
      double energy;
      
      memset( &part, 0, sizeof( part ) );
      part.type = PT_FIRE;
      part.img = img_particles;
      part.img_y_offset = 6;
      part.w = part.h = 2;
      part.frame_count = 10;
      part.frame_change = 0.01;
      part.alpha = 200;
      part.alpha_change = -0.2;
      part.wind = &wind;
      for ( frame = 0, energy = 0.03, i = 0; i < density; i++, frame++, energy += 0.001 ) {
            if ( frame == 6 ) frame = 0;
            part.frame = frame;
            part.pos.x = x + RAND(-radius, radius);
            part.pos.y = y + RAND(-(radius>>1),(radius>>1));
            part.dir.x = (double)RAND(-20,20);
            part.dir.y = (double)RAND(-20,20);
            part.dir.z = (double)RAND(100,400);
            vector_scale( &part.dir, energy );
            particle_add( &part );
      }
}

void particles_set_smoke( int x, int y, int radius, int density )
{
      int i, xoff;
      Particle part;
      double energy;
      
      memset( &part, 0, sizeof( part ) );
      part.type = PT_SMOKE;
      part.img = img_particles;
      part.img_y_offset = 8;
      part.w = part.h = 6;
      part.frame_count = 1;
      part.alpha = 128;
      part.alpha_change = -0.1;
      part.wind = &wind;
      for ( xoff = 0, energy = 0.04, i = 0; i < density; i++, energy += 0.01, xoff += 6 ) {
            if ( xoff == 18 ) xoff = 0;
            part.img_x_offset = xoff;
            part.pos.x = x + RAND(-radius, radius);
            part.pos.y = y + RAND(-(radius>>1),(radius>>1));
            part.dir.x = (double)RAND(-20,20);
            part.dir.y = (double)RAND(-20,20);
            part.dir.z = (double)RAND(100,400);
            vector_scale( &part.dir, energy );
            particle_add( &part );
      }
}

void particles_set_muzzle_fire( int x, int y, int density )
{
      int i;
      Particle part;
      
      memset( &part, 0, sizeof( part ) );
      part.type = PT_EXPLOSION;
      part.img = img_particles;
      part.frame_count = 8;
      part.frame_change = 0.1;
      part.alpha = 200;
      part.alpha_change = -0.2;
      part.wind = &wind;
      part.pos.x = x;
      part.pos.y = y;
      part.w = part.h = 4;
      part.img_y_offset = 14;
      for ( i = 0; i < density; i++ ) {
            part.dir.x = (double)RAND(-80,80);
            part.dir.y = (double)RAND(-80,80);
            part.dir.z = (double)RAND(200,500);
            vector_scale( &part.dir, 0.2 );
            particle_add( &part );
      }
}

void particles_explode_human( int x, int y, int sx, int sy )
{
      int i;
      double dx = x - sx, dy = y - sy;
      Particle part;
      double energy;

      energy = sqrt(dx*dx+dy*dy); dx /= energy; dy /= energy;
      
      memset( &part, 0, sizeof( part ) );
      part.type = PT_BALLISTIC;
      part.img = img_particles;
      part.img_y_offset = 4;
      part.frame_count = 1;
      part.alpha = 200;
      part.wind = &wind;
      part.grav = &grav;
      for ( energy = 0.1, i = 0; i < 10; i++, energy += 0.01 ) {
            part.w = part.h = 2;
            part.img_x_offset = 1;
            part.pos.x = x + RAND(-2,2);
            part.pos.y = y + RAND(-2,2);
            part.dir.x = dx;
            part.dir.y = dy;
            part.dir.z = 3+ rand() % 3;
            vector_scale( &part.dir, energy );
            particle_add( &part );
      }
      for ( energy = 0.1, i = 0; i < 20; i++, energy += 0.01 ) {
            part.w = part.h = 1;
            part.pos.x = x + RAND(-2,2);
            part.pos.y = y + RAND(-2,2);
            part.dir.x = dx;
            part.dir.y = dy;
            part.dir.z = 3 + rand() % 3;
            vector_scale( &part.dir, energy );
            particle_add( &part );
      }

}

void particles_add_emitter( int type, int x, int y, int radius, double rate, int lifespan )
{
      Emitter emitter;
      
      if ( emitter_count >= MAX_EMITTERS ) return;
      
      memset( &emitter, 0, sizeof( emitter ) );
      emitter.type = type;
      emitter.x = x;
      emitter.y = y;
      emitter.radius = radius;
      emitter.lifespan = lifespan;
      emitter.rate = rate;

      emitters[emitter_count] = emitter; emitter_count++;
}


Generated by  Doxygen 1.6.0   Back to index