-/*
-===============
-CL_MoveParticles
-===============
-*/
-void CL_MoveParticles (void)
-{
- particle_t *p;
- int i, maxparticle, j, a, content;
- float gravity, dvel, decalfade, frametime, f, dist, org[3], oldorg[3];
- particletype_t *decaltype, *bloodtype;
- int hitent;
- trace_t trace;
-
- // LordHavoc: early out condition
- if (!cl.num_particles)
- {
- cl.free_particle = 0;
- return;
- }
-
- frametime = cl.time - cl.oldtime;
- gravity = frametime * sv_gravity.value;
- dvel = 1+4*frametime;
- decalfade = frametime * 255 / cl_decals_fadetime.value;
- decaltype = particletype + pt_decal;
- bloodtype = particletype + pt_blood;
-
- maxparticle = -1;
- j = 0;
- for (i = 0, p = cl.particles;i < cl.num_particles;i++, p++)
- {
- if (!p->type)
- {
- if (cl.free_particle > i)
- cl.free_particle = i;
- continue;
- }
- maxparticle = i;
-
- // heavily optimized decal case
- if (p->type == decaltype)
- {
- // FIXME: this has fairly wacky handling of alpha
- if (cl.time > p->time2 + cl_decals_time.value)
- {
- p->alpha -= decalfade;
- if (p->alpha <= 0)
- {
- p->type = NULL;
- if (cl.free_particle > i)
- cl.free_particle = i;
- continue;
- }
- }
- if (p->owner)
- {
- if (cl.entities[p->owner].render.model == p->ownermodel)
- {
- Matrix4x4_Transform(&cl.entities[p->owner].render.matrix, p->relativeorigin, p->org);
- Matrix4x4_Transform3x3(&cl.entities[p->owner].render.matrix, p->relativedirection, p->vel);
- }
- else
- {
- p->type = NULL;
- if (cl.free_particle > i)
- cl.free_particle = i;
- }
- }
- continue;
- }
-
- content = 0;
-
- p->alpha -= p->alphafade * frametime;
-
- if (p->alpha <= 0)
- {
- p->type = NULL;
- if (cl.free_particle > i)
- cl.free_particle = i;
- continue;
- }
-
- if (p->type->orientation != PARTICLE_BEAM)
- {
- VectorCopy(p->org, oldorg);
- VectorMA(p->org, frametime, p->vel, p->org);
- VectorCopy(p->org, org);
- if (p->bounce)
- {
- trace = CL_TraceBox(oldorg, vec3_origin, vec3_origin, p->org, true, &hitent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | (p->type == particletype + pt_rain ? SUPERCONTENTS_LIQUIDSMASK : 0), false);
- // if the trace started in or hit something of SUPERCONTENTS_NODROP
- // or if the trace hit something flagged as NOIMPACT
- // then remove the particle
- if (trace.hitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT || ((trace.startsupercontents | trace.hitsupercontents) & SUPERCONTENTS_NODROP))
- {
- p->type = NULL;
- continue;
- }
- // react if the particle hit something
- if (trace.fraction < 1)
- {
- VectorCopy(trace.endpos, p->org);
- if (p->type == particletype + pt_rain)
- {
- // raindrop - splash on solid/water/slime/lava
- int count;
- // convert from a raindrop particle to a rainsplash decal
- VectorCopy(trace.plane.normal, p->vel);
- VectorAdd(p->org, p->vel, p->org);
- p->type = particletype + pt_raindecal;
- p->texnum = tex_rainsplash;
- p->time2 = cl.time;
- p->alphafade = p->alpha / 0.4;
- p->bounce = 0;
- p->airfriction = 0;
- p->liquidfriction = 0;
- p->gravity = 0;
- p->size *= 1.0f;
- p->sizeincrease = p->size * 16;
- count = rand() & 3;
- while(count--)
- particle(particletype + pt_spark, 0x000000, 0x707070, tex_particle, 0.25f, 0, lhrandom(64, 255), 512, 1, 0, p->org[0], p->org[1], p->org[2], p->vel[0]*16, p->vel[1]*16, 32 + p->vel[2]*16, 0, 0, 32);
- }
- else if (p->type == bloodtype)
- {
- // blood - splash on solid
- if (trace.hitq3surfaceflags & Q3SURFACEFLAG_NOMARKS)
- {
- p->type = NULL;
- continue;
- }
- if (!cl_decals.integer)
- {
- p->type = NULL;
- continue;
- }
- // convert from a blood particle to a blood decal
- VectorCopy(trace.plane.normal, p->vel);
- VectorAdd(p->org, p->vel, p->org);
- if (cl_stainmaps.integer)
- R_Stain(p->org, 32, 32, 16, 16, (int)(p->alpha * p->size * (1.0f / 40.0f)), 192, 48, 48, (int)(p->alpha * p->size * (1.0f / 40.0f)));
-
- p->type = particletype + pt_decal;
- p->texnum = tex_blooddecal[rand()&7];
- p->owner = hitent;
- p->ownermodel = cl.entities[hitent].render.model;
- // these relative things are only used to regenerate p->org and p->vel if p->owner is not world (0)
- Matrix4x4_Transform(&cl.entities[hitent].render.inversematrix, p->org, p->relativeorigin);
- Matrix4x4_Transform3x3(&cl.entities[hitent].render.inversematrix, p->vel, p->relativedirection);
- p->time2 = cl.time;
- p->alphafade = 0;
- p->bounce = 0;
- p->airfriction = 0;
- p->liquidfriction = 0;
- p->gravity = 0;
- p->size *= 2.0f;
- }
- else if (p->bounce < 0)
- {
- // bounce -1 means remove on impact
- p->type = NULL;
- continue;
- }
- else
- {
- // anything else - bounce off solid
- dist = DotProduct(p->vel, trace.plane.normal) * -p->bounce;
- VectorMA(p->vel, dist, trace.plane.normal, p->vel);
- if (DotProduct(p->vel, p->vel) < 0.03)
- VectorClear(p->vel);
- }
- }
- }
- p->vel[2] -= p->gravity * gravity;
-
- if (p->liquidfriction && CL_PointSuperContents(p->org) & SUPERCONTENTS_LIQUIDSMASK)
- {
- f = 1.0f - min(p->liquidfriction * frametime, 1);
- VectorScale(p->vel, f, p->vel);
- }
- else if (p->airfriction)
- {
- f = 1.0f - min(p->airfriction * frametime, 1);
- VectorScale(p->vel, f, p->vel);
- }
- }
-
- if (p->type != particletype + pt_static)
- {
- switch (p->type - particletype)
- {
- case pt_entityparticle:
- // particle that removes itself after one rendered frame
- if (p->time2)
- p->type = NULL;
- else
- p->time2 = 1;
- break;
- case pt_blood:
- a = CL_PointSuperContents(p->org);
- if (a & (SUPERCONTENTS_WATER | SUPERCONTENTS_SLIME))
- {
- p->size += frametime * 8;
- //p->alpha -= bloodwaterfade;
- }
- else
- p->vel[2] -= gravity;
- if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP))
- p->type = NULL;
- break;
- case pt_bubble:
- a = CL_PointSuperContents(p->org);
- if (!(a & (SUPERCONTENTS_WATER | SUPERCONTENTS_SLIME)))
- {
- p->type = NULL;
- break;
- }
- break;
- case pt_rain:
- a = CL_PointSuperContents(p->org);
- if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK))
- p->type = NULL;
- break;
- case pt_snow:
- if (cl.time > p->time2)
- {
- // snow flutter
- p->time2 = cl.time + (rand() & 3) * 0.1;
- p->vel[0] = p->relativedirection[0] + lhrandom(-32, 32);
- p->vel[1] = p->relativedirection[1] + lhrandom(-32, 32);
- //p->vel[2] = p->relativedirection[2] + lhrandom(-32, 32);
- }
- a = CL_PointSuperContents(p->org);
- if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK))
- p->type = NULL;
- break;
- default:
- break;
- }
- }
- }
- cl.num_particles = maxparticle + 1;
-}
-
-#define MAX_PARTICLETEXTURES 64
-// particletexture_t is a rectangle in the particlefonttexture
-typedef struct particletexture_s
-{
- rtexture_t *texture;
- float s1, t1, s2, t2;
-}
-particletexture_t;
-
-static rtexturepool_t *particletexturepool;
-static rtexture_t *particlefonttexture;
-static particletexture_t particletexture[MAX_PARTICLETEXTURES];
-