Multiple Particle Effects
4. Particle Based Lasers
Introduction
We are going to modify the client, to create 'instant particles' to represent lasers. Then when we disable the original laser rendering code in the renderer, we will get textures on our lasers.

Before you start, you should have already implemented the third part of this tutorial.
Definitions
In the files
  • client\cl_ents.c
  • client\cl_tent.c
add the following lines, up at the top near #include "client.h"
// c14 particles
#include "../ref_gl/gl_particles.h"
extern cparticle_t	*active_particles, *free_particles;
In the file ref_gl\gl_rmain.c, comment out the entire contents of the function R_DrawBeam. This will prevent the renderer from drawing old-style beams.
Find the following in the function CL_AddPacketEntities in client\cl_ents.c
		// tweak the color of beams
		if ( renderfx & RF_BEAM )
		{	// the four beam colors are encoded in 32 bits of skinnum (hack)
			ent.alpha = 0.30;
			ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff;
			ent.model = NULL;
		}
and replace it thus:
		// tweak the color of beams
		if ( renderfx & RF_BEAM )
		{	// the four beam colors are encoded in 32 bits of skinnum (hack)
			// c14 particles. Added particles for beams.

			cparticle_t	*p;

			p = free_particles;
			if (p) {
				free_particles = p->next;
				p->next = active_particles;
				active_particles = p;

				p->time = cl.time;
				VectorClear (p->accel);
				VectorClear (p->vel);
				p->alpha = 0.3;
				p->alphavel = INSTANT_PARTICLE;
				p->color = (s1->skinnum >> ((rand() % 4)*8)) & 0xff;
				p->type = PT_BEAM; // c14 particles
				VectorCopy (s1->origin, p->org);
				VectorSubtract(s1->old_origin, s1->origin, p->length);
			}

			/*
			ent.alpha = 0.30;
			ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff;
			ent.model = NULL;
			*/
		}
For each entity which has a RF_BEAM render flag, we are creating a PT_BEAM particle (like the core of the of the railgun trail). The constant value INSTANT_PARTICLE is used as a special flag, allowing particles to be created for just one frame. Particles with an alphavel value of INSTANT_PARTICLE are automatically killed after each frame.
This works well for the lasers that you find on maps, but unfortunately, this function is called, before the temporary entities are handled, so BFG lasers are not created, and therefore, the corresponding particles are not created.

To deal with this, we will modify the code which handles temporary lasers, in a similar way to the code above. Find the function CL_AddLasers in the file client\cl_tent.c
void CL_AddLasers (void)
{
	laser_t		*l;
	int			i;

	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
	{
		if (l->endtime >= cl.time)
			V_AddEntity (&l->ent);
	}
}
and replace it thus:
void CL_AddLasers (void)
{
	laser_t		*l;
	int			i;

	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
	{
		if (l->endtime >= cl.time) {

			// c14 particles
			cparticle_t	*p;

			p = free_particles;
			if (p) {
				free_particles = p->next;
				p->next = active_particles;
				active_particles = p;

				p->time = cl.time;
				VectorClear (p->accel);
				VectorClear (p->vel);
				p->alpha = 0.3;
				p->alphavel = INSTANT_PARTICLE;
				p->color = (l->ent.skinnum >> ((rand() % 4)*8)) & 0xff;
				p->type = PT_BEAM; // c14 particles
				VectorCopy (l->ent.origin, p->org);
				VectorSubtract(l->ent.oldorigin, l->ent.origin, p->length);
			}


		}
		//	V_AddEntity (&l->ent);
	}
}
That's all there is to it.

In the next part of this tutorial, we will be tidying up some loose ends.

Go to part 5
Lasers
Additional Notes
In the original beam handling code, the width (diameter) of the laser beam is given by the frame value of the entity. In the code above, we are not dealing with lasers of differing widths at all.

If you want to handle different width beams, you could add a new width property to the particle, in the same way that we added length in part 1 of this tutorial. Then set the width value when you create the instant particles in the code above. Finally in the PT_BEAM renderer, scale the width vector by half of the particle's width value. Don't forget to set the width value for the ordinary railgun PT_BEAM particle. A value of 4 would be suitable.