X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=cl_particles.c;h=3c16601b38d3711cf68e831b4d4bbf087c849707;hb=813af879dc83087e91430dff5962dfa6b3127f9d;hp=3313af09cf7f0f697742d2a84a7d28a968be4736;hpb=bff2055635d6a0b18173b0b7a8f5aa7741d1dd4e;p=xonotic%2Fdarkplaces.git diff --git a/cl_particles.c b/cl_particles.c index 3313af09..3c16601b 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -32,11 +32,14 @@ ptype_t; typedef struct particle_s { ptype_t type; + int orientation; // typically PARTICLE_BILLBOARD vec3_t org; vec3_t vel; + int additive; int tex; float die; - float scale; + float scalex; + float scaley; float alpha; // 0-255 float time2; // used for various things (snow fluttering, for example) float bounce; // how much bounce-back from a surface the particle hits (0 = no physics, 1 = stop and slide, 2 = keep bouncing forever, 1.5 is typical) @@ -45,7 +48,7 @@ typedef struct particle_s float friction; // how much air friction affects this object (objects with a low mass/size ratio tend to get more air friction) float pressure; // if non-zero, apply pressure to other particles int dynlight; // if set the particle will be dynamically lit (if cl_dynamicparticles is on), used for smoke and blood - byte color[4]; + qbyte color[4]; } particle_t; @@ -90,12 +93,11 @@ static int explosparkramp[8] = {0x4b0700, 0x6f0f00, 0x931f07, 0xb7330f, 0xcf632b // these must match r_part.c's textures static const int tex_smoke[8] = {0, 1, 2, 3, 4, 5, 6, 7}; -static const int tex_bullethole[8] = {8, 9, 10, 11, 12, 13, 14, 15}; -static const int tex_rainsplash[16] = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; -static const int tex_particle = 32; -static const int tex_rain = 33; -static const int tex_bubble = 34; -static const int tex_rocketglow = 35; +static const int tex_rainsplash[16] = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; +static const int tex_particle = 24; +static const int tex_rain = 25; +static const int tex_bubble = 26; +static const int tex_rocketglow = 27; static int cl_maxparticles; static int cl_numparticles; @@ -107,6 +109,9 @@ static cvar_t cl_particles = {CVAR_SAVE, "cl_particles", "1"}; static cvar_t cl_particles_size = {CVAR_SAVE, "cl_particles_size", "1"}; static cvar_t cl_particles_bloodshowers = {CVAR_SAVE, "cl_particles_bloodshowers", "1"}; static cvar_t cl_particles_blood = {CVAR_SAVE, "cl_particles_blood", "1"}; +static cvar_t cl_particles_blood_size_min = {CVAR_SAVE, "cl_particles_blood_size_min", "3"}; +static cvar_t cl_particles_blood_size_max = {CVAR_SAVE, "cl_particles_blood_size_max", "15"}; +static cvar_t cl_particles_blood_alpha = {CVAR_SAVE, "cl_particles_blood_alpha", "1"}; static cvar_t cl_particles_smoke = {CVAR_SAVE, "cl_particles_smoke", "1"}; static cvar_t cl_particles_sparks = {CVAR_SAVE, "cl_particles_sparks", "1"}; static cvar_t cl_particles_bubbles = {CVAR_SAVE, "cl_particles_bubbles", "1"}; @@ -146,6 +151,9 @@ void CL_Particles_Init (void) Cvar_RegisterVariable (&cl_particles_size); Cvar_RegisterVariable (&cl_particles_bloodshowers); Cvar_RegisterVariable (&cl_particles_blood); + Cvar_RegisterVariable (&cl_particles_blood_size_min); + Cvar_RegisterVariable (&cl_particles_blood_size_max); + Cvar_RegisterVariable (&cl_particles_blood_alpha); Cvar_RegisterVariable (&cl_particles_smoke); Cvar_RegisterVariable (&cl_particles_sparks); Cvar_RegisterVariable (&cl_particles_bubbles); @@ -157,10 +165,10 @@ void CL_Particles_Init (void) cl_numparticles = 0; // FIXME: r_refdef stuff should be allocated somewhere else? - r_refdef.particles = cl_renderparticles = Mem_Alloc(cl_part_mempool, cl_maxparticles * sizeof(renderparticle_t)); + r_refdef.particles = cl_renderparticles = Mem_Alloc(cl_refdef_mempool, cl_maxparticles * sizeof(renderparticle_t)); } -#define particle(ptype, pcolor, ptex, plight, pscale, palpha, ptime, pbounce, px, py, pz, pvx, pvy, pvz, ptime2, pvx2, pvy2, pvz2, pfriction, ppressure)\ +#define particle(ptype, porientation, pcolor, ptex, plight, padditive, pscalex, pscaley, palpha, ptime, pbounce, px, py, pz, pvx, pvy, pvz, ptime2, pvx2, pvy2, pvz2, pfriction, ppressure)\ {\ particle_t *part;\ int tempcolor;\ @@ -174,8 +182,11 @@ void CL_Particles_Init (void) part->color[2] = (tempcolor) & 0xFF;\ part->color[3] = 0xFF;\ part->tex = (ptex);\ + part->orientation = (porientation);\ part->dynlight = (plight);\ - part->scale = (pscale);\ + part->additive = (padditive);\ + part->scalex = (pscalex);\ + part->scaley = (pscaley);\ part->alpha = (palpha);\ part->die = cl.time + (ptime);\ part->bounce = (pbounce);\ @@ -229,7 +240,7 @@ void CL_EntityParticles (entity_t *ent) forward[1] = cp*sy; forward[2] = -sp; - particle(pt_oneframe, particlepalette[0x6f], tex_particle, false, 2, 255, 9999, 0, ent->render.origin[0] + m_bytenormals[i][0]*dist + forward[0]*beamlength, ent->render.origin[1] + m_bytenormals[i][1]*dist + forward[1]*beamlength, ent->render.origin[2] + m_bytenormals[i][2]*dist + forward[2]*beamlength, 0, 0, 0, 0, 0, 0, 0, 0, 0); + particle(pt_oneframe, PARTICLE_BILLBOARD, particlepalette[0x6f], tex_particle, false, false, 2, 2, 255, 9999, 0, ent->render.origin[0] + m_bytenormals[i][0]*dist + forward[0]*beamlength, ent->render.origin[1] + m_bytenormals[i][1]*dist + forward[1]*beamlength, ent->render.origin[2] + m_bytenormals[i][2]*dist + forward[2]*beamlength, 0, 0, 0, 0, 0, 0, 0, 0, 0); } } @@ -273,7 +284,7 @@ void CL_ReadPointFile_f (void) Con_Printf ("Not enough free particles\n"); break; } - particle(pt_static, particlepalette[(-c)&15], tex_particle, false, 2, 255, 99999, 0, org[0], org[1], org[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); + particle(pt_static, PARTICLE_BILLBOARD, particlepalette[(-c)&15], tex_particle, false, false, 2, 2, 255, 99999, 0, org[0], org[1], org[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); } Mem_Free(pointfile); @@ -315,76 +326,86 @@ CL_ParticleExplosion */ void CL_ParticleExplosion (vec3_t org, int smoke) { - int i, j; - float f; - vec3_t v, end, ang; - byte noise1[32*32], noise2[32*32]; - + R_Stain(org, 96, 80, 80, 80, 128, 176, 176, 176, 128); if (cl_particles.integer && cl_particles_explosions.integer) { + int i, j; + float f; + vec3_t v, end, ang; + qbyte noise1[32*32], noise2[32*32]; + + VectorClear(end); // hush MSVC i = Mod_PointInLeaf(org, cl.worldmodel)->contents; if (i == CONTENTS_SLIME || i == CONTENTS_WATER) { for (i = 0;i < 128;i++) - particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 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, 0, 0); + particle(pt_bubble, PARTICLE_BILLBOARD, 0xFFFFFF, tex_bubble, false, true, 2, 2, 255, 9999, 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, 0, 0); ang[2] = lhrandom(0, 360); - fractalnoise(noise1, 32, 4); - fractalnoise(noise2, 32, 8); + fractalnoisequick(noise1, 32, 4); + fractalnoisequick(noise2, 32, 8); for (i = 0;i < 32;i++) { for (j = 0;j < 32;j++) { VectorRandom(v); VectorMA(org, 16, v, v); - TraceLine(org, v, end, NULL, 0); + TraceLine(org, v, end, NULL, 0, true); ang[0] = (j + 0.5f) * (360.0f / 32.0f); ang[1] = (i + 0.5f) * (360.0f / 32.0f); AngleVectors(ang, v, NULL, NULL); f = noise1[j*32+i] * 1.5f; VectorScale(v, f, v); - particle(pt_underwaterspark, noise2[j*32+i] * 0x010101, tex_smoke[rand()&7], false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2], 512.0f, 0, 0, 0, 2, 0); + particle(pt_underwaterspark, PARTICLE_BILLBOARD, noise2[j*32+i] * 0x010101, tex_smoke[rand()&7], false, true, 10, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2], 512.0f, 0, 0, 0, 2, 0); VectorScale(v, 0.75, v); - particle(pt_underwaterspark, explosparkramp[(noise2[j*32+i] >> 5)], tex_particle, false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2], 512.0f, 0, 0, 0, 2, 0); + particle(pt_underwaterspark, PARTICLE_BILLBOARD, explosparkramp[(noise2[j*32+i] >> 5)], tex_particle, false, true, 10, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2], 512.0f, 0, 0, 0, 2, 0); } } } else { ang[2] = lhrandom(0, 360); - fractalnoise(noise1, 32, 4); - fractalnoise(noise2, 32, 8); + fractalnoisequick(noise1, 32, 4); + fractalnoisequick(noise2, 32, 8); for (i = 0;i < 32;i++) { for (j = 0;j < 32;j++) { VectorRandom(v); VectorMA(org, 16, v, v); - TraceLine(org, v, end, NULL, 0); + TraceLine(org, v, end, NULL, 0, true); ang[0] = (j + 0.5f) * (360.0f / 32.0f); ang[1] = (i + 0.5f) * (360.0f / 32.0f); AngleVectors(ang, v, NULL, NULL); f = noise1[j*32+i] * 1.5f; VectorScale(v, f, v); - particle(pt_spark, noise2[j*32+i] * 0x010101, tex_smoke[rand()&7], false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0); + particle(pt_spark, PARTICLE_BILLBOARD, noise2[j*32+i] * 0x010101, tex_smoke[rand()&7], false, true, 10, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0); VectorScale(v, 0.75, v); - particle(pt_spark, explosparkramp[(noise2[j*32+i] >> 5)], tex_particle, false, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0); + particle(pt_spark, PARTICLE_BILLBOARD, explosparkramp[(noise2[j*32+i] >> 5)], tex_particle, false, true, 10, 10, lhrandom(128, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0); // VectorRandom(v); // VectorScale(v, 384, v); - // particle(pt_spark, explosparkramp[rand()&7], tex_particle, false, 2, lhrandom(16, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0); + // particle(pt_spark, PARTICLE_BILLBOARD, explosparkramp[rand()&7], tex_particle, false, true, 2, 2, lhrandom(16, 255), 9999, 1.5, end[0], end[1], end[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0); } } } } else { - R_NewExplosion(org); - + /* + int i; + vec3_t v; for (i = 0;i < 256;i++) { - VectorRandom(v); - particle(pt_spark, explosparkramp[rand()&7], tex_particle, false, 2, lhrandom(16, 255), 9999, 1.5, end[0], end[1], end[2], v[0] * 384.0f, v[1] * 384.0f, v[2] * 384.0f + 160.0f, 512.0f, 0, 0, 0, 2, 0); + do + { + VectorRandom(v); + } + while(DotProduct(v,v) < 0.75); + VectorScale(v, 512, v); + particle(pt_spark, PARTICLE_BILLBOARD, explosparkramp[rand()&7], tex_particle, false, true, 4, 4, 255, 9999, 1.5, org[0], org[1], org[2], v[0], v[1], v[2] + 160.0f, 512.0f, 0, 0, 0, 2, 0); } + */ + R_NewExplosion(org); } } @@ -400,7 +421,7 @@ void CL_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength) if (!cl_particles.integer) return; for (i = 0;i < 512;i++) - particle(pt_fade, particlepalette[colorStart + (i % colorLength)], tex_particle, false, 1.5, 255, 0.3, 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, 0.1f, 0); + particle(pt_fade, PARTICLE_BILLBOARD, particlepalette[colorStart + (i % colorLength)], tex_particle, false, false, 1.5, 1.5, 255, 0.3, 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), 384, 0, 0, 0, 1, 0); } /* @@ -411,13 +432,18 @@ CL_BlobExplosion */ void CL_BlobExplosion (vec3_t org) { - int i; + //int i; if (!cl_particles.integer) return; - for (i = 0;i < 256;i++) - particle(pt_blob , particlepalette[ 66+(rand()%6)], tex_particle, false, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128), 0, 0, 0, 0, 0, 0); - for (i = 0;i < 256;i++) - particle(pt_blob2, particlepalette[150+(rand()%6)], tex_particle, false, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128), 0, 0, 0, 0, 0, 0); + R_Stain(org, 96, 80, 80, 80, 128, 176, 176, 176, 128); + //R_Stain(org, 96, 96, 64, 96, 128, 160, 128, 160, 128); + + R_NewExplosion(org); + + //for (i = 0;i < 256;i++) + // particle(pt_blob , PARTICLE_BILLBOARD, particlepalette[ 66+(rand()%6)], tex_particle, false, true, 4, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128), 0, 0, 0, 0, 0, 0); + //for (i = 0;i < 256;i++) + // particle(pt_blob2, PARTICLE_BILLBOARD, particlepalette[150+(rand()%6)], tex_particle, false, true, 4, 4, 255, 9999, 0, org[0] + lhrandom(-16, 16), org[1] + lhrandom(-16, 16), org[2] + lhrandom(-16, 16), lhrandom(-4, 4), lhrandom(-4, 4), lhrandom(-128, 128), 0, 0, 0, 0, 0, 0); } /* @@ -436,7 +462,7 @@ void CL_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count) return; } while (count--) - particle(pt_fade, particlepalette[color + (rand()&7)], tex_particle, false, 1, 128, 9999, 0, org[0] + lhrandom(-8, 8), org[1] + lhrandom(-8, 8), org[2] + lhrandom(-8, 8), lhrandom(-15, 15), lhrandom(-15, 15), lhrandom(-15, 15), 0, 0, 0, 0, 0, 0); + particle(pt_fade, PARTICLE_BILLBOARD, particlepalette[color + (rand()&7)], tex_particle, false, false, 1, 1, 128, 9999, 0, org[0] + lhrandom(-8, 8), org[1] + lhrandom(-8, 8), org[2] + lhrandom(-8, 8), lhrandom(-15, 15), lhrandom(-15, 15), lhrandom(-15, 15), 384, 0, 0, 0, 0, 0); } // LordHavoc: added this for spawning sparks/dust (which have strong gravity) @@ -449,39 +475,52 @@ void CL_SparkShower (vec3_t org, vec3_t dir, int count) { if (!cl_particles.integer) return; - CL_Decal(org, tex_bullethole[rand()&7], 16 * cl_particles_size.value, 0, 0, 0, 1); + R_Stain(org, 32, 96, 96, 96, 32, 128, 128, 128, 32); // smoke puff if (cl_particles_smoke.integer) - particle(pt_bulletsmoke, 0xA0A0A0, tex_smoke[rand()&7], true, 5, 255, 9999, 0, org[0], org[1], org[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(0, 16), 0, 0, 0, 0, 0, 0); + particle(pt_bulletsmoke, PARTICLE_BILLBOARD, 0xFFFFFF /*0xA0A0A0*/, tex_smoke[rand()&7], true, true, 2, 2, 255, 9999, 0, org[0], org[1], org[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(0, 16), 0, 0, 0, 0, 0, 0); if (cl_particles_sparks.integer) { // sparks while(count--) - particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(0, 255), 9999, 1.5, org[0], org[1], org[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(0, 128), 512.0f, 0, 0, 0, 0.2f, 0); + particle(pt_spark, PARTICLE_BILLBOARD, particlepalette[0x68 + (rand() & 7)], tex_particle, false, true, 1, 1, lhrandom(64, 128), 9999, 0, org[0], org[1], org[2], lhrandom(-64, 64) + dir[0], lhrandom(-64, 64) + dir[1], lhrandom(0, 128) + dir[2], 480, 0, 0, 0, 1, 0); } } +void CL_PlasmaBurn (vec3_t org) +{ + if (!cl_particles.integer) return; + + R_Stain(org, 48, 96, 96, 96, 48, 128, 128, 128, 48); +} + void CL_BloodPuff (vec3_t org, vec3_t vel, int count) { + float r, s; // bloodcount is used to accumulate counts too small to cause a blood particle static int bloodcount = 0; if (!cl_particles.integer) return; if (!cl_particles_blood.integer) return; - if (count > 100) - count = 100; + s = count + 32.0f; + count *= 5.0f; + if (count > 1000) + count = 1000; bloodcount += count; - while(bloodcount >= 10) + while(bloodcount > 0) { - particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, org[0], org[1], org[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0); - bloodcount -= 10; + r = lhrandom(cl_particles_blood_size_min.value, cl_particles_blood_size_max.value); + particle(pt_blood, PARTICLE_BILLBOARD, 0x300000, tex_smoke[rand()&7], true, false, r, r, cl_particles_blood_alpha.value * 255, 9999, -1, org[0], org[1], org[2], vel[0] + lhrandom(-s, s), vel[1] + lhrandom(-s, s), vel[2] + lhrandom(-s, s), 0, 0, 0, 0, 1, 0); + bloodcount -= r; } } void CL_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count) { + float c; + float r; vec3_t diff, center, velscale; if (!cl_particles.integer) return; if (!cl_particles_bloodshowers.integer) return; @@ -496,7 +535,8 @@ void CL_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count) velscale[1] = velspeed * 2.0 / diff[1]; velscale[2] = velspeed * 2.0 / diff[2]; - while (count--) + c = count * 5; + while (c > 0) { vec3_t org, vel; org[0] = lhrandom(mins[0], maxs[0]); @@ -505,26 +545,28 @@ void CL_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count) vel[0] = (org[0] - center[0]) * velscale[0]; vel[1] = (org[1] - center[1]) * velscale[1]; vel[2] = (org[2] - center[2]) * velscale[2]; - particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, org[0], org[1], org[2], vel[0], vel[1], vel[2], 0, 0, 0, 0, 1.0f, 0); + r = lhrandom(cl_particles_blood_size_min.value, cl_particles_blood_size_max.value); + c -= r; + particle(pt_blood, PARTICLE_BILLBOARD, 0x300000, tex_smoke[rand()&7], true, false, r, r, cl_particles_blood_alpha.value * 255, 9999, -1, org[0], org[1], org[2], vel[0], vel[1], vel[2], 0, 0, 0, 0, 1, 0); } } void CL_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel) { - float t; + float t; if (!cl_particles.integer) return; if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;} if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;} if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;} while (count--) - particle(gravity ? pt_grav : pt_static, particlepalette[colorbase + (rand()&3)], tex_particle, false, 2, 255, lhrandom(1, 2), 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), dir[0] + lhrandom(-randomvel, randomvel), dir[1] + lhrandom(-randomvel, randomvel), dir[2] + lhrandom(-randomvel, randomvel), 0, 0, 0, 0, 0, 0); + particle(gravity ? pt_grav : pt_static, PARTICLE_BILLBOARD, particlepalette[colorbase + (rand()&3)], tex_particle, false, false, 2, 2, 255, lhrandom(1, 2), 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), dir[0] + lhrandom(-randomvel, randomvel), dir[1] + lhrandom(-randomvel, randomvel), dir[2] + lhrandom(-randomvel, randomvel), 0, 0, 0, 0, 0, 0); } void CL_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type) { - vec3_t vel; - float t, z; + vec3_t vel; + float t, z; if (!cl_particles.integer) return; if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;} if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;} @@ -545,12 +587,14 @@ void CL_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int color switch(type) { case 0: + count *= 4; // ick, this should be in the mod or maps? + while(count--) { vel[0] = dir[0] + lhrandom(-16, 16); vel[1] = dir[1] + lhrandom(-16, 16); vel[2] = dir[2] + lhrandom(-32, 32); - particle(pt_rain, particlepalette[colorbase + (rand()&3)], tex_rain, true, 3, 255, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2], 0, 0); + particle(pt_rain, PARTICLE_UPRIGHT_FACING, particlepalette[colorbase + (rand()&3)], tex_particle, true, true, 1, 64, 64, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2], 0, 0); } break; case 1: @@ -559,7 +603,7 @@ void CL_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int color vel[0] = dir[0] + lhrandom(-16, 16); vel[1] = dir[1] + lhrandom(-16, 16); vel[2] = dir[2] + lhrandom(-32, 32); - particle(pt_snow, particlepalette[colorbase + (rand()&3)], tex_particle, false, 2, 255, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2], 0, 0); + particle(pt_snow, PARTICLE_BILLBOARD, particlepalette[colorbase + (rand()&3)], tex_particle, false, true, 2, 2, 255, t, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), z, vel[0], vel[1], vel[2], 0, vel[0], vel[1], vel[2], 0, 0); } break; default: @@ -569,14 +613,14 @@ void CL_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int color void CL_FlameCube (vec3_t mins, vec3_t maxs, int count) { - float t; + float t; if (!cl_particles.integer) return; if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;} if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;} if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;} while (count--) - particle(pt_flame, particlepalette[224 + (rand()&15)], tex_particle, false, 8, 255, 9999, 1.1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), lhrandom(-32, 32), lhrandom(-32, 32), lhrandom(-32, 64), 0, 0, 0, 0, 0.1f, 0); + particle(pt_flame, PARTICLE_BILLBOARD, particlepalette[224 + (rand()&15)], tex_particle, false, true, 8, 8, 255, 9999, 1.1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), lhrandom(-32, 32), lhrandom(-32, 32), lhrandom(-32, 64), 0, 0, 0, 0, 1, 0); } void CL_Flames (vec3_t org, vec3_t vel, int count) @@ -584,7 +628,7 @@ void CL_Flames (vec3_t org, vec3_t vel, int count) if (!cl_particles.integer) return; while (count--) - particle(pt_flame, particlepalette[224 + (rand()&15)], tex_particle, false, 8, 255, 9999, 1.1, org[0], org[1], org[2], vel[0] + lhrandom(-128, 128), vel[1] + lhrandom(-128, 128), vel[2] + lhrandom(-128, 128), 0, 0, 0, 0, 0.1f, 0); + particle(pt_flame, PARTICLE_BILLBOARD, particlepalette[224 + (rand()&15)], tex_particle, false, true, 8, 8, 255, 9999, 1.1, org[0], org[1], org[2], vel[0] + lhrandom(-128, 128), vel[1] + lhrandom(-128, 128), vel[2] + lhrandom(-128, 128), 0, 0, 0, 0, 1, 0); } @@ -613,7 +657,7 @@ void CL_LavaSplash (vec3_t origin) org[1] = origin[1] + dir[1]; org[2] = origin[2] + lhrandom(0, 64); vel = lhrandom(50, 120) / VectorLength(dir); // normalize and scale - particle(pt_lavasplash, particlepalette[224 + (rand()&7)], tex_particle, false, 7, 255, 9999, 0, org[0], org[1], org[2], dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0, 0, 0); + particle(pt_lavasplash, PARTICLE_BILLBOARD, particlepalette[224 + (rand()&7)], tex_particle, false, true, 7, 7, 255, 9999, 0, org[0], org[1], org[2], dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0, 0, 0); } } } @@ -632,169 +676,163 @@ void CL_TeleportSplash (vec3_t org) for (i=-16 ; i<16 ; i+=8) for (j=-16 ; j<16 ; j+=8) for (k=-24 ; k<32 ; k+=8) - particle(pt_fade, 0xFFFFFF, tex_particle, false, 1, lhrandom(64, 128), 9999, 0, org[0] + i + lhrandom(0, 8), org[1] + j + lhrandom(0, 8), org[2] + k + lhrandom(0, 8), i*2 + lhrandom(-12.5, 12.5), j*2 + lhrandom(-12.5, 12.5), k*2 + lhrandom(27.5, 52.5), 0, 0, 0, 0, 0.1f, -512.0f); + //particle(pt_fade, PARTICLE_BILLBOARD, 0xFFFFFF, tex_particle, false, true, 1.5, 1.5, lhrandom(64, 128), 9999, 0, org[0] + i + lhrandom(0, 8), org[1] + j + lhrandom(0, 8), org[2] + k + lhrandom(0, 8), i*2 + lhrandom(-12.5, 12.5), j*2 + lhrandom(-12.5, 12.5), k*2 + lhrandom(27.5, 52.5), 384.0f, 0, 0, 0, 1, 0); + particle(pt_fade, PARTICLE_BILLBOARD, 0xFFFFFF, tex_particle, false, true, 10, 10, lhrandom(64, 128), 9999, 0, org[0] + i + lhrandom(0, 8), org[1] + j + lhrandom(0, 8), org[2] + k + lhrandom(0, 8), lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-256, 256), 256.0f, 0, 0, 0, 1, 0); } void CL_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) { - vec3_t vec, dir, vel; - float len, dec = 0, speed; - int contents, bubbles; - double t; + vec3_t vec, dir, vel, pos; + float len, dec, speed; + int contents, bubbles/*, c*/; if (!cl_particles.integer) return; VectorSubtract(end, start, dir); VectorNormalize(dir); - if (type == 0 && host_frametime != 0) // rocket glow - particle(pt_oneframe, 0xFFFFFF, tex_rocketglow, false, 24, 255, 9999, 0, end[0] - 12 * dir[0], end[1] - 12 * dir[1], end[2] - 12 * dir[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); - - t = ent->persistent.trail_time; - if (t >= cl.time) - return; // no particles to spawn this frame (sparse trail) - - if (t < cl.oldtime) - t = cl.oldtime; + //if (type == 0 && host_frametime != 0) // rocket glow + // particle(pt_oneframe, PARTICLE_BILLBOARD, 0xFFFFFF, tex_rocketglow, false, true, 24, 24, 255, 9999, 0, end[0] - 12 * dir[0], end[1] - 12 * dir[1], end[2] - 12 * dir[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); VectorSubtract (end, start, vec); len = VectorNormalizeLength (vec); - if (len <= 0.01f) - { - // advance the trail time - ent->persistent.trail_time = cl.time; + dec = -ent->persistent.trail_time; + ent->persistent.trail_time += len; + if (ent->persistent.trail_time < 0.01f) return; - } - speed = len / (cl.time - cl.oldtime); - VectorScale(vec, speed, vel); + + speed = 1.0f / (ent->state_current.time - ent->state_previous.time); + VectorSubtract(ent->state_current.origin, ent->state_previous.origin, vel); + VectorScale(vel, speed, vel); // advance into this frame to reach the first puff location - dec = t - cl.oldtime; - dec *= speed; - VectorMA(start, dec, vec, start); + VectorMA(start, dec, vec, pos); + len -= dec; + + // if we skip out, leave it reset + ent->persistent.trail_time = 0.0f; - contents = Mod_PointInLeaf(start, cl.worldmodel)->contents; + contents = Mod_PointInLeaf(pos, cl.worldmodel)->contents; if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA) - { - // advance the trail time - ent->persistent.trail_time = cl.time; return; - } bubbles = (contents == CONTENTS_WATER || contents == CONTENTS_SLIME); - while (t < cl.time) + while (len >= 0) { switch (type) { case 0: // rocket trail if (!cl_particles_smoke.integer) - dec = cl.time - t; - else if (bubbles && cl_particles_bubbles.integer) + return; + //dec = 5; + //particle(pt_fade, PARTICLE_BILLBOARD, 0x707070, tex_particle, true, false, dec, dec, 128, 9999, 0, pos[0], pos[1], pos[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 256.0f, 0, 0, 0, 0, 0); + dec = 6; + particle(pt_fade, PARTICLE_BILLBOARD, 0x404040, tex_smoke[rand()&7], true, true, dec, dec, 128, 9999, 0, pos[0], pos[1], pos[2], lhrandom(-5, 5), lhrandom(-5, 5), lhrandom(-5, 5), 256.0f, 0, 0, 0, 0, 0); + //particle(pt_fade, PARTICLE_BILLBOARD, 0x707070, tex_smoke[rand()&7], false, true, dec, dec, 128, 9999, 0, pos[0], pos[1], pos[2], lhrandom(-10, 10), lhrandom(-10, 10), lhrandom(-10, 10), 128.0f, 0, 0, 0, 0, 0); + //dec = 10; + //particle(pt_smoke, PARTICLE_BILLBOARD, 0x707070, tex_smoke[rand()&7], false, true, 2, 2, 160, 9999, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); + if (bubbles && cl_particles_bubbles.integer) { - dec = 0.005f; - particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0); - particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0); - particle(pt_smoke, 0xFFFFFF, tex_smoke[rand()&7], false, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); + particle(pt_bubble, PARTICLE_BILLBOARD, 0xFFFFFF, tex_bubble, false, true, 2, 2, 255, 9999, 1.5, pos[0], pos[1], pos[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0); + //particle(pt_bubble, PARTICLE_BILLBOARD, 0xFFFFFF, tex_bubble, false, true, 2, 2, 255, 9999, 1.5, pos[0], pos[1], pos[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0); } else { - dec = 0.005f; - particle(pt_smoke, 0xC0C0C0, tex_smoke[rand()&7], true, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); - //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0); - //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0); - //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0); - //particle(pt_spark, particlepalette[0x68 + (rand() & 7)], tex_particle, false, 1, lhrandom(128, 255), 9999, 1.5, start[0], start[1], start[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 0.1f, 0); + //particle(pt_spark, PARTICLE_BILLBOARD, particlepalette[0x68 + (rand() & 7)], tex_particle, false, true, 2, 2, lhrandom(128, 255), 9999, 1.5, pos[0], pos[1], pos[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64), 512.0f, 0, 0, 0, 1, 0); + //particle(pt_spark, PARTICLE_BILLBOARD, particlepalette[0x68 + (rand() & 7)], tex_particle, false, true, 2, 2, lhrandom(128, 255), 9999, 1.5, pos[0], pos[1], pos[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64), 512.0f, 0, 0, 0, 1, 0); + //particle(pt_spark, PARTICLE_BILLBOARD, particlepalette[0x68 + (rand() & 7)], tex_particle, false, true, 1, 1, lhrandom(128, 255), 9999, 1.5, pos[0], pos[1], pos[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 1, 0); + //particle(pt_spark, PARTICLE_BILLBOARD, particlepalette[0x68 + (rand() & 7)], tex_particle, false, true, 1, 1, lhrandom(128, 255), 9999, 1.5, pos[0], pos[1], pos[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 1, 0); + //particle(pt_spark, PARTICLE_BILLBOARD, particlepalette[0x68 + (rand() & 7)], tex_particle, false, true, 1, 1, lhrandom(128, 255), 9999, 1.5, pos[0], pos[1], pos[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 1, 0); + //particle(pt_spark, PARTICLE_BILLBOARD, particlepalette[0x68 + (rand() & 7)], tex_particle, false, true, 1, 1, lhrandom(128, 255), 9999, 1.5, pos[0], pos[1], pos[2], lhrandom(-64, 64) - vel[0] * 0.0625, lhrandom(-64, 64) - vel[1] * 0.0625, lhrandom(-64, 64) - vel[2] * 0.0625, 512.0f, 0, 0, 0, 1, 0); } break; case 1: // grenade trail // FIXME: make it gradually stop smoking if (!cl_particles_smoke.integer) - dec = cl.time - t; - else if (bubbles && cl_particles_bubbles.integer) - { - dec = 0.02f; - particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0); - particle(pt_bubble, 0xFFFFFF, tex_bubble, false, lhrandom(1, 2), 255, 9999, 1.5, start[0], start[1], start[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0); - particle(pt_smoke, 0xFFFFFF, tex_smoke[rand()&7], false, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); - } - else + return; + //dec = 5; + //particle(pt_fade, PARTICLE_BILLBOARD, 0x707070, tex_particle, true, false, dec, dec, 128, 9999, 0, pos[0], pos[1], pos[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 256.0f, 0, 0, 0, 0, 0); + dec = 6; + particle(pt_fade, PARTICLE_BILLBOARD, 0x404040, tex_smoke[rand()&7], true, true, dec, dec, 128, 9999, 0, pos[0], pos[1], pos[2], lhrandom(-5, 5), lhrandom(-5, 5), lhrandom(-5, 5), 256.0f, 0, 0, 0, 0, 0); + //particle(pt_smoke, PARTICLE_BILLBOARD, 0x404040, tex_smoke[rand()&7], false, true, 2, 2, 160, 9999, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); + if (bubbles && cl_particles_bubbles.integer) { - dec = 0.02f; - particle(pt_smoke, 0x808080, tex_smoke[rand()&7], true, 2, 160, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); + particle(pt_bubble, PARTICLE_BILLBOARD, 0xFFFFFF, tex_bubble, false, true, 2, 2, 255, 9999, 1.5, pos[0], pos[1], pos[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0); + //particle(pt_bubble, PARTICLE_BILLBOARD, 0xFFFFFF, tex_bubble, false, true, 2, 2, 255, 9999, 1.5, pos[0], pos[1], pos[2], lhrandom(-16, 16), lhrandom(-16, 16), lhrandom(-16, 16), 0, 0, 0, 0, 0, 0); } break; case 2: // blood if (!cl_particles_blood.integer) - dec = cl.time - t; - else - { - dec = 0.1f; - particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, start[0], start[1], start[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0); - } + return; + dec = lhrandom(cl_particles_blood_size_min.value, cl_particles_blood_size_max.value); + //particle(pt_blood, PARTICLE_BILLBOARD, 0x300000, tex_smoke[rand()&7], true, false, dec, dec, cl_particles_blood_alpha.value * 255.0f, 9999, -1, pos[0], pos[1], pos[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1, 0); + particle(pt_blood, PARTICLE_BILLBOARD, 0x300000, tex_smoke[rand()&7], true, false, dec, dec, cl_particles_blood_alpha.value * 255.0f, 9999, -1, pos[0], pos[1], pos[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64), 0, 0, 0, 0, 1, 0); + //c = ((rand() & 15) + 16) << 16; + //particle(pt_blood, PARTICLE_BILLBOARD, c, tex_particle, true, false, dec, dec, cl_particles_blood_alpha.value * 255.0f, 9999, -1, pos[0], pos[1], pos[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64), 0, 0, 0, 0, 1, 0); break; case 4: // slight blood if (!cl_particles_blood.integer) - dec = cl.time - t; - else - { - dec = 0.15f; - particle(pt_blood, 0x300000, tex_smoke[rand()&7], true, 24, 255, 9999, -1, start[0], start[1], start[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1.0f, 0); - } + return; + dec = lhrandom(cl_particles_blood_size_min.value, cl_particles_blood_size_max.value); + //particle(pt_blood, PARTICLE_BILLBOARD, 0x300000, tex_smoke[rand()&7], true, false, dec, dec, cl_particles_blood_alpha.value * 128.0f, 9999, -1, pos[0], pos[1], pos[2], vel[0] + lhrandom(-64, 64), vel[1] + lhrandom(-64, 64), vel[2] + lhrandom(-64, 64), 0, 0, 0, 0, 1, 0); + particle(pt_blood, PARTICLE_BILLBOARD, 0x300000, tex_smoke[rand()&7], true, false, dec, dec, cl_particles_blood_alpha.value * 128.0f, 9999, -1, pos[0], pos[1], pos[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64), 0, 0, 0, 0, 1, 0); + //c = ((rand() & 15) + 16) << 16; + //particle(pt_blood, PARTICLE_BILLBOARD, c, tex_particle, true, false, dec, dec, cl_particles_blood_alpha.value * 128.0f, 9999, -1, pos[0], pos[1], pos[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64), 0, 0, 0, 0, 1, 0); break; case 3: // green tracer - dec = 0.02f; - particle(pt_fade, 0x373707, tex_smoke[rand()&7], false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); + dec = 6; + //particle(pt_fade, PARTICLE_BILLBOARD, 0x373707, tex_particle, false, true, dec, dec, 128, 9999, 0, pos[0], pos[1], pos[2], 0, 0, 0, 384.0f, 0, 0, 0, 0, 0); + particle(pt_fade, PARTICLE_BILLBOARD, 0x373707, tex_particle, false, true, dec, dec, 128, 9999, 0, pos[0], pos[1], pos[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 384.0f, 0, 0, 0, 0, 0); break; case 5: // flame tracer - dec = 0.02f; - particle(pt_fade, 0xCF632B, tex_smoke[rand()&7], false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); + dec = 6; + //particle(pt_fade, PARTICLE_BILLBOARD, 0xCF632B, tex_particle, false, true, dec, dec, 128, 9999, 0, pos[0], pos[1], pos[2], 0, 0, 0, 384.0f, 0, 0, 0, 0, 0); + particle(pt_fade, PARTICLE_BILLBOARD, 0xCF632B, tex_particle, false, true, dec, dec, 128, 9999, 0, pos[0], pos[1], pos[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 384.0f, 0, 0, 0, 0, 0); break; case 6: // voor trail - dec = 0.05f; // sparse trail - particle(pt_fade, 0x47232B, tex_smoke[rand()&7], false, 4, 255, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); + dec = 6; + //particle(pt_fade, PARTICLE_BILLBOARD, 0x47232B, tex_particle, false, true, dec, dec, 128, 9999, 0, pos[0], pos[1], pos[2], 0, 0, 0, 384.0f, 0, 0, 0, 0, 0); + particle(pt_fade, PARTICLE_BILLBOARD, 0x47232B, tex_particle, false, true, dec, dec, 128, 9999, 0, pos[0], pos[1], pos[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 384.0f, 0, 0, 0, 0, 0); break; case 7: // Nehahra smoke tracer if (!cl_particles_smoke.integer) - dec = cl.time - t; - else - { - dec = 0.14f; - particle(pt_smoke, 0xC0C0C0, tex_smoke[rand()&7], true, 10, 64, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); - } + return; + dec = 10; + particle(pt_smoke, PARTICLE_BILLBOARD, 0xC0C0C0, tex_smoke[rand()&7], true, false, dec, dec, 64, 9999, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); break; } // advance to next time and position - t += dec; - dec *= speed; - VectorMA (start, dec, vec, start); + len -= dec; + VectorMA (pos, dec, vec, pos); } - ent->persistent.trail_time = t; + ent->persistent.trail_time = len; } void CL_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent) { - vec3_t vec; + vec3_t vec, pos; int len; if (!cl_particles.integer) return; if (!cl_particles_smoke.integer) return; + VectorCopy(start, pos); VectorSubtract (end, start, vec); len = (int) (VectorNormalizeLength (vec) * (1.0f / 3.0f)); VectorScale(vec, 3, vec); color = particlepalette[color]; while (len--) { - particle(pt_smoke, color, tex_particle, false, 8, 192, 9999, 0, start[0], start[1], start[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); - VectorAdd (start, vec, start); + particle(pt_smoke, PARTICLE_BILLBOARD, color, tex_particle, false, false, 5, 5, 128, 9999, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, 0, 0); + VectorAdd (pos, vec, pos); } } @@ -807,13 +845,16 @@ CL_MoveParticles void CL_MoveParticles (void) { particle_t *p; - renderparticle_t *r; - int i, activeparticles, maxparticle, j, a, b, pressureused = false; - float gravity, dvel, frametime, f, dist, normal[3], v[3], org[3], o[3]; + renderparticle_t *r, *rend; + int i, activeparticles, maxparticle, j, a, pressureused = false, content; + float gravity, dvel, frametime, f, dist, normal[3], v[3], org[3]; // LordHavoc: early out condition if (!cl_numparticles) + { + r_refdef.numparticles = 0; return; + } frametime = cl.time - cl.oldtime; if (!frametime) @@ -824,7 +865,7 @@ void CL_MoveParticles (void) activeparticles = 0; maxparticle = -1; j = 0; - for (i = 0, p = particles, r = r_refdef.particles;i < cl_numparticles;i++, p++) + for (i = 0, p = particles, r = r_refdef.particles, rend = r + cl_maxparticles;i < cl_numparticles;i++, p++) { if (p->die < cl.time) { @@ -832,22 +873,19 @@ void CL_MoveParticles (void) continue; } + content = 0; VectorCopy(p->org, p->oldorg); VectorMA(p->org, frametime, p->vel, p->org); - if (p->friction) - { - f = 1.0f - (p->friction * frametime); - VectorScale(p->vel, f, p->vel); - } VectorCopy(p->org, org); if (p->bounce) { - if (TraceLine(p->oldorg, p->org, v, normal, 0) < 1) + if (TraceLine(p->oldorg, p->org, v, normal, 0, true) < 1) { VectorCopy(v, p->org); if (p->bounce < 0) { - CL_Decal(v, p->tex, p->scale * cl_particles_size.value, p->color[0] * (1.0f / 255.0f), p->color[1] * (1.0f / 255.0f), p->color[2] * (1.0f / 255.0f), p->alpha * (1.0f / 255.0f)); + // assume it's blood (lame, but...) + R_Stain(v, 48, 64, 24, 24, p->alpha * p->scalex * p->scaley * (1.0f / 2048.0f), 192, 48, 48, p->alpha * p->scalex * p->scaley * (1.0f / 2048.0f)); p->die = -1; freeparticles[j++] = p; continue; @@ -861,6 +899,16 @@ void CL_MoveParticles (void) } } } + if (p->friction) + { + f = p->friction * frametime; + if (!content) + content = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + if (content != CONTENTS_EMPTY) + f *= 4; + f = 1.0f - f; + VectorScale(p->vel, f, p->vel); + } switch (p->type) { @@ -895,10 +943,13 @@ void CL_MoveParticles (void) p->vel[1] = (rand()&63)-32 + p->vel2[1]; p->vel[2] = (rand()&63)-32 + p->vel2[2]; } - a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + if (!content) + content = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + a = content; if (a != CONTENTS_EMPTY && a != CONTENTS_SKY) { - vec3_t normal; + p->die = -1; + /* if (a == CONTENTS_SOLID && Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents == CONTENTS_SOLID) break; // still in solid p->die = cl.time + 1000; @@ -908,102 +959,105 @@ void CL_MoveParticles (void) case CONTENTS_LAVA: case CONTENTS_SLIME: p->tex = tex_smoke[rand()&7]; + p->orientation = PARTICLE_BILLBOARD; p->type = pt_steam; p->alpha = 96; - p->scale = 5; + p->scalex = 5; + p->scaley = 5; p->vel[2] = 96; break; case CONTENTS_WATER: p->tex = tex_smoke[rand()&7]; + p->orientation = PARTICLE_BILLBOARD; p->type = pt_splash; p->alpha = 96; - p->scale = 5; + p->scalex = 5; + p->scaley = 5; p->vel[2] = 96; break; default: // CONTENTS_SOLID and any others - TraceLine(p->oldorg, p->org, v, normal, 0); + TraceLine(p->oldorg, p->org, v, normal, 0, true); VectorCopy(v, p->org); p->tex = tex_smoke[rand()&7]; + p->orientation = PARTICLE_BILLBOARD; p->type = pt_fade; + p->time2 = 384.0f; + p->scalex = 5; + p->scaley = 5; VectorClear(p->vel); break; } + */ } break; case pt_blood: p->friction = 1; - a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + if (!content) + content = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + a = content; if (a != CONTENTS_EMPTY) { if (a == CONTENTS_WATER || a == CONTENTS_SLIME) { - p->friction = 5; - p->scale += frametime * 32.0f; - p->alpha -= frametime * 128.0f; - p->vel[2] += gravity * 0.125f; + //p->friction = 5; + p->scalex += frametime * (cl_particles_blood_size_min.value + cl_particles_blood_size_max.value); + p->scaley += frametime * (cl_particles_blood_size_min.value + cl_particles_blood_size_max.value); + p->alpha -= frametime * max(cl_particles_blood_alpha.value, 0.01f) * 128.0f; + //p->vel[2] += gravity * 0.25f; if (p->alpha < 1) p->die = -1; - break; } else - { p->die = -1; - break; - } } - p->vel[2] -= gravity * 0.5; + else + p->vel[2] -= gravity; break; case pt_spark: p->alpha -= frametime * p->time2; p->vel[2] -= gravity; if (p->alpha < 1) p->die = -1; - else if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY) - p->type = pt_underwaterspark; - break; - case pt_underwaterspark: - if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY) + else { - p->tex = tex_smoke[rand()&7]; - p->color[0] = p->color[1] = p->color[2] = 255; - p->scale = 16; - p->type = pt_explosionsplash; + if (!content) + content = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + if (content != CONTENTS_EMPTY) + p->die = -1; } - else - p->vel[2] += gravity * 0.5f; - p->alpha -= frametime * p->time2; - if (p->alpha < 1) - p->die = -1; break; case pt_explosionsplash: if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY) p->vel[2] -= gravity; else p->alpha = 0; - p->scale += frametime * 64.0f; + p->scalex += frametime * 64.0f; + p->scaley += frametime * 64.0f; p->alpha -= frametime * 1024.0f; if (p->alpha < 1) p->die = -1; break; case pt_fade: - p->alpha -= frametime * 512; + p->alpha -= frametime * p->time2; if (p->alpha < 1) p->die = -1; break; case pt_bubble: - a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; - if (a != CONTENTS_WATER && a != CONTENTS_SLIME) + if (!content) + content = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + if (content != CONTENTS_WATER && content != CONTENTS_SLIME) { p->tex = tex_smoke[rand()&7]; + p->orientation = PARTICLE_BILLBOARD; p->type = pt_splashpuff; - p->scale = 4; + p->scalex = 4; + p->scaley = 4; p->vel[0] = p->vel[1] = p->vel[2] = 0; break; } - p->vel[2] += gravity * 0.25; p->vel[0] *= (1 - (frametime * 0.0625)); p->vel[1] *= (1 - (frametime * 0.0625)); - p->vel[2] *= (1 - (frametime * 0.0625)); + p->vel[2] = (p->vel[2] + gravity * 0.25) * (1 - (frametime * 0.0625)); if (cl.time > p->time2) { p->time2 = cl.time + lhrandom(0, 0.5); @@ -1016,21 +1070,24 @@ void CL_MoveParticles (void) p->die = -1; break; case pt_bulletsmoke: - p->scale += frametime * 16; + p->scalex += frametime * 16; + p->scaley += frametime * 16; p->alpha -= frametime * 1024; - p->vel[2] += gravity * 0.1; + p->vel[2] += gravity * 0.2; if (p->alpha < 1) p->die = -1; break; case pt_smoke: - p->scale += frametime * 24; - p->alpha -= frametime * 256; - p->vel[2] += gravity * 0.1; + p->scalex += frametime * 16; + p->scaley += frametime * 16; + p->alpha -= frametime * 320; + //p->vel[2] += gravity * 0.2; if (p->alpha < 1) p->die = -1; break; case pt_steam: - p->scale += frametime * 48; + p->scalex += frametime * 48; + p->scaley += frametime * 48; p->alpha -= frametime * 512; p->vel[2] += gravity * 0.05; if (p->alpha < 1) @@ -1042,16 +1099,25 @@ void CL_MoveParticles (void) p->die = -1; break; case pt_rain: + if (!content) + content = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + a = content; + if (a != CONTENTS_EMPTY && a != CONTENTS_SKY) + p->die = -1; + /* f = 0; b = Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents; VectorCopy(p->oldorg, o); while (f < 1) { a = b; - f = TraceLine(o, p->org, v, normal, a); + f = TraceLine(o, p->org, v, normal, a, true); b = traceline_endcontents; if (f < 1 && b != CONTENTS_EMPTY && b != CONTENTS_SKY) { + #if 1 + p->die = -1; + #else p->die = cl.time + 1000; p->vel[0] = p->vel[1] = p->vel[2] = 0; VectorCopy(v, p->org); @@ -1060,22 +1126,30 @@ void CL_MoveParticles (void) case CONTENTS_LAVA: case CONTENTS_SLIME: p->tex = tex_smoke[rand()&7]; + p->orientation = PARTICLE_BILLBOARD; p->type = pt_steam; - p->scale = 3; + p->scalex = 3; + p->scaley = 3; p->vel[2] = 96; break; default: // water, solid, and anything else p->tex = tex_rainsplash[0]; + p->orientation = PARTICLE_ORIENTED_DOUBLESIDED; p->time2 = 0; VectorCopy(normal, p->vel2); // VectorAdd(p->org, normal, p->org); p->type = pt_raindropsplash; - p->scale = 8; + p->scalex = 8; + p->scaley = 8; break; } + #endif + break; } } + */ break; + /* case pt_raindropsplash: p->time2 += frametime * 64.0f; if (p->time2 >= 16.0f) @@ -1084,7 +1158,9 @@ void CL_MoveParticles (void) break; } p->tex = tex_rainsplash[(int) p->time2]; + p->orientation = PARTICLE_ORIENTED_DOUBLESIDED; break; + */ case pt_flame: p->alpha -= frametime * 512; p->vel[2] += gravity; @@ -1113,22 +1189,17 @@ void CL_MoveParticles (void) pressureused = true; // build renderparticle for renderer to use - if (p->type == pt_raindropsplash) - { - r->orientation = PARTICLE_ORIENTED_DOUBLESIDED; - r->dir[0] = p->vel2[0]; - r->dir[1] = p->vel2[1]; - r->dir[2] = p->vel2[2]; - } - else if (p->tex == tex_rain) - r->orientation = PARTICLE_UPRIGHT_FACING; - else - r->orientation = PARTICLE_BILLBOARD; + r->orientation = p->orientation; + r->additive = p->additive; + r->dir[0] = p->vel2[0]; + r->dir[1] = p->vel2[1]; + r->dir[2] = p->vel2[2]; r->org[0] = p->org[0]; r->org[1] = p->org[1]; r->org[2] = p->org[2]; r->tex = p->tex; - r->scale = p->scale * 0.5f * cl_particles_size.value; + r->scalex = p->scalex * cl_particles_size.value; + r->scaley = p->scaley * cl_particles_size.value; r->dynlight = p->dynlight; r->color[0] = p->color[0] * (1.0f / 255.0f); r->color[1] = p->color[1] * (1.0f / 255.0f); @@ -1168,9 +1239,9 @@ void CL_MoveParticles (void) dist = DotProduct(diff, diff); if (dist < 4096 && dist >= 1) { - dist = freeparticles[j]->scale * 4.0f * frametime / sqrt(dist); + dist = freeparticles[j]->scalex * 4.0f * frametime / sqrt(dist); VectorMA(p->vel, dist, diff, p->vel); - //dist = freeparticles[j]->scale * 4.0f * frametime / dist; + //dist = freeparticles[j]->scalex * 4.0f * frametime / dist; //VectorMA(p->vel, dist, freeparticles[j]->vel, p->vel); } }