/* PLIB - A Suite of Portable Game Libraries Copyright (C) 1998,2002 Steve Baker This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA For further information visit http://plib.sourceforge.net */ #include "ssgAux.h" ssgaParticleSystem::ssgaParticleSystem ( int num, int initial_num, float _create_rate, int _ttf, float sz, float bsphere_size, ssgaParticleCreateFunc _particle_create, ssgaParticleUpdateFunc _particle_update, ssgaParticleDeleteFunc _particle_delete ) : ssgVtxTable ( GL_QUADS, new ssgVertexArray ( num * 4, new sgVec3 [ num * 4 ] ), new ssgNormalArray ( num * 4, new sgVec3 [ num * 4 ] ), new ssgTexCoordArray ( num * 4, new sgVec2 [ num * 4 ] ), new ssgColourArray ( num * 4, new sgVec4 [ num * 4 ] ) ) { turn_to_face = _ttf ; create_error = 0 ; create_rate = _create_rate ; particle_create = _particle_create ; particle_update = _particle_update ; particle_delete = _particle_delete ; size = sz ; num_particles = num ; num_verts = num * 4 ; getBSphere () -> setRadius ( bsphere_size ) ; getBSphere () -> setCenter ( 0, 0, 0 ) ; particle = new ssgaParticle [ num ] ; int i ; for ( i = 0 ; i < num_verts ; i++ ) { sgSetVec3 ( getNormal ( i ), 0, -1, 0 ) ; sgSetVec4 ( getColour ( i ), 1, 1, 1, 1 ) ; sgZeroVec3 ( getVertex ( i ) ) ; } for ( i = 0 ; i < num_particles ; i++ ) { sgSetVec2 ( getTexCoord ( i*4+0 ), 0, 0 ) ; sgSetVec2 ( getTexCoord ( i*4+1 ), 1, 0 ) ; sgSetVec2 ( getTexCoord ( i*4+2 ), 1, 1 ) ; sgSetVec2 ( getTexCoord ( i*4+3 ), 0, 1 ) ; } num_active = 0 ; if ( particle_create ) for ( i = 0 ; i < initial_num ; i++ ) (*particle_create) ( this, i, & particle [ i ] ) ; } void ssgaParticleSystem::draw_geometry () { sgVec3 nxny, xxny, xxyy, nxyy ; float sz = size / 2.0f ; if ( turn_to_face ) { sgMat4 mat ; glGetFloatv ( GL_MODELVIEW_MATRIX, (float *) mat ) ; sgVec3 xx, yy ; sgSetVec3 ( xx, mat[0][0] * sz, mat[1][0] * sz, mat[2][0] * sz ) ; sgSetVec3 ( yy, mat[0][1] * sz, mat[1][1] * sz, mat[2][1] * sz ) ; sgSetVec3 ( nxny, -xx[0]-yy[0], -xx[1]-yy[1], -xx[2]-yy[2] ) ; sgSetVec3 ( nxyy, -xx[0]+yy[0], -xx[1]+yy[1], -xx[2]+yy[2] ) ; sgSetVec3 ( xxny, xx[0]-yy[0], xx[1]-yy[1], xx[2]-yy[2] ) ; sgSetVec3 ( xxyy, xx[0]+yy[0], xx[1]+yy[1], xx[2]+yy[2] ) ; } else { sgSetVec3 ( xxny , sz, 0, -sz ) ; sgSetVec3 ( nxny , -sz, 0, -sz ) ; sgSetVec3 ( nxyy , -sz, 0, sz ) ; sgSetVec3 ( xxyy, sz, 0, sz ) ; } int j = 0 ; for ( int i = 0 ; i < num_particles ; i++ ) { /* Make them disappear if not needed */ if ( particle[i].time_to_live <= 0.0f ) continue ; sgCopyVec4 ( getColour ( j + 0 ), particle[i].col ) ; sgCopyVec4 ( getColour ( j + 1 ), particle[i].col ) ; sgCopyVec4 ( getColour ( j + 2 ), particle[i].col ) ; sgCopyVec4 ( getColour ( j + 3 ), particle[i].col ) ; sgAddScaledVec3 ( getVertex ( j + 0 ), particle[i].pos, nxny, particle[i].size ) ; sgAddScaledVec3 ( getVertex ( j + 1 ), particle[i].pos, xxny, particle[i].size ) ; sgAddScaledVec3 ( getVertex ( j + 2 ), particle[i].pos, xxyy, particle[i].size ) ; sgAddScaledVec3 ( getVertex ( j + 3 ), particle[i].pos, nxyy, particle[i].size ) ; j += 4 ; } rawSetNumVertices ( j ) ; /* Avoid drawing more than 'j' vertices. */ if ( j > 0 ) { glDisable ( GL_CULL_FACE ) ; glDepthMask ( 0 ) ; ssgVtxTable::draw_geometry () ; glDepthMask ( 1 ) ; glEnable ( GL_CULL_FACE ) ; } } ssgaParticleSystem::~ssgaParticleSystem () { if ( particle_delete ) for ( int i = 0 ; i < num_particles ; i++ ) if ( particle [ i ] . time_to_live >= 0.0 ) (*particle_delete) ( this, i, & particle [ i ] ) ; delete [] particle ; } void ssgaParticleSystem::update ( float t ) { int i ; create_error += create_rate * t ; num_active = 0 ; /* Call the update routine for all the particles */ if ( particle_update ) { for ( i = 0 ; i < num_particles ; i++ ) if ( particle [ i ] . time_to_live > 0.0f ) { particle [ i ] . update ( t ) ; (*particle_update) ( t, this, i, & particle [ i ] ) ; } } else for ( i = 0 ; i < num_particles ; i++ ) if ( particle [ i ] . time_to_live > 0.0f ) particle [ i ] . update ( t ) ; /* Check for death of particles */ for ( i = 0 ; i < num_particles ; i++ ) if ( particle [ i ] . time_to_live <= 0.0 ) { if ( particle_delete ) (*particle_delete) ( this, i, & particle [ i ] ) ; particle [ i ] . pos [ 2 ] = -1000000.0f ; if ( create_error >= 1.0f && particle_create ) { (*particle_create) ( this, i, & particle [ i ] ) ; create_error -= 1.0f ; } } else num_active++ ; }