Example #1
0
void GLFWCALL PhysicsThreadFun( void *arg )
{
    while( running )
    {
        // Lock mutex
        glfwLockMutex( thread_sync.particles_lock );

        // Wait for particle drawing to be done
        while( running && thread_sync.p_frame > thread_sync.d_frame )
        {
            glfwWaitCond( thread_sync.d_done, thread_sync.particles_lock,
                          0.1 );
        }

        // No longer running?
        if( !running )
        {
            break;
        }

        // Update particles
        ParticleEngine( thread_sync.t, thread_sync.dt );

        // Update frame counter
        thread_sync.p_frame ++;

        // Unlock mutex and signal drawing thread
        glfwUnlockMutex( thread_sync.particles_lock );
        glfwSignalCond( thread_sync.p_done );
    }
}
ParticleEngine ParticleEngineBuilder::Build(){ return ParticleEngine(gBuilder,rMinBuilder,blackHoleMassBuilder,blackHoleRadiusBuilder,disappearingRadiusBuilder,minSpawnRadiusBuilder,maxSpawnRadiusBuilder,spawnVelocityBuilder,maxZSpawnDistanceBuilder,numberOfThreadsBuilder,numberOfParticlesBuilder,collisionsBuilder,integratorBuilder, gravityCutOffBuilder);}
Example #3
0
void DrawParticles( double t, float dt )
{
    int       i, particle_count;
    VERTEX    vertex_array[ BATCH_PARTICLES * PARTICLE_VERTS ], *vptr;
    float     alpha;
    GLuint    rgba;
    VEC       quad_lower_left, quad_lower_right;
    GLfloat   mat[ 16 ];
    PARTICLE  *pptr;

    // Here comes the real trick with flat single primitive objects (s.c.
    // "billboards"): We must rotate the textured primitive so that it
    // always faces the viewer (is coplanar with the view-plane).
    // We:
    //   1) Create the primitive around origo (0,0,0)
    //   2) Rotate it so that it is coplanar with the view plane
    //   3) Translate it according to the particle position
    // Note that 1) and 2) is the same for all particles (done only once).

    // Get modelview matrix. We will only use the upper left 3x3 part of
    // the matrix, which represents the rotation.
    glGetFloatv( GL_MODELVIEW_MATRIX, mat );

    // 1) & 2) We do it in one swift step:
    // Although not obvious, the following six lines represent two matrix/
    // vector multiplications. The matrix is the inverse 3x3 rotation
    // matrix (i.e. the transpose of the same matrix), and the two vectors
    // represent the lower left corner of the quad, PARTICLE_SIZE/2 *
    // (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0).
    // The upper left/right corners of the quad is always the negative of
    // the opposite corners (regardless of rotation).
    quad_lower_left.x = (-PARTICLE_SIZE/2) * (mat[0] + mat[1]);
    quad_lower_left.y = (-PARTICLE_SIZE/2) * (mat[4] + mat[5]);
    quad_lower_left.z = (-PARTICLE_SIZE/2) * (mat[8] + mat[9]);
    quad_lower_right.x = (PARTICLE_SIZE/2) * (mat[0] - mat[1]);
    quad_lower_right.y = (PARTICLE_SIZE/2) * (mat[4] - mat[5]);
    quad_lower_right.z = (PARTICLE_SIZE/2) * (mat[8] - mat[9]);

    // Don't update z-buffer, since all particles are transparent!
    glDepthMask( GL_FALSE );

    // Enable blending
    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE );

    // Select particle texture
    if( !wireframe )
    {
        glEnable( GL_TEXTURE_2D );
        glBindTexture( GL_TEXTURE_2D, particle_tex_id );
    }

    // Set up vertex arrays. We use interleaved arrays, which is easier to
    // handle (in most situations) and it gives a linear memeory access
    // access pattern (which may give better performance in some
    // situations). GL_T2F_C4UB_V3F means: 2 floats for texture coords,
    // 4 ubytes for color and 3 floats for vertex coord (in that order).
    // Most OpenGL cards / drivers are optimized for this format.
    glInterleavedArrays( GL_T2F_C4UB_V3F, 0, vertex_array );

    // Is particle physics carried out in a separate thread?
    if( multithreading )
    {
        // Wait for particle physics thread to be done
        glfwLockMutex( thread_sync.particles_lock );
        while( running && thread_sync.p_frame <= thread_sync.d_frame )
        {
            glfwWaitCond( thread_sync.p_done, thread_sync.particles_lock,
                          0.1 );
        }

        // Store the frame time and delta time for the physics thread
        thread_sync.t  = t;
        thread_sync.dt = dt;

        // Update frame counter
        thread_sync.d_frame ++;
    }
    else
    {
        // Perform particle physics in this thread
        ParticleEngine( t, dt );
    }

    // Loop through all particles and build vertex arrays.
    particle_count = 0;
    vptr = vertex_array;
    pptr = particles;
    for( i = 0; i < MAX_PARTICLES; i ++ )
    {
        if( pptr->active )
        {
            // Calculate particle intensity (we set it to max during 75%
            // of its life, then it fades out)
            alpha =  4.0f * pptr->life;
            if( alpha > 1.0f )
            {
                alpha = 1.0f;
            }

            // Convert color from float to 8-bit (store it in a 32-bit
            // integer using endian independent type casting)
            ((GLubyte *)&rgba)[0] = (GLubyte)(pptr->r * 255.0f);
            ((GLubyte *)&rgba)[1] = (GLubyte)(pptr->g * 255.0f);
            ((GLubyte *)&rgba)[2] = (GLubyte)(pptr->b * 255.0f);
            ((GLubyte *)&rgba)[3] = (GLubyte)(alpha * 255.0f);

            // 3) Translate the quad to the correct position in modelview
            // space and store its parameters in vertex arrays (we also
            // store texture coord and color information for each vertex).

            // Lower left corner
            vptr->s    = 0.0f;
            vptr->t    = 0.0f;
            vptr->rgba = rgba;
            vptr->x    = pptr->x + quad_lower_left.x;
            vptr->y    = pptr->y + quad_lower_left.y;
            vptr->z    = pptr->z + quad_lower_left.z;
            vptr ++;

            // Lower right corner
            vptr->s    = 1.0f;
            vptr->t    = 0.0f;
            vptr->rgba = rgba;
            vptr->x    = pptr->x + quad_lower_right.x;
            vptr->y    = pptr->y + quad_lower_right.y;
            vptr->z    = pptr->z + quad_lower_right.z;
            vptr ++;

            // Upper right corner
            vptr->s    = 1.0f;
            vptr->t    = 1.0f;
            vptr->rgba = rgba;
            vptr->x    = pptr->x - quad_lower_left.x;
            vptr->y    = pptr->y - quad_lower_left.y;
            vptr->z    = pptr->z - quad_lower_left.z;
            vptr ++;

            // Upper left corner
            vptr->s    = 0.0f;
            vptr->t    = 1.0f;
            vptr->rgba = rgba;
            vptr->x    = pptr->x - quad_lower_right.x;
            vptr->y    = pptr->y - quad_lower_right.y;
            vptr->z    = pptr->z - quad_lower_right.z;
            vptr ++;

            // Increase count of drawable particles
            particle_count ++;
        }

        // If we have filled up one batch of particles, draw it as a set
        // of quads using glDrawArrays.
        if( particle_count >= BATCH_PARTICLES )
        {
            // The first argument tells which primitive type we use (QUAD)
            // The second argument tells the index of the first vertex (0)
            // The last argument is the vertex count
            glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count );
            particle_count = 0;
            vptr = vertex_array;
        }

        // Next particle
        pptr ++;
    }

    // We are done with the particle data: Unlock mutex and signal physics
    // thread
    if( multithreading )
    {
        glfwUnlockMutex( thread_sync.particles_lock );
        glfwSignalCond( thread_sync.d_done );
    }

    // Draw final batch of particles (if any)
    glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count );

    // Disable vertex arrays (Note: glInterleavedArrays implicitly called
    // glEnableClientState for vertex, texture coord and color arrays)
    glDisableClientState( GL_VERTEX_ARRAY );
    glDisableClientState( GL_TEXTURE_COORD_ARRAY );
    glDisableClientState( GL_COLOR_ARRAY );

    // Disable texturing and blending
    glDisable( GL_TEXTURE_2D );
    glDisable( GL_BLEND );

    // Allow Z-buffer updates again
    glDepthMask( GL_TRUE );
}