}
#else
#include "cl_collision.h"
+#include "image.h"
#endif
#define MAX_PARTICLES 32768 // default max # of particles at one time
typedef enum
{
- pt_static, pt_rain, pt_bubble, pt_blood, pt_grow, pt_decal, pt_decalfade
+ pt_dead, pt_static, pt_rain, pt_bubble, pt_blood, pt_grow, pt_decal, pt_decalfade, pt_ember
}
ptype_t;
static int cl_maxparticles;
static int cl_numparticles;
+static int cl_freeparticle;
static particle_t *particles;
-static particle_t **freeparticles; // list used only in compacting particles array
cvar_t cl_particles = {CVAR_SAVE, "cl_particles", "1"};
cvar_t cl_particles_quality = {CVAR_SAVE, "cl_particles_quality", "1"};
cvar_t cl_particles_blood_alpha = {CVAR_SAVE, "cl_particles_blood_alpha", "0.5"};
cvar_t cl_particles_blood_bloodhack = {CVAR_SAVE, "cl_particles_blood_bloodhack", "1"};
cvar_t cl_particles_bulletimpacts = {CVAR_SAVE, "cl_particles_bulletimpacts", "1"};
+cvar_t cl_particles_explosions_bubbles = {CVAR_SAVE, "cl_particles_explosions_bubbles", "1"};
+cvar_t cl_particles_explosions_smoke = {CVAR_SAVE, "cl_particles_explosions_smokes", "0"};
+cvar_t cl_particles_explosions_sparks = {CVAR_SAVE, "cl_particles_explosions_sparks", "1"};
+cvar_t cl_particles_explosions_shell = {CVAR_SAVE, "cl_particles_explosions_shell", "0"};
cvar_t cl_particles_smoke = {CVAR_SAVE, "cl_particles_smoke", "1"};
cvar_t cl_particles_smoke_alpha = {CVAR_SAVE, "cl_particles_smoke_alpha", "0.5"};
cvar_t cl_particles_smoke_alphafade = {CVAR_SAVE, "cl_particles_smoke_alphafade", "0.55"};
void CL_Particles_Clear(void)
{
cl_numparticles = 0;
+ cl_freeparticle = 0;
+ memset(particles, 0, sizeof(particle_t) * cl_maxparticles);
}
/*
Cvar_RegisterVariable (&cl_particles_blood);
Cvar_RegisterVariable (&cl_particles_blood_alpha);
Cvar_RegisterVariable (&cl_particles_blood_bloodhack);
+ Cvar_RegisterVariable (&cl_particles_explosions_bubbles);
+ Cvar_RegisterVariable (&cl_particles_explosions_smoke);
+ Cvar_RegisterVariable (&cl_particles_explosions_sparks);
+ Cvar_RegisterVariable (&cl_particles_explosions_shell);
Cvar_RegisterVariable (&cl_particles_bulletimpacts);
Cvar_RegisterVariable (&cl_particles_smoke);
Cvar_RegisterVariable (&cl_particles_smoke_alpha);
#ifdef WORKINGLQUAKE
particles = (particle_t *) Hunk_AllocName(cl_maxparticles * sizeof(particle_t), "particles");
- freeparticles = (void *) Hunk_AllocName(cl_maxparticles * sizeof(particle_t *), "particles");
#else
- cl_part_mempool = Mem_AllocPool("CL_Part");
+ cl_part_mempool = Mem_AllocPool("CL_Part", 0, NULL);
particles = (particle_t *) Mem_Alloc(cl_part_mempool, cl_maxparticles * sizeof(particle_t));
- freeparticles = (void *) Mem_Alloc(cl_part_mempool, cl_maxparticles * sizeof(particle_t *));
#endif
- cl_numparticles = 0;
+ CL_Particles_Clear();
}
// list of all 26 parameters:
// ppressure - pushes other particles away if they are within 64 units distance, the force is based on scalex, this feature is supported but not currently used
particle_t *particle(ptype_t ptype, porientation_t porientation, int pcolor1, int pcolor2, int ptex, int plight, pblend_t pblendmode, float pscalex, float pscaley, float palpha, float palphafade, float ptime, float pgravity, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz, float ptime2, float pvx2, float pvy2, float pvz2, float pfriction, float ppressure)
{
- if (cl_numparticles < cl_maxparticles)
+ particle_t *part;
+ int ptempcolor, ptempcolor2, pcr1, pcg1, pcb1, pcr2, pcg2, pcb2;
+ ptempcolor = (pcolor1);
+ ptempcolor2 = (pcolor2);
+ pcr2 = ((ptempcolor2) >> 16) & 0xFF;
+ pcg2 = ((ptempcolor2) >> 8) & 0xFF;
+ pcb2 = (ptempcolor2) & 0xFF;
+ if (ptempcolor != ptempcolor2)
{
- particle_t *part;
- int ptempcolor, ptempcolor2, pcr1, pcg1, pcb1, pcr2, pcg2, pcb2;
- ptempcolor = (pcolor1);
- ptempcolor2 = (pcolor2);
- pcr2 = ((ptempcolor2) >> 16) & 0xFF;
- pcg2 = ((ptempcolor2) >> 8) & 0xFF;
- pcb2 = (ptempcolor2) & 0xFF;
- if (ptempcolor != ptempcolor2)
- {
- pcr1 = ((ptempcolor) >> 16) & 0xFF;
- pcg1 = ((ptempcolor) >> 8) & 0xFF;
- pcb1 = (ptempcolor) & 0xFF;
- ptempcolor = rand() & 0xFF;
- pcr2 = (((pcr2 - pcr1) * ptempcolor) >> 8) + pcr1;
- pcg2 = (((pcg2 - pcg1) * ptempcolor) >> 8) + pcg1;
- pcb2 = (((pcb2 - pcb1) * ptempcolor) >> 8) + pcb1;
- }
- part = &particles[cl_numparticles++];
- memset(part, 0, sizeof(*part));
- part->type = (ptype);
- part->color[0] = pcr2;
- part->color[1] = pcg2;
- part->color[2] = pcb2;
- part->color[3] = 0xFF;
- part->orientation = porientation;
- part->texnum = ptex;
- part->blendmode = pblendmode;
- part->scalex = (pscalex);
- part->scaley = (pscaley);
- part->alpha = (palpha);
- part->alphafade = (palphafade);
- part->die = cl.time + (ptime);
- part->gravity = (pgravity);
- part->bounce = (pbounce);
- part->org[0] = (px);
- part->org[1] = (py);
- part->org[2] = (pz);
- part->vel[0] = (pvx);
- part->vel[1] = (pvy);
- part->vel[2] = (pvz);
- part->time2 = (ptime2);
- part->vel2[0] = (pvx2);
- part->vel2[1] = (pvy2);
- part->vel2[2] = (pvz2);
- part->friction = (pfriction);
- part->pressure = (ppressure);
- return part;
+ pcr1 = ((ptempcolor) >> 16) & 0xFF;
+ pcg1 = ((ptempcolor) >> 8) & 0xFF;
+ pcb1 = (ptempcolor) & 0xFF;
+ ptempcolor = rand() & 0xFF;
+ pcr2 = (((pcr2 - pcr1) * ptempcolor) >> 8) + pcr1;
+ pcg2 = (((pcg2 - pcg1) * ptempcolor) >> 8) + pcg1;
+ pcb2 = (((pcb2 - pcb1) * ptempcolor) >> 8) + pcb1;
}
- return NULL;
+ for (;cl_freeparticle < cl_maxparticles && particles[cl_freeparticle].type;cl_freeparticle++);
+ if (cl_freeparticle >= cl_maxparticles)
+ return NULL;
+ part = &particles[cl_freeparticle++];
+ if (cl_numparticles < cl_freeparticle)
+ cl_numparticles = cl_freeparticle;
+ memset(part, 0, sizeof(*part));
+ part->type = (ptype);
+ part->color[0] = pcr2;
+ part->color[1] = pcg2;
+ part->color[2] = pcb2;
+ part->color[3] = 0xFF;
+ part->orientation = porientation;
+ part->texnum = ptex;
+ part->blendmode = pblendmode;
+ part->scalex = (pscalex);
+ part->scaley = (pscaley);
+ part->alpha = (palpha);
+ part->alphafade = (palphafade);
+ part->die = cl.time + (ptime);
+ part->gravity = (pgravity);
+ part->bounce = (pbounce);
+ part->org[0] = (px);
+ part->org[1] = (py);
+ part->org[2] = (pz);
+ part->vel[0] = (pvx);
+ part->vel[1] = (pvy);
+ part->vel[2] = (pvz);
+ part->time2 = (ptime2);
+ part->vel2[0] = (pvx2);
+ part->vel2[1] = (pvy2);
+ part->vel2[2] = (pvz2);
+ part->friction = (pfriction);
+ part->pressure = (ppressure);
+ return part;
}
void CL_SpawnDecalParticleForSurface(void *hitent, const vec3_t org, const vec3_t normal, int color1, int color2, int texnum, float size, float alpha)
#if WORKINGLQUAKE
pointfile = COM_LoadTempFile (name);
#else
- pointfile = FS_LoadFile(name, true);
+ pointfile = FS_LoadFile(name, tempmempool, true);
#endif
if (!pointfile)
{
*/
void CL_ParticleExplosion (vec3_t org)
{
- int i, k;
+ int i;
//vec3_t v;
//vec3_t v2;
if (cl_stainmaps.integer)
CL_SpawnDecalParticleForPoint(org, 40, 48, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
i = CL_PointQ1Contents(org);
- if ((i == CONTENTS_SLIME || i == CONTENTS_WATER) && cl_particles.integer && cl_particles_bubbles.integer)
+ if (i == CONTENTS_SLIME || i == CONTENTS_WATER)
{
- for (i = 0;i < 128 * cl_particles_quality.value;i++)
- particle(pt_bubble, PARTICLE_BILLBOARD, 0x404040, 0x808080, tex_bubble, false, PBLEND_ADD, 2, 2, (1.0f / cl_particles_quality.value) * lhrandom(128, 255), (1.0f / cl_particles_quality.value) * 256, 9999, -0.25, 1.5, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-96, 96), lhrandom(-96, 96), lhrandom(-96, 96), 0, 0, 0, 0, (1.0 / 16.0), 0);
+ if (cl_particles.integer && cl_particles_bubbles.integer && cl_particles_explosions_bubbles.integer)
+ for (i = 0;i < 128 * cl_particles_quality.value;i++)
+ particle(pt_bubble, PARTICLE_BILLBOARD, 0x404040, 0x808080, tex_bubble, false, PBLEND_ADD, 2, 2, (1.0f / cl_particles_quality.value) * lhrandom(128, 255), (1.0f / cl_particles_quality.value) * 256, 9999, -0.25, 1.5, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-96, 96), lhrandom(-96, 96), lhrandom(-96, 96), 0, 0, 0, 0, (1.0 / 16.0), 0);
}
else
{
- /*
// LordHavoc: smoke effect similar to UT2003, chews fillrate too badly up close
// smoke puff
- if (cl_particles.integer && cl_particles_smoke.integer)
+ if (cl_particles.integer && cl_particles_smoke.integer && cl_particles_explosions_smoke.integer)
{
- for (i = 0;i < 64;i++)
+ for (i = 0;i < 32;i++)
{
+ int k;
+ vec3_t v, v2;
#ifdef WORKINGLQUAKE
- v2[0] = lhrandom(-64, 64);
- v2[1] = lhrandom(-64, 64);
- v2[2] = lhrandom(-8, 24);
+ v2[0] = lhrandom(-48, 48);
+ v2[1] = lhrandom(-48, 48);
+ v2[2] = lhrandom(-48, 48);
#else
for (k = 0;k < 16;k++)
{
- v[0] = org[0] + lhrandom(-64, 64);
- v[1] = org[1] + lhrandom(-64, 64);
- v[2] = org[2] + lhrandom(-8, 24);
+ v[0] = org[0] + lhrandom(-48, 48);
+ v[1] = org[1] + lhrandom(-48, 48);
+ v[2] = org[2] + lhrandom(-48, 48);
if (CL_TraceLine(org, v, v2, NULL, true, NULL, SUPERCONTENTS_SOLID) >= 0.1)
break;
}
VectorSubtract(v2, org, v2);
#endif
VectorScale(v2, 2.0f, v2);
- particle(pt_static, PARTICLE_BILLBOARD, 0x101010, 0x202020, tex_smoke[rand()&7], true, PBLEND_ADD, 12, 12, 255, 512, 9999, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0, 0, 0, 0, 0, 0);
+ particle(pt_static, PARTICLE_BILLBOARD, 0xFFFFFF, 0xFFFFFF, tex_smoke[rand()&7], true, PBLEND_ADD, 12, 12, 32, 64, 9999, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0, 0, 0, 0, 0, 0);
}
}
- */
- if (cl_particles.integer && cl_particles_sparks.integer)
- {
- // sparks
+#if 1
+ if (cl_particles.integer && cl_particles_sparks.integer && cl_particles_explosions_sparks.integer)
+ for (i = 0;i < 128 * cl_particles_quality.value;i++)
+ particle(pt_static, PARTICLE_SPARK, 0x903010, 0xFFD030, tex_particle, false, PBLEND_ADD, 1.0f, 0.02f, (1.0f / cl_particles_quality.value) * lhrandom(0, 255), (1.0f / cl_particles_quality.value) * 512, 9999, 1, 0, org[0], org[1], org[2], lhrandom(-256, 256), lhrandom(-256, 256), lhrandom(-256, 256) + 80, 0, 0, 0, 0, 0.2, 0);
+#elif 1
+ if (cl_particles.integer && cl_particles_sparks.integer && cl_particles_explosions_sparks.integer)
+ for (i = 0;i < 64 * cl_particles_quality.value;i++)
+ particle(pt_ember, PARTICLE_SPARK, 0x903010, 0xFFD030, tex_particle, false, PBLEND_ADD, 1.0f, 0.01f, (1.0f / cl_particles_quality.value) * lhrandom(0, 255), (1.0f / cl_particles_quality.value) * 256, 9999, 0.7, 0, org[0], org[1], org[2], lhrandom(-256, 256), lhrandom(-256, 256), lhrandom(-256, 256) + 80, cl.time, 0, 0, 0, 0, 0);
+#else
+ if (cl_particles.integer && cl_particles_sparks.integer && cl_particles_explosions_sparks.integer)
for (i = 0;i < 256 * cl_particles_quality.value;i++)
- {
- k = particlepalette[0x68 + (rand() & 7)];
- particle(pt_static, PARTICLE_SPARK, k, k, tex_particle, false, PBLEND_ADD, 1.5f, 0.05f, (1.0f / cl_particles_quality.value) * lhrandom(0, 255), (1.0f / cl_particles_quality.value) * 512, 9999, 1, 0, org[0], org[1], org[2], lhrandom(-192, 192), lhrandom(-192, 192), lhrandom(-192, 192) + 160, 0, 0, 0, 0, 0, 0);
- }
- }
+ particle(pt_static, PARTICLE_SPARK, 0x903010, 0xFFD030, tex_particle, false, PBLEND_ADD, 1.5f, 0.05f, (1.0f / cl_particles_quality.value) * lhrandom(0, 255), (1.0f / cl_particles_quality.value) * 512, 9999, 1, 0, org[0], org[1], org[2], lhrandom(-192, 192), lhrandom(-192, 192), lhrandom(-192, 192) + 160, 0, 0, 0, 0, 0.2, 0);
+#endif
}
- if (cl_explosions.integer)
+ if (cl_particles_explosions_shell.integer)
R_NewExplosion(org);
}
*/
void CL_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
{
+ vec3_t vel;
+ vec3_t offset;
int i, k;
+ float pscale;
if (!cl_particles.integer) return;
for (i = 0;i < 512 * cl_particles_quality.value;i++)
{
+ VectorRandom (offset);
+ VectorScale (offset, 192, vel);
+ VectorScale (offset, 8, offset);
k = particlepalette[colorStart + (i % colorLength)];
- particle(pt_static, PARTICLE_BILLBOARD, k, k, tex_particle, false, PBLEND_ALPHA, 1.5, 1.5, (1.0f / cl_particles_quality.value) * 255, (1.0f / cl_particles_quality.value) * 384, 0.3, 0, 0, org[0] + lhrandom(-8, 8), org[1] + lhrandom(-8, 8), org[2] + lhrandom(-8, 8), lhrandom(-192, 192), lhrandom(-192, 192), lhrandom(-192, 192), 0, 0, 0, 0, 1, 0);
+ pscale = lhrandom(0.5, 1.5);
+ particle(pt_static, PARTICLE_BILLBOARD, k, k, tex_particle, false, PBLEND_ADD, pscale, pscale, (1.0f / cl_particles_quality.value) * 255, (1.0f/cl_particles_quality.value)*512, 9999, 0, 0, org[0] + offset[0], org[1] + offset[1], org[2] + offset[2], vel[0], vel[1], vel[2], 0, 0, 0, 0, lhrandom(1.5, 3), 0);
}
}
*/
void CL_BlobExplosion (vec3_t org)
{
- if (cl_stainmaps.integer)
- R_Stain(org, 96, 80, 80, 80, 64, 176, 176, 176, 64);
- CL_SpawnDecalParticleForPoint(org, 40, 48, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
-
- if (cl_explosions.integer)
- R_NewExplosion(org);
+ CL_ParticleExplosion(org);
}
/*
org2[1] = org[1] + 0.125f * lhrandom(-count, count);
org2[2] = org[2] + 0.125f * lhrandom(-count, count);
CL_TraceLine(org, org2, org3, NULL, true, NULL, SUPERCONTENTS_SOLID);
- particle(pt_grow, PARTICLE_BILLBOARD, 0x101010, 0x202020, tex_smoke[rand()&7], true, PBLEND_ADD, 3, 3, (1.0f / cl_particles_quality.value) * 255, (1.0f / cl_particles_quality.value) * 1024, 9999, -0.2, 0, org3[0], org3[1], org3[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(0, 16), 15, 0, 0, 0, 0, 0);
+ particle(pt_grow, PARTICLE_BILLBOARD, 0x101010, 0x202020, tex_smoke[rand()&7], true, PBLEND_ADD, 3, 3, (1.0f / cl_particles_quality.value) * 255, (1.0f / cl_particles_quality.value) * 1024, 9999, -0.2, 0, org3[0], org3[1], org3[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(0, 16), 15, 0, 0, 0, 0.2, 0);
}
}
while(count--)
{
k = particlepalette[0x68 + (rand() & 7)];
- particle(pt_static, PARTICLE_SPARK, k, k, tex_particle, false, PBLEND_ADD, 0.4f, 0.015f, (1.0f / cl_particles_quality.value) * lhrandom(64, 255), (1.0f / cl_particles_quality.value) * 512, 9999, 1, 0, org[0], org[1], org[2], lhrandom(-64, 64) + dir[0], lhrandom(-64, 64) + dir[1], lhrandom(0, 128) + dir[2], 0, 0, 0, 0, 0, 0);
+ particle(pt_static, PARTICLE_SPARK, k, k, tex_particle, false, PBLEND_ADD, 0.4f, 0.015f, (1.0f / cl_particles_quality.value) * lhrandom(64, 255), (1.0f / cl_particles_quality.value) * 512, 9999, 1, 0, org[0], org[1], org[2], lhrandom(-64, 64) + dir[0], lhrandom(-64, 64) + dir[1], lhrandom(0, 128) + dir[2], 0, 0, 0, 0, 0.2, 0);
}
}
}
VectorNormalizeFast(v);
VectorScale(v, 100, v);
v[2] += sv_gravity.value * 0.15f;
- particle(pt_static, PARTICLE_BILLBOARD, 0x903010, 0xFFD030, tex_particle, false, PBLEND_ADD, 1.5, 1.5, lhrandom(64, 128) / cl_particles_quality.value, 128 / cl_particles_quality.value, 9999, 1, 0, o[0], o[1], o[2], v[0], v[1], v[2], 0, 0, 0, 0, 0, 0);
+ particle(pt_static, PARTICLE_BILLBOARD, 0x903010, 0xFFD030, tex_particle, false, PBLEND_ADD, 1.5, 1.5, lhrandom(64, 128) / cl_particles_quality.value, 128 / cl_particles_quality.value, 9999, 1, 0, o[0], o[1], o[2], v[0], v[1], v[2], 0, 0, 0, 0, 0.2, 0);
}
}
{
if (gamemode == GAME_GOODVSBAD2)
particle(pt_static, PARTICLE_BILLBOARD, particlepalette[0 + (rand()&255)], particlepalette[0 + (rand()&255)], tex_particle, false, PBLEND_ALPHA, 6, 6, qd*255, qd*384, 9999, 0, 0, pos[0], pos[1], pos[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 0, 0, 0, 0, 0, 0);
+ else if (gamemode == GAME_PRYDON)
+ particle(pt_static, PARTICLE_BILLBOARD, 0x103040, 0x204050, tex_particle, false, PBLEND_ADD, 6, 6, qd*128, qd*384, 9999, 0, 0, pos[0], pos[1], pos[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 0, 0, 0, 0, 0, 0);
else
particle(pt_static, PARTICLE_BILLBOARD, 0x502030, 0x502030, tex_particle, false, PBLEND_ADD, 6, 6, qd*128, qd*384, 9999, 0, 0, pos[0], pos[1], pos[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 0, 0, 0, 0, 0, 0);
}
void CL_MoveParticles (void)
{
particle_t *p;
- int i, activeparticles, maxparticle, j, a, pressureused = false, content;
+ int i, maxparticle, j, a, content;
float gravity, dvel, bloodwaterfade, frametime, f, dist, normal[3], v[3], org[3];
#ifdef WORKINGLQUAKE
void *hitent;
// LordHavoc: early out condition
if (!cl_numparticles)
+ {
+ cl_freeparticle = 0;
return;
+ }
#ifdef WORKINGLQUAKE
frametime = cl.frametime;
dvel = 1+4*frametime;
bloodwaterfade = max(cl_particles_blood_alpha.value, 0.01f) * frametime * 128.0f;
- activeparticles = 0;
maxparticle = -1;
j = 0;
for (i = 0, p = particles;i < cl_numparticles;i++, p++)
{
+ if (!p->type)
+ continue;
+ maxparticle = i;
content = 0;
VectorCopy(p->org, p->oldorg);
VectorMA(p->org, frametime, p->vel, p->org);
if (cl_stainmaps.integer)
R_Stain(v, 32, 32, 16, 16, p->alpha * p->scalex * (1.0f / 40.0f), 192, 48, 48, p->alpha * p->scalex * (1.0f / 40.0f));
#endif
- if (cl_decals.integer)
+ if (!cl_decals.integer)
{
- p->type = pt_decal;
- p->orientation = PARTICLE_ORIENTED_DOUBLESIDED;
- // convert from a blood particle to a blood decal
- p->texnum = tex_blooddecal[rand()&7];
-#ifndef WORKINGLQUAKE
- p->owner = hitent;
- p->ownermodel = hitent->model;
- Matrix4x4_Transform(&hitent->inversematrix, v, p->relativeorigin);
- Matrix4x4_Transform3x3(&hitent->inversematrix, normal, p->relativedirection);
- VectorAdd(p->relativeorigin, p->relativedirection, p->relativeorigin);
-#endif
- p->time2 = cl.time + cl_decals_time.value;
- p->die = p->time2 + cl_decals_fadetime.value;
- p->alphafade = 0;
- VectorCopy(normal, p->vel2);
- VectorClear(p->vel);
- VectorAdd(p->org, normal, p->org);
- p->bounce = 0;
- p->friction = 0;
- p->gravity = 0;
- p->scalex *= 1.25f;
- p->scaley *= 1.25f;
- }
- else
- {
- p->die = -1;
- freeparticles[j++] = p;
+ p->type = pt_dead;
continue;
}
+
+ p->type = pt_decal;
+ p->orientation = PARTICLE_ORIENTED_DOUBLESIDED;
+ // convert from a blood particle to a blood decal
+ p->texnum = tex_blooddecal[rand()&7];
+#ifndef WORKINGLQUAKE
+ p->owner = hitent;
+ p->ownermodel = hitent->model;
+ Matrix4x4_Transform(&hitent->inversematrix, v, p->relativeorigin);
+ Matrix4x4_Transform3x3(&hitent->inversematrix, normal, p->relativedirection);
+ VectorAdd(p->relativeorigin, p->relativedirection, p->relativeorigin);
+#endif
+ p->time2 = cl.time + cl_decals_time.value;
+ p->die = p->time2 + cl_decals_fadetime.value;
+ p->alphafade = 0;
+ VectorCopy(normal, p->vel2);
+ VectorClear(p->vel);
+ VectorAdd(p->org, normal, p->org);
+ p->bounce = 0;
+ p->friction = 0;
+ p->gravity = 0;
+ p->scalex *= 1.25f;
+ p->scaley *= 1.25f;
}
else
{
}
}
}
+
p->vel[2] -= p->gravity * gravity;
+
p->alpha -= p->alphafade * frametime;
+
+ if (p->alpha <= 0 || cl.time > p->die)
+ {
+ p->type = pt_dead;
+ continue;
+ }
+
if (p->friction)
{
f = p->friction * frametime;
//p->alpha -= bloodwaterfade;
}
else
- p->die = -1;
+ p->type = pt_dead;
}
else
p->vel[2] -= gravity;
content = CL_PointQ1Contents(p->org);
if (content != CONTENTS_WATER && content != CONTENTS_SLIME)
{
- p->die = -1;
+ p->type = pt_dead;
break;
}
break;
content = CL_PointQ1Contents(p->org);
a = content;
if (a != CONTENTS_EMPTY && a != CONTENTS_SKY)
- p->die = -1;
+ p->type = pt_dead;
break;
case pt_grow:
p->scalex += frametime * p->time2;
{
Matrix4x4_Transform(&p->owner->matrix, p->relativeorigin, p->org);
Matrix4x4_Transform3x3(&p->owner->matrix, p->relativedirection, p->vel2);
+ if (cl.time > p->time2)
+ {
+ p->alphafade = p->alpha / (p->die - cl.time);
+ p->type = pt_decalfade;
+ }
}
else
- p->die = -1;
+ p->type = pt_dead;
#endif
- if (cl.time > p->time2)
- {
- p->alphafade = p->alpha / (p->die - cl.time);
- p->type = pt_decalfade;
- }
break;
case pt_decalfade:
#ifndef WORKINGLQUAKE
Matrix4x4_Transform3x3(&p->owner->matrix, p->relativedirection, p->vel2);
}
else
- p->die = -1;
+ p->type = pt_dead;
#endif
break;
+ case pt_ember:
+ while (cl.time > p->time2)
+ {
+ p->time2 += 0.025;
+ particle(pt_static, PARTICLE_SPARK, 0x903010, 0xFFD030, tex_particle, false, PBLEND_ADD, p->scalex * 0.75, p->scaley * 0.75, p->alpha, p->alphafade, 9999, 0.5, 0, p->org[0], p->org[1], p->org[2], p->vel[0] * lhrandom(0.4, 0.6), p->vel[1] * lhrandom(0.4, 0.6), p->vel[2] * lhrandom(0.4, 0.6), 0, 0, 0, 0, 0, 0);
+ }
+ break;
default:
Con_Printf("unknown particle type %i\n", p->type);
- p->die = -1;
+ p->type = pt_dead;
break;
}
}
-
- // remove dead particles
- if (p->alpha < 1 || p->die < cl.time)
- freeparticles[j++] = p;
- else
- {
- maxparticle = i;
- activeparticles++;
- if (p->pressure)
- pressureused = true;
- }
- }
- // fill in gaps to compact the array
- i = 0;
- while (maxparticle >= activeparticles)
- {
- *freeparticles[i++] = particles[maxparticle--];
- while (maxparticle >= activeparticles && particles[maxparticle].die < cl.time)
- maxparticle--;
- }
- cl_numparticles = activeparticles;
-
- if (pressureused)
- {
- activeparticles = 0;
- for (i = 0, p = particles;i < cl_numparticles;i++, p++)
- if (p->pressure)
- freeparticles[activeparticles++] = p;
-
- if (activeparticles)
- {
- for (i = 0, p = particles;i < cl_numparticles;i++, p++)
- {
- for (j = 0;j < activeparticles;j++)
- {
- if (freeparticles[j] != p)
- {
- float dist, diff[3];
- VectorSubtract(p->org, freeparticles[j]->org, diff);
- dist = DotProduct(diff, diff);
- if (dist < 4096 && dist >= 1)
- {
- dist = freeparticles[j]->scalex * 4.0f * frametime / sqrt(dist);
- VectorMA(p->vel, dist, diff, p->vel);
- }
- }
- }
- }
- }
}
+ cl_numparticles = maxparticle + 1;
+ cl_freeparticle = 0;
}
#define MAX_PARTICLETEXTURES 64
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#else
- particlefonttexture = R_LoadTexture2D(particletexturepool, "particlefont", 256, 256, particletexturedata, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
+ particlefonttexture = loadtextureimage(particletexturepool, "particles/particlefont.tga", 0, 0, false, TEXF_ALPHA | TEXF_PRECACHE);
+ if (!particlefonttexture)
+ particlefonttexture = R_LoadTexture2D(particletexturepool, "particlefont", 256, 256, particletexturedata, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
for (i = 0;i < MAX_PARTICLETEXTURES;i++)
particletexture[i].texture = particlefonttexture;
- // beam
+ // nexbeam
fractalnoise(&noise1[0][0], 64, 4);
m = 0;
for (y = 0;y < 64;y++)
}
}
- particletexture[tex_beam].texture = R_LoadTexture2D(particletexturepool, "beam", 16, 64, &data2[0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", 0, 0, false, TEXF_ALPHA | TEXF_PRECACHE);
+ if (!particletexture[tex_beam].texture)
+ particletexture[tex_beam].texture = R_LoadTexture2D(particletexturepool, "nexbeam", 16, 64, &data2[0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
particletexture[tex_beam].s1 = 0;
particletexture[tex_beam].t1 = 0;
particletexture[tex_beam].s2 = 1;
static void r_part_newmap(void)
{
cl_numparticles = 0;
+ cl_freeparticle = 0;
}
void R_Particles_Init (void)
}
}
- GL_ColorPointer(NULL);
- GL_Color(cr, cg, cb, ca);
-
R_Mesh_Matrix(&r_identitymatrix);
memset(&m, 0, sizeof(m));
m.tex[0] = R_GetTexture(tex->texture);
m.pointer_texcoord[0] = particle_texcoord2f;
- R_Mesh_State_Texture(&m);
+ m.pointer_vertex = particle_vertex3f;
+ R_Mesh_State(&m);
+
+ GL_Color(cr, cg, cb, ca);
if (p->blendmode == 0)
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
GL_DepthMask(false);
GL_DepthTest(true);
- GL_VertexPointer(particle_vertex3f);
#endif
if (p->orientation == PARTICLE_BILLBOARD || p->orientation == PARTICLE_ORIENTED_DOUBLESIDED)
{
glDepthMask(0);
// LordHavoc: only render if not too close
for (i = 0, p = particles;i < cl_numparticles;i++, p++)
- if (DotProduct(p->org, r_viewforward) >= minparticledist)
+ if (p->type && DotProduct(p->org, r_viewforward) >= minparticledist)
R_DrawParticle(p);
glDepthMask(1);
glDisable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#else
// LordHavoc: only render if not too close
- c_particles += cl_numparticles;
for (i = 0, p = particles;i < cl_numparticles;i++, p++)
- if (DotProduct(p->org, r_viewforward) >= minparticledist || p->orientation == PARTICLE_BEAM)
- R_MeshQueue_AddTransparent(p->org, R_DrawParticleCallback, p, 0);
+ {
+ if (p->type)
+ {
+ c_particles++;
+ if (DotProduct(p->org, r_viewforward) >= minparticledist || p->orientation == PARTICLE_BEAM)
+ R_MeshQueue_AddTransparent(p->org, R_DrawParticleCallback, p, 0);
+ }
+ }
#endif
}