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

particles.c

/*
 *  Copyright 1994-2011 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou 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.
 *
 *  lebiniou is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include "particles.h"

#define G (-9.81 / 100.0) /* FIXME a tuner --oliv3 */


Particle_System_t *
Particle_System_new(const long max_particles)
{
  Particle_System_t *ps = xcalloc(1, sizeof(Particle_System_t));

  ps->max_particles = max_particles;
  ps->nb_particles = 0;

  return ps;
}


static void
Particle_delete(Particle_t *p)
{
  xfree(p);
}


void
Particle_System_delete(Particle_System_t *ps)
{
  GSList *p = ps->particles;
      
  while (p != NULL) {
    Particle_t *dp = (Particle_t *)p->data;
    p = g_slist_next(p);
    Particle_delete(dp);
  }
  g_slist_free(p);

  xfree(ps);
}


static Particle_t *
Particle_new(float ttl, Point3d_t pos, Point3d_t vel, Point3d_t acc, float gfa)
{
  Particle_t *p = xcalloc(1, sizeof(Particle_t));
  
  p->ttl = ttl;
  p->pos = pos;
  p->vel = vel;
  p->acc = acc;
  p->gra.pos.y = gfa * -G;
      
  gettimeofday(&p->age, NULL);
      
  return p;
}


Particle_t *
Particle_new_indexed(float ttl, Pixel_t col, Point3d_t pos, Point3d_t vel, Point3d_t acc, float gfa)
{
  Particle_t *p = Particle_new(ttl, pos, vel, acc, gfa);
  
  p->col.idx = col;
      
  return p;
}


Particle_t *
Particle_new_rgba(float ttl, rgba_t rgba, Point3d_t pos, Point3d_t vel, Point3d_t acc, float gfa)
{
  Particle_t *p = Particle_new(ttl, pos, vel, acc, gfa);
  
  /* ici on est pourtant sur que les particules ont un bon RGBA */
  p->col.rgba = rgba;
      
  return p;
}


u_char
Particle_System_can_add(const Particle_System_t *ps)
{
  if (ps->max_particles == PS_NOLIMIT)
    return 1;
  else
    return (ps->nb_particles < ps->max_particles);
}


void
Particle_System_add(Particle_System_t *ps, const Particle_t *p)
{
#ifdef XDEBUG
  if (ps == NULL)
    xerror ("non mais ca suffit comme ca");
  if (p == NULL)
    xerror ("ARRETEZ ENFIN #@##@@#@");
#endif
      
#ifdef XDEBUG
  if (g_slist_length(ps->particles) >= ps->max_particles)
    xerror ("non nooon noooooooooooooooooon");
#endif
  ps->particles = g_slist_prepend(ps->particles, (gpointer)p);
  ps->nb_particles++;
}


/* if we were in erlang,
 * each particle would have it's own timer,
 * move by it's own,
 * then decide if it should die or not. But we are in C, so...
 */

static void
Particle_System_decay(Particle_System_t *ps)
{
  GSList *tmp = ps->particles;
  struct timeval t;
  GSList *newp = NULL;
      
  gettimeofday(&t, NULL);

  while (tmp != NULL) {
    float age;
    struct timeval elapsed;
    Particle_t *dp = (Particle_t *)tmp->data;

    /* ok let's compute this particle's age */
    if (dp->age.tv_usec > t.tv_usec) {
      t.tv_usec += 1000000;
      t.tv_sec--;
    }
    elapsed.tv_sec = t.tv_sec - dp->age.tv_sec;
    elapsed.tv_usec = t.tv_usec - dp->age.tv_usec;
    age = elapsed.tv_sec + ((double)elapsed.tv_usec / 1e6);
            
    if (age >= dp->ttl) {
      /* die, particle, die ! */
      Particle_delete(dp);
      ps->nb_particles--;
    }
    else
      newp = g_slist_prepend(newp, dp);
    
    tmp = g_slist_next(tmp);
  }
  g_slist_free(ps->particles);

  ps->particles = newp;
}


static void
Particle_System_move(Particle_System_t *ps)
{
  GSList *p = ps->particles;
      
  while (p != NULL) {
    Particle_t *dp = (Particle_t *)p->data;
            
    /* change position */
    dp->pos = p3d_add(&dp->pos, &dp->vel);

    /* change speed */
    dp->vel = p3d_add(&dp->vel, &dp->acc);

    /* apply gravity */
    dp->vel = p3d_add(&dp->vel, &dp->gra);

    /* next patient, please */
    p = g_slist_next(p);
  }
}


void
Particle_System_go(Particle_System_t *ps)
{
  /* remove old particles */
  Particle_System_decay(ps);

  /* move the rest */
  Particle_System_move(ps);
}


void
Particle_System_draw(const Particle_System_t *ps, const Params3d_t *params3d, Buffer8_t *dst)
{
  GSList *p = ps->particles;
  
  while (p != NULL) {
    Particle_t *dp = (Particle_t *)p->data;
    set_pixel_3d_nc(params3d, dst, &dp->pos, dp->col.idx);

    p = g_slist_next(p);
  }
}

Generated by  Doxygen 1.6.0   Back to index