Multiple Particle Effects
1. Preparing the Ground
Introduction
We are going to modify the engine and the gl renderer to allow us to define different kinds of particles, which will be rendered in different ways.

Before you start, you should have already implemented some form of externally loaded particle texture. If you haven't done this, you can use my Soft Particles Tutorial.
Definitions
First, create a new file called "gl_particles.h" and store it in the "ref_gl" directory. Put the following into it:
#define PT_DEFAULT      0
#define PT_BEAM         1
#define PT_SPIRAL       2
This file will hold our constants. PT_ constants will be used for the different Particle Types that we are going to define.

We need to include this file in several source files. Add a line like this:
#include "..\ref_gl\gl_particles.h"  // c14 particles
to the following files, with the other #include lines near the top of the file.
  • client\cl_fx.c
  • client\cl_newfx.c
  • client\cl_view.c
  • ref_gl\gl_rmain.c
The particle structure
In order to specify what type each particle will be, we need somewhere to store that information for each particle.

Particles are defined in two places, once for the client, which creates and manages them, and once for the renderer which has to draw them. To both of these definitions, we will add two new pieces of information. The type of the particle is simply a number which we can refer to using the definitions we put in gl_particles.h. The length is a new vector value which we will add to store any additional information about the particle that we might need later.

In the file client\client.h search for the following:
typedef struct particle_s
{
    struct particle_s   *next;

    float       time;

    vec3_t      org;
    vec3_t      vel;
    vec3_t      accel;
    float       color;
    float       colorvel;
    float       alpha;
    float       alphavel;
} cparticle_t;
and add two lines as marked
typedef struct particle_s
{
    struct particle_s   *next;

    float       time;

    vec3_t      org;
    vec3_t      vel;
    vec3_t      accel;
    vec3_t      length;     // c14 particles
    int         type;       // c14 particles
    float       color;
    float       colorvel;
    float       alpha;
    float       alphavel;
} cparticle_t;
And in the file client\ref.h search for the following:
typedef struct
{
    vec3_t  origin;
    int     color;
    float   alpha;
} particle_t;
and add two lines as marked
typedef struct
{
    vec3_t  origin;
    vec3_t  length;    // c14 particles
    int     type;      // c14 particles
    int     color;
    float   alpha;
} particle_t;
Passing the information from client to renderer
Now we need to ensure that the renderer receives the new information from the client. Make the following changes.

In client\cl_fx.c
    V_AddParticle (org, color, alpha);
becomes
    V_AddParticle (org, p->length, color, alpha, p->type); // c14 particles
In client\client.h
void V_AddParticle (vec3_t org, int color, float alpha);
becomes
void V_AddParticle (vec3_t org, vec3_t length, int color, float alpha, int type); // c14 particles
And in client\cl_view.c
void V_AddParticle (vec3_t org, vec3_t length, int color, float alpha, int type)
{
    particle_t  *p;

    if (r_numparticles >= MAX_PARTICLES)
        return;
    p = &r_particles[r_numparticles++];
    VectorCopy (org, p->origin);
    p->color = color;
    p->alpha = alpha;
}
becomes
void V_AddParticle (vec3_t org, vec3_t length, int color, float alpha, int type)
{
    particle_t  *p;

    if (r_numparticles >= MAX_PARTICLES)
        return;
    p = &r_particles[r_numparticles++];
    VectorCopy (org, p->origin);
    VectorCopy (length, p->length); //c14 particles
    p->color = color;
    p->alpha = alpha;
    p->type = type;                 //c14 particles
}
Setting the default particle type
Because particles get re-used, we should set the default particle type PT_DEFAULT for every particle which we are not going to change. Otherwise there's a risk that an unchanged blaster spark, will suddenly look like a blood spatter, or something else.

This is a little tiresome. Everywhere that the color of a particle is set, we should follow that up by setting the type to PT_DEFAULT This needs to be done in 26 places in client\cl_fx.c and in 25 places in client\cl_newfx.c (although one of them is actually commented out).

Follow this example from client\cl_fx.c:
        if (type == MZ_LOGIN)
            p->color = 0xd0 + (rand()&7);   // green
        else if (type == MZ_LOGOUT)
            p->color = 0x40 + (rand()&7);   // red
        else
            p->color = 0xe0 + (rand()&7);   // yellow
becomes
        if (type == MZ_LOGIN)
            p->color = 0xd0 + (rand()&7);   // green
        else if (type == MZ_LOGOUT)
            p->color = 0x40 + (rand()&7);   // red
        else
            p->color = 0xe0 + (rand()&7);   // yellow
        p->type = PT_DEFAULT;               // c14 particles
Rendering the default particle type
Now the last thing we need to do at this stage is to change the renderer, so that it only draws default particles. As we add new particle types to the system, we will add new stages to the particle renderer to handle them. In the file ref_gl\gl_rmain.c find the following
    for ( p = particles, i=0 ; i < num_particles ; i++,p++)
    {
        // hack a scale up to keep particles from disapearing
        scale = ( p->origin[0] - r_origin[0] ) * vpn[0] +
and add the marked line.
    for ( p = particles, i=0 ; i < num_particles ; i++,p++)
    {
        if (p->type != PT_DEFAULT) continue; // c14 particles

        // hack a scale up to keep particles from disapearing
        scale = ( p->origin[0] - r_origin[0] ) * vpn[0] +
This is the beginning of the loop which renders all of the visible particles. We have added a line to tell it to ignore any particle which is not the default type.

If you compile and run up the programs now (quake2.exe and ref_gl.dll) you should find that they work pretty much as previous. We're not yet trying to draw new particles so you shouldn't see any difference.

In the next part of this tutorial, we will actually create our first new particle type

Go to part 2