-/*
-===============
-CL_MoveDecals
-===============
-*/
-void CL_MoveDecals (void)
-{
- decal_t *decal;
- int i;
- float decalfade;
-
- // LordHavoc: early out condition
- if (!cl.num_decals)
- {
- cl.free_decal = 0;
- return;
- }
-
- decalfade = bound(0, cl.time - cl.oldtime, 0.1) * 255 / cl_decals_fadetime.value;
-
- for (i = 0, decal = cl.decals;i < cl.num_decals;i++, decal++)
- {
- if (!decal->typeindex)
- continue;
-
- // heavily optimized decal case
- // FIXME: this has fairly wacky handling of alpha
- if (cl.time > decal->time2 + cl_decals_time.value)
- {
- decal->alpha -= decalfade;
- if (decal->alpha <= 0)
- {
- decal->typeindex = 0;
- if (cl.free_decal > i)
- cl.free_decal = i;
- continue;
- }
- }
-
- if (decal->owner)
- {
- if (cl.entities[decal->owner].render.model == decal->ownermodel)
- {
- Matrix4x4_Transform(&cl.entities[decal->owner].render.matrix, decal->relativeorigin, decal->org);
- Matrix4x4_Transform3x3(&cl.entities[decal->owner].render.matrix, decal->relativenormal, decal->normal);
- }
- else
- {
- decal->typeindex = 0;
- if (cl.free_decal > i)
- cl.free_decal = i;
- }
- }
- }
-
- // reduce cl.num_decals if possible
- while (cl.num_decals > 0 && cl.decals[cl.num_decals - 1].typeindex == 0)
- cl.num_decals--;
-}
-
-/*
-===============
-CL_MoveParticles
-===============
-*/
-void CL_MoveParticles (void)
-{
- particle_t *p;
- int i, j, a, content;
- float gravity, dvel, decalfade, frametime, f, dist, oldorg[3];
- int hitent;
- trace_t trace;
-
- // LordHavoc: early out condition
- if (!cl.num_particles)
- {
- cl.free_particle = 0;
- return;
- }
-
- frametime = bound(0, cl.time - cl.oldtime, 0.1);
- gravity = frametime * cl.movevars_gravity;
- dvel = 1+4*frametime;
- decalfade = frametime * 255 / cl_decals_fadetime.value;
-
- j = 0;
- for (i = 0, p = cl.particles;i < cl.num_particles;i++, p++)
- {
- if (!p->typeindex)
- {
- if (cl.free_particle > i)
- cl.free_particle = i;
- continue;
- }
-
- if (p->delayedspawn)
- {
- if (p->delayedspawn > cl.time)
- continue;
- p->delayedspawn = 0;
- }
-
- content = 0;
-
- p->size += p->sizeincrease * frametime;
- p->alpha -= p->alphafade * frametime;
-
- if (p->alpha <= 0 || p->die <= cl.time)
- {
- p->typeindex = 0;
- if (cl.free_particle > i)
- cl.free_particle = i;
- continue;
- }
-
- if (particletype[p->typeindex].orientation != PARTICLE_BEAM && frametime > 0)
- {
- if (p->liquidfriction && (CL_PointSuperContents(p->org) & SUPERCONTENTS_LIQUIDSMASK))
- {
- if (p->typeindex == pt_blood)
- p->size += frametime * 8;
- else
- p->vel[2] -= p->gravity * gravity;
- f = 1.0f - min(p->liquidfriction * frametime, 1);
- VectorScale(p->vel, f, p->vel);
- }
- else
- {
- p->vel[2] -= p->gravity * gravity;
- if (p->airfriction)
- {
- f = 1.0f - min(p->airfriction * frametime, 1);
- VectorScale(p->vel, f, p->vel);
- }
- }
-
- VectorCopy(p->org, oldorg);
- VectorMA(p->org, frametime, p->vel, p->org);
- if (p->bounce && cl.time >= p->delayedcollisions)
- {
- trace = CL_Move(oldorg, vec3_origin, vec3_origin, p->org, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, &hitent, 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) || (trace.startsupercontents & SUPERCONTENTS_SOLID))
- {
- p->typeindex = 0;
- if (cl.free_particle > i)
- cl.free_particle = i;
- continue;
- }
- VectorCopy(trace.endpos, p->org);
- // react if the particle hit something
- if (trace.fraction < 1)
- {
- VectorCopy(trace.endpos, p->org);
- if (p->typeindex == 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->typeindex = 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 * 20;
- count = (int)lhrandom(1, 10);
- while(count--)
- CL_NewParticle(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, cl.movevars_gravity * 0.04 + p->vel[2]*16, 0, 0, 0, 32);
- continue;
- }
- else if (p->typeindex == pt_blood)
- {
- // blood - splash on solid
- if (trace.hitq3surfaceflags & Q3SURFACEFLAG_NOMARKS)
- {
- p->typeindex = 0;
- continue;
- }
- 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)));
- if (!cl_decals.integer)
- {
- p->typeindex = 0;
- continue;
- }
- // create a decal for the blood splat
- CL_SpawnDecalParticleForSurface(hitent, p->org, trace.plane.normal, p->color[0] * 65536 + p->color[1] * 256 + p->color[2], p->color[0] * 65536 + p->color[1] * 256 + p->color[2], tex_blooddecal[rand()&7], p->size * 2, p->alpha);
- p->typeindex = 0;
- if (cl.free_particle > i)
- cl.free_particle = i;
- continue;
- }
- else if (p->bounce < 0)
- {
- // bounce -1 means remove on impact
- p->typeindex = 0;
- if (cl.free_particle > i)
- cl.free_particle = i;
- 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);
- }
- }
- }
- }
-
- if (p->typeindex != pt_static)
- {
- switch (p->typeindex)
- {
- case pt_entityparticle:
- // particle that removes itself after one rendered frame
- if (p->time2)
- {
- p->typeindex = 0;
- if (cl.free_particle > i)
- cl.free_particle = i;
- }
- else
- p->time2 = 1;
- break;
- case pt_blood:
- a = CL_PointSuperContents(p->org);
- if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP))
- {
- p->typeindex = 0;
- if (cl.free_particle > i)
- cl.free_particle = i;
- }
- break;
- case pt_bubble:
- a = CL_PointSuperContents(p->org);
- if (!(a & (SUPERCONTENTS_WATER | SUPERCONTENTS_SLIME)))
- {
- p->typeindex = 0;
- if (cl.free_particle > i)
- cl.free_particle = i;
- }
- break;
- case pt_rain:
- a = CL_PointSuperContents(p->org);
- if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK))
- {
- p->typeindex = 0;
- if (cl.free_particle > i)
- cl.free_particle = i;
- }
- break;
- case pt_snow:
- if (cl.time > p->time2)
- {
- // snow flutter
- p->time2 = cl.time + (rand() & 3) * 0.1;
- p->vel[0] = p->vel[0] * 0.9f + lhrandom(-32, 32);
- p->vel[1] = p->vel[0] * 0.9f + lhrandom(-32, 32);
- }
- a = CL_PointSuperContents(p->org);
- if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK))
- {
- p->typeindex = 0;
- if (cl.free_particle > i)
- cl.free_particle = i;
- }
- break;
- default:
- break;
- }
- }
- }
-
- // reduce cl.num_particles if possible
- while (cl.num_particles > 0 && cl.particles[cl.num_particles - 1].typeindex == 0)
- cl.num_particles--;
-}
-