Shell Effects
New Texture
We need to define a variable to hold our new texture.

We'll do it where the particle texture is defined in gl_rmain.c
image_t     *r_notexture;       // use for bad textures
image_t     *r_particletexture;
image_t     *r_shelltexture;    // c14 added shell texture
Also we'll make a global definition for it in gl_local.h
extern  image_t     *r_notexture;
extern  image_t     *r_particletexture;
extern  image_t     *r_shelltexture;     // c14 added shell texture
extern  entity_t    *currententity;
extern  model_t     *currentmodel;
We need to load a nice texture in gl_rmisc.c

The code below assumes that you've already done something to load tga textures or some such.
    for (x=0 ; x<8 ; x++)
    {
        for (y=0 ; y<8 ; y++)
        {
            data[y][x][0] = 255;
            data[y][x][1] = 255;
            data[y][x][2] = 255;
            data[y][x][3] = dottexture[x][y] * 255;
        }
    }
    r_particletexture = GL_LoadPic ("***particle***", (byte *)data, 8, 8, it_sprite, 32);

// c14 add from here
    r_shelltexture = Draw_FindPic("particle/shell");
    if (!r_shelltexture) {
        r_shelltexture = GL_LoadPic ("***shell***", (byte *)data, 8, 8, it_sprite, 32);
    }
// c14 to here

Make sure that the shell texture is not unloaded between games in gl_image.c
    // never free r_notexture or particle texture
    r_notexture->registration_sequence = registration_sequence;
    r_particletexture->registration_sequence = registration_sequence;
    r_shelltexture->registration_sequence = registration_sequence;    // c14 added shell texture
Rendering
All of the rendering work is done in the function GL_DrawAliasFrameLerp in gl_mesh.c
In the vanilla code, textures on shells are disabled.
    if (currententity->flags & RF_TRANSLUCENT)
        alpha = currententity->alpha;
    else
        alpha = 1.0;

    // PMM - added double shell
    if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
    //  qglDisable( GL_TEXTURE_2D );      // c14 comment out this line
        GL_Bind(r_shelltexture->texnum);  // add this line
Force the alpha back up to 1, because the alpha channel of the texture will give us our transparency.
        qglEnableClientState( GL_VERTEX_ARRAY );
        qglVertexPointer( 3, GL_FLOAT, 16, s_lerped );	// padded for SIMD

//      if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) )
        // PMM - added double damage shell
        if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
        {
         // qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha );    // c14 comment out this line
            qglColor4f( shadelight[0], shadelight[1], shadelight[2], 1.0 );      // c14 add this line
        }
Now add in texture coordinates. Here I have based the horizontal coordinates on a combination of the x and y of the model vertex, and the vertical coordinate is the z of the vertex modified by the time, so that the textures flows upwards.
            // PMM - added double damage shell
            if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
            {
                do
                {
                    index_xyz = order[2];
                    order += 3;
                    // c14 added the line below
                    qglTexCoord2f ((s_lerped[index_xyz][1] + s_lerped[index_xyz][0]) / 40.0, s_lerped[index_xyz][2] / 40.0 - r_newrefdef.time / 2.0);
                    qglVertex3fv( s_lerped[index_xyz] );

                } while (--count);
            }
Both of the above changes, also need to be done a little further down, just in case you're not using gl_vertex_arrays.
            // c14 The line below seems to be a bug. It looks like PMM should have modified this line when the new shell types were added.
            // if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) // c14 comment out this line
            if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) // c14 added this line.
            {
                do
                {
                    index_xyz = order[2];
                    order += 3;

                    // qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha); // c14 comment out this line
                    qglColor4f( shadelight[0], shadelight[1], shadelight[2], 1.0);      // c14 add this line
                    // c14 added the line below
                    qglTexCoord2f ((s_lerped[index_xyz][1] + s_lerped[index_xyz][0]) / 40.0, s_lerped[index_xyz][2] / 40.0 - r_newrefdef.time / 2.0);
                    qglVertex3fv (s_lerped[index_xyz]);

                } while (--count);
            }
            else
That's it. I think. Give it a try.

I've added a couple more features because somebody asked about them. They're in a separate tutorial.

Here is the texture that I use, you can have it in TGA or PNG format.
texture
Here is another texture that I use, you can have it in TGA or PNG format. texture