www.pudn.com > 32709.zip > particle.cpp


/*************************************************** 
 * Developer: Clinton Jon Selke                    * 
 *   Version: Totally FreeWare (Do what you will)  * 
 *   Section: Particle Implementation              * 
 ***************************************************/ 
 
#include "particle.h" 
#include "resource.h" 
#include  
#include  
#include "image.h" 
 
// RANDOM_FLOAT_0_1 returns a random number from 0.f to 1.f 
#define RANDOM_FLOAT_0_1 ((float)rand() / (float)RAND_MAX) 
// RANDOM_FLOAT(min, max) returns a random number from min to max 
#define RANDOM_FLOAT(min, max) (((max) - (min)) * RANDOM_FLOAT_0_1 + (min)) 
 
struct Particle { 
    float   age,        // current age in seconds 
            dying_age,  // dying age in seconds 
            size,       // current size 
            inc_size,   // increase in size per second 
            alpha,      // current alpha (transparency) 
            inc_alpha;  // increase in alpha per second 
    Vector3 colour,     // current colour 
            inc_colour, // increase in colour per second 
            position,   // current position 
            velocity;   // current velocity 
}; 
 
GLuint ParticleSystem::_particle_texture = 0; 
 
ParticleSystem::ParticleSystem( 
    const Vector3& position, 
    const Vector3& velocity, 
    float min_dying_age, 
    float max_dying_age, 
    float start_size, 
    float end_size, 
    float start_alpha, 
    float end_alpha, 
    float min_speed, 
    float max_speed, 
    float create_delay, 
    const Vector3& start_colour, 
    const Vector3& end_colour, 
    const Vector3& gravity, 
    unsigned int max_particles 
): 
    _position(position), _velocity(velocity), 
    MIN_DYING_AGE(min_dying_age), 
    MAX_DYING_AGE(max_dying_age), 
    START_SIZE(start_size), 
    END_SIZE(end_size), 
    START_ALPHA(start_alpha), 
    END_ALPHA(end_alpha), 
    MIN_SPEED(min_speed), 
    MAX_SPEED(max_speed), 
    CREATE_DELAY(create_delay), 
    START_COLOUR(start_colour), 
    END_COLOUR(end_colour), 
    GRAVITY(gravity), 
    MAX_PARTICLES(max_particles), 
    _number_of_particles(0), 
    _creation_timer(create_delay) 
{ 
    // Allocate array of null particles 
    _particle_array = new Particle *[MAX_PARTICLES]; 
    for (int i = 0; i < MAX_PARTICLES; i++) { 
        _particle_array[i] = 0; 
    } 
} 
 
ParticleSystem::~ParticleSystem() { 
    // Free particle array 
    for (unsigned int i = 0; i < _number_of_particles; i++) { 
        if (_particle_array[i]) { 
            delete _particle_array[i]; 
            _particle_array[i] = 0; 
        } 
    } 
    if (_particle_array) { 
        delete [] _particle_array; 
        _particle_array = 0; 
    } 
    _number_of_particles = 0; 
} 
 
void ParticleSystem::loadTexture() { 
    Image texture("particle.bmp"); 
    // Create OpenGL Texture from bitmap 
    glGenTextures(1, &_particle_texture); 
    glBindTexture(GL_TEXTURE_2D, _particle_texture); 
    glTexImage2D(GL_TEXTURE_2D, 0, 3, texture.sizeX(), texture.sizeY(), 0, GL_RGB, GL_UNSIGNED_BYTE, texture.data()); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
} 
 
void ParticleSystem::calculate(float dt) { 
    // For all particles 
    for (unsigned int i = 0; i < _number_of_particles; i++) { 
        // Grab particle from array 
        Particle &p = *_particle_array[i]; 
         
        // Calculate new age 
        p.age += dt; 
         
        // If the particle has reach its dying age, then its dead so destroy it 
        if (p.age >= p.dying_age) { 
            delete _particle_array[i]; 
            _number_of_particles--; 
            if (_number_of_particles) { 
                _particle_array[i] = _particle_array[_number_of_particles]; 
                _particle_array[_number_of_particles] = 0; 
                continue; 
            } else { 
                break; 
            } 
        } 
         
        // Calculate other particles stats 
        p.size += p.inc_size * dt; 
        p.alpha += p.inc_alpha * dt; 
        p.colour += p.inc_colour * dt; 
        p.position += p.velocity * dt; 
        p.velocity += GRAVITY * 0.5f * dt * dt; 
    } 
     
    // Check for creation of particle 
    if (_number_of_particles < MAX_PARTICLES) { 
        if ((_creation_timer -= dt) <= 0.f) { 
            // Setup new particle 
            Particle p; 
            p.age        = 0; 
            p.dying_age  = RANDOM_FLOAT(MIN_DYING_AGE, MAX_DYING_AGE); 
            float one_over_dying_age = 1.f / p.dying_age; // speed purposes 
            p.size       = START_SIZE; 
            p.inc_size   = (END_SIZE - START_SIZE) * one_over_dying_age; 
            p.alpha      = START_ALPHA; 
            p.inc_alpha  = (END_ALPHA - START_ALPHA) * one_over_dying_age; 
            p.colour     = START_COLOUR; 
            p.inc_colour = (END_COLOUR - START_COLOUR) * one_over_dying_age; 
            p.position   = _position; 
            { 
                float speed = RANDOM_FLOAT(MIN_SPEED, MAX_SPEED); 
                float theta = RANDOM_FLOAT(-M_PI, M_PI); 
                float phi   = RANDOM_FLOAT(-M_PI*0.5f, M_PI*0.5f); 
                p.velocity.x = sin(phi) * speed; 
                p.velocity.y = cos(phi) * cos(theta) * speed; 
                p.velocity.z = cos(phi) * sin(theta) * speed; 
            } 
             
            // Store new particle in array 
            _particle_array[_number_of_particles++] = new Particle(p); 
             
            // Reset creation timer 
            _creation_timer = CREATE_DELAY; 
        } 
    } 
} 
 
void ParticleSystem::draw() { 
    // Select our texture 
    glBindTexture(GL_TEXTURE_2D, _particle_texture); 
 
    // For all particles that exist 
    for (unsigned int i = 0; i < _number_of_particles; i++) { 
        // Grab particle the from array 
        Particle &p = *_particle_array[i]; 
         
        // Set colour of particle 
        glColor4f(p.colour.x, p.colour.y, p.colour.z, p.alpha); 
         
        // Set texture of particle 
        glBindTexture(GL_TEXTURE_2D, _particle_texture); 
         
        // Draw particle 
        float half_size = p.size * 0.5f; 
        glBegin(GL_TRIANGLE_STRIP); 
            glTexCoord2d(1.f, 1.f); glVertex3f(p.position.x + half_size, p.position.y + half_size, p.position.z); 
            glTexCoord2d(0.f, 1.f); glVertex3f(p.position.x - half_size, p.position.y + half_size, p.position.z); 
            glTexCoord2d(1.f, 0.f); glVertex3f(p.position.x + half_size, p.position.y - half_size, p.position.z); 
            glTexCoord2d(0.f, 0.f); glVertex3f(p.position.x - half_size, p.position.y - half_size, p.position.z); 
        glEnd(); 
    } 
}