X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=cl_particles.c;h=0a24cf75aacf7fc667eac81fda9e4e30a93d3457;hb=3869bc4ae01a780a71af98e2f49c5b2f9297c9ae;hp=d658b7b6e43bd8e425e25a418016101db6f4b7b2;hpb=16742571f9a7d696a654668febdc10b4f4affd57;p=xonotic%2Fdarkplaces.git diff --git a/cl_particles.c b/cl_particles.c index d658b7b6..0a24cf75 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -169,7 +169,8 @@ static const int tex_raindrop = 61; static const int tex_beam = 60; cvar_t cl_particles = {CVAR_SAVE, "cl_particles", "1", "enables particle effects"}; -cvar_t cl_particles_quality = {CVAR_SAVE, "cl_particles_quality", "1", "multiplies number of particles and reduces their alpha"}; +cvar_t cl_particles_quality = {CVAR_SAVE, "cl_particles_quality", "1", "multiplies number of particles"}; +cvar_t cl_particles_alpha = {CVAR_SAVE, "cl_particles_alpha", "1", "multiplies opacity of particles"}; cvar_t cl_particles_size = {CVAR_SAVE, "cl_particles_size", "1", "multiplies particle size"}; cvar_t cl_particles_quake = {CVAR_SAVE, "cl_particles_quake", "0", "makes particle effects look mostly like the ones in Quake"}; cvar_t cl_particles_blood = {CVAR_SAVE, "cl_particles_blood", "1", "enables blood effects"}; @@ -179,6 +180,8 @@ cvar_t cl_particles_bulletimpacts = {CVAR_SAVE, "cl_particles_bulletimpacts", "1 cvar_t cl_particles_explosions_smoke = {CVAR_SAVE, "cl_particles_explosions_smokes", "0", "enables smoke from explosions"}; cvar_t cl_particles_explosions_sparks = {CVAR_SAVE, "cl_particles_explosions_sparks", "1", "enables sparks from explosions"}; cvar_t cl_particles_explosions_shell = {CVAR_SAVE, "cl_particles_explosions_shell", "0", "enables polygonal shell from explosions"}; +cvar_t cl_particles_rain = {CVAR_SAVE, "cl_particles_rain", "1", "enables rain effects"}; +cvar_t cl_particles_snow = {CVAR_SAVE, "cl_particles_snow", "1", "enables snow effects"}; cvar_t cl_particles_smoke = {CVAR_SAVE, "cl_particles_smoke", "1", "enables smoke (used by multiple effects)"}; cvar_t cl_particles_smoke_alpha = {CVAR_SAVE, "cl_particles_smoke_alpha", "0.5", "smoke brightness"}; cvar_t cl_particles_smoke_alphafade = {CVAR_SAVE, "cl_particles_smoke_alphafade", "0.55", "brightness fade per second"}; @@ -206,7 +209,7 @@ void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend) argv[arrayindex][0] = 0; for (;;) { - if (!COM_ParseToken(&text, true)) + if (!COM_ParseToken_Simple(&text, true, false)) return; if (!strcmp(com_token, "\n")) break; @@ -415,6 +418,7 @@ void CL_Particles_Init (void) Cvar_RegisterVariable (&cl_particles); Cvar_RegisterVariable (&cl_particles_quality); + Cvar_RegisterVariable (&cl_particles_alpha); Cvar_RegisterVariable (&cl_particles_size); Cvar_RegisterVariable (&cl_particles_quake); Cvar_RegisterVariable (&cl_particles_blood); @@ -424,6 +428,8 @@ void CL_Particles_Init (void) Cvar_RegisterVariable (&cl_particles_explosions_sparks); Cvar_RegisterVariable (&cl_particles_explosions_shell); Cvar_RegisterVariable (&cl_particles_bulletimpacts); + Cvar_RegisterVariable (&cl_particles_rain); + Cvar_RegisterVariable (&cl_particles_snow); Cvar_RegisterVariable (&cl_particles_smoke); Cvar_RegisterVariable (&cl_particles_smoke_alpha); Cvar_RegisterVariable (&cl_particles_smoke_alphafade); @@ -487,6 +493,47 @@ static particle_t *particle(particletype_t *ptype, int pcolor1, int pcolor2, int part->time2 = 0; part->airfriction = pairfriction; part->liquidfriction = pliquidfriction; + part->die = cl.time + part->alpha / (part->alphafade ? part->alphafade : 1); + part->delayedcollisions = 0; + // if it is rain or snow, trace ahead and shut off collisions until an actual collision event needs to occur to improve performance + if (part->type == particletype + pt_rain) + { + int i; + particle_t *part2; + float lifetime = part->die - cl.time; + vec3_t endvec; + trace_t trace; + // turn raindrop into simple spark and create delayedspawn splash effect + part->type = particletype + pt_spark; + part->bounce = 0; + VectorMA(part->org, lifetime, part->vel, endvec); + trace = CL_Move(part->org, vec3_origin, vec3_origin, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((part->type == particletype + pt_rain || part->type == particletype + pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, NULL, false); + part->die = cl.time + lifetime * trace.fraction; + part2 = particle(particletype + pt_raindecal, pcolor1, pcolor2, tex_rainsplash, part->size, part->size * 20, part->alpha, part->alpha / 0.4, 0, 0, trace.endpos[0] + trace.plane.normal[0], trace.endpos[1] + trace.plane.normal[1], trace.endpos[2] + trace.plane.normal[2], trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2], 0, 0, 0, 0); + if (part2) + { + part2->delayedspawn = part->die; + part2->die += part->die - cl.time; + for (i = rand() & 7;i < 10;i++) + { + part2 = particle(particletype + pt_spark, pcolor1, pcolor2, tex_particle, 0.25f, 0, part->alpha * 2, part->alpha * 4, 1, 0, trace.endpos[0] + trace.plane.normal[0], trace.endpos[1] + trace.plane.normal[1], trace.endpos[2] + trace.plane.normal[2], trace.plane.normal[0] * 16, trace.plane.normal[1] * 16, trace.plane.normal[2] * 16 + cl.movevars_gravity * 0.04, 0, 0, 0, 32); + if (part2) + { + part2->delayedspawn = part->die; + part2->die += part->die - cl.time; + } + } + } + } + else if (part->bounce != 0 && part->gravity == 0) + { + float lifetime = part->alpha / (part->alphafade ? part->alphafade : 1); + vec3_t endvec; + trace_t trace; + VectorMA(part->org, lifetime, part->vel, endvec); + trace = CL_Move(part->org, vec3_origin, vec3_origin, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((part->type == particletype + pt_rain || part->type == particletype + pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, NULL, false); + part->delayedcollisions = cl.time + lifetime * trace.fraction; + } return part; } @@ -536,7 +583,8 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, CL_SpawnDecalParticleForSurface(besthitent, bestorg, bestnormal, color1, color2, texnum, size, alpha); } -static void CL_Sparks(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float sparkcount, float smokecount); +static void CL_Sparks(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float sparkcount); +static void CL_Smoke(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float smokecount); void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles) { vec3_t center; @@ -559,11 +607,11 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o { int k = particlepalette[palettecolor + (rand()&7)]; if (cl_particles_quake.integer) - particle(particletype + pt_alphastatic, k, k, tex_particle, 1, 0, lhrandom(51, 255), 512, 0.05, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 8, 0); + particle(particletype + pt_alphastatic, k, k, tex_particle, 1.5, 0, lhrandom(51, 255), 512, 0.05, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 8, 0); else if (gamemode == GAME_GOODVSBAD2) particle(particletype + pt_alphastatic, k, k, tex_particle, 5, 0, 255, 300, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 8, 10); else - particle(particletype + pt_alphastatic, k, k, tex_particle, 1, 0, 255, 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 8, 15); + particle(particletype + pt_alphastatic, k, k, tex_particle, 1.5, 0, 255, 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 8, 15); } } } @@ -582,7 +630,10 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o CL_ParticleEffect(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); } else - CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 15*count, 4*count); + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 15*count); + } } // bullet hole if (cl_stainmaps.integer) R_Stain(center, 32, 96, 96, 96, 24, 128, 128, 128, 24); @@ -598,7 +649,10 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o CL_ParticleEffect(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); } else - CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 15*count, 4*count); + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 15*count); + } } // bullet hole if (cl_stainmaps.integer) R_Stain(center, 32, 96, 96, 96, 24, 128, 128, 128, 24); @@ -615,7 +669,10 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); } else - CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 30*count, 8*count); + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 8*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 30*count); + } } // bullet hole if (cl_stainmaps.integer) R_Stain(center, 32, 96, 96, 96, 24, 128, 128, 128, 24); @@ -631,7 +688,10 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); } else - CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 30*count, 8*count); + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 8*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 30*count); + } } // bullet hole if (cl_stainmaps.integer) R_Stain(center, 32, 96, 96, 96, 24, 128, 128, 128, 24); @@ -653,7 +713,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o } } else if (effectnameindex == EFFECT_TE_SPARK) - CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, count, 0); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, count); else if (effectnameindex == EFFECT_TE_PLASMABURN) { // plasma scorch mark @@ -668,7 +728,10 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o if (cl_particles_quake.integer) CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); else - CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 15*count, 4*count); + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 20*count); + } } // bullet hole if (cl_stainmaps.integer) R_Stain(center, 32, 96, 96, 96, 24, 128, 128, 128, 24); @@ -681,7 +744,10 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o if (cl_particles_quake.integer) CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); else - CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 15*count, 4*count); + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 20*count); + } } // bullet hole if (cl_stainmaps.integer) R_Stain(center, 32, 96, 96, 96, 24, 128, 128, 128, 24); @@ -706,9 +772,9 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o for (i = 0;i < 1024 * cl_particles_quality.value;i++) { if (i & 1) - particle(particletype + pt_static, particlepalette[66], particlepalette[71], tex_particle, 1, 0, lhrandom(182, 255), 182, 0, 0, center[0], center[1], center[2], 0, 0, 0, -4, -4, 16, 256); + particle(particletype + pt_static, particlepalette[66], particlepalette[71], tex_particle, 1.5f, 0, lhrandom(182, 255), 182, 0, 0, center[0], center[1], center[2], 0, 0, 0, -4, -4, 16, 256); else - particle(particletype + pt_static, particlepalette[150], particlepalette[155], tex_particle, 1, 0, lhrandom(182, 255), 182, 0, 0, center[0], center[1], center[2], 0, 0, lhrandom(-256, 256), 0, 0, 16, 0); + particle(particletype + pt_static, particlepalette[150], particlepalette[155], tex_particle, 1.5f, 0, lhrandom(182, 255), 182, 0, 0, center[0], center[1], center[2], 0, 0, lhrandom(-256, 256), 0, 0, 16, 0); } } else @@ -740,7 +806,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o org[1] = center[1] + dir[1]; org[2] = center[2] + lhrandom(0, 64); vel = lhrandom(50, 120) / VectorLength(dir); // normalize and scale - particle(particletype + pt_alphastatic, particlepalette[224], particlepalette[231], tex_particle, 1, 0, inc * lhrandom(24, 32), inc * 12, 0.05, 0, org[0], org[1], org[2], dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0); + particle(particletype + pt_alphastatic, particlepalette[224], particlepalette[231], tex_particle, 1.5f, 0, inc * lhrandom(24, 32), inc * 12, 0.05, 0, org[0], org[1], org[2], dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0); } } } @@ -759,7 +825,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o VectorSet(dir, i*8, j*8, k*8); VectorNormalize(dir); vel = lhrandom(50, 113); - particle(particletype + pt_alphastatic, particlepalette[7], particlepalette[14], tex_particle, 1, 0, inc * lhrandom(37, 63), inc * 187, 0, 0, center[0] + i + lhrandom(0, inc), center[1] + j + lhrandom(0, inc), center[2] + k + lhrandom(0, inc), dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0); + particle(particletype + pt_alphastatic, particlepalette[7], particlepalette[14], tex_particle, 1.5f, 0, inc * lhrandom(37, 63), inc * 187, 0, 0, center[0] + i + lhrandom(0, inc), center[1] + j + lhrandom(0, inc), center[2] + k + lhrandom(0, inc), dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0); } } } @@ -849,13 +915,18 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o VectorSubtract(originmaxs, originmins, dir); len = VectorNormalizeLength(dir); - dec = -ent->persistent.trail_time; - ent->persistent.trail_time += len; - if (ent->persistent.trail_time < 0.01f) - return; + if (ent) + { + dec = -ent->persistent.trail_time; + ent->persistent.trail_time += len; + if (ent->persistent.trail_time < 0.01f) + return; - // if we skip out, leave it reset - ent->persistent.trail_time = 0.0f; + // if we skip out, leave it reset + ent->persistent.trail_time = 0.0f; + } + else + dec = 0; // advance into this frame to reach the first puff location VectorMA(originmins, dec, dir, pos); @@ -876,7 +947,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o if (cl_particles_quake.integer) { color = particlepalette[67 + (rand()&3)]; - particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 255, 128, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); + particle(particletype + pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 128, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); } else { @@ -890,7 +961,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o { dec = 6; color = particlepalette[67 + (rand()&3)]; - particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 255, 128, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); + particle(particletype + pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 128, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); } else { @@ -907,7 +978,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o { r = rand()&3; color = particlepalette[ramp3[r]]; - particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 42*(6-r), 306, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); + particle(particletype + pt_alphastatic, color, color, tex_particle, 1.5f, 0, 42*(6-r), 306, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); } else { @@ -921,11 +992,11 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o { r = 2 + (rand()%5); color = particlepalette[ramp3[r]]; - particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 42*(6-r), 306, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); + particle(particletype + pt_alphastatic, color, color, tex_particle, 1.5f, 0, 42*(6-r), 306, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); } else { - particle(particletype + pt_smoke, 0x303030, 0x606060, tex_smoke[rand()&7], 3, 0, cl_particles_smoke_alpha.value*50, cl_particles_smoke_alphafade.value*50, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); + particle(particletype + pt_smoke, 0x303030, 0x606060, tex_smoke[rand()&7], 3, 0, cl_particles_smoke_alpha.value*50, cl_particles_smoke_alphafade.value*75, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); } } else if (effectnameindex == EFFECT_TR_WIZSPIKE) @@ -934,8 +1005,8 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o { dec = 6; color = particlepalette[52 + (rand()&7)]; - particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 255, 512, 0, 0, pos[0], pos[1], pos[2], 30*dir[1], 30*-dir[0], 0, 0, 0, 0, 0); - particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 255, 512, 0, 0, pos[0], pos[1], pos[2], 30*-dir[1], 30*dir[0], 0, 0, 0, 0, 0); + particle(particletype + pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 512, 0, 0, pos[0], pos[1], pos[2], 30*dir[1], 30*-dir[0], 0, 0, 0, 0, 0); + particle(particletype + pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 512, 0, 0, pos[0], pos[1], pos[2], 30*-dir[1], 30*dir[0], 0, 0, 0, 0, 0); } else if (gamemode == GAME_GOODVSBAD2) { @@ -954,8 +1025,8 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o { dec = 6; color = particlepalette[230 + (rand()&7)]; - particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 255, 512, 0, 0, pos[0], pos[1], pos[2], 30*dir[1], 30*-dir[0], 0, 0, 0, 0, 0); - particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 255, 512, 0, 0, pos[0], pos[1], pos[2], 30*-dir[1], 30*dir[0], 0, 0, 0, 0, 0); + particle(particletype + pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 512, 0, 0, pos[0], pos[1], pos[2], 30*dir[1], 30*-dir[0], 0, 0, 0, 0, 0); + particle(particletype + pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 512, 0, 0, pos[0], pos[1], pos[2], 30*-dir[1], 30*dir[0], 0, 0, 0, 0, 0); } else { @@ -968,7 +1039,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o if (cl_particles_quake.integer) { color = particlepalette[152 + (rand()&3)]; - particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 255, 850, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 8, 0); + particle(particletype + pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 850, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 8, 0); } else if (gamemode == GAME_GOODVSBAD2) { @@ -1008,7 +1079,8 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o len -= dec; VectorMA (pos, dec, dir, pos); } - ent->persistent.trail_time = len; + if (ent) + ent->persistent.trail_time = len; } else if (developer.integer >= 1) Con_Printf("CL_ParticleEffect_Fallback: no fallback found for effect %s\n", particleeffectname[effectnameindex]); @@ -1106,6 +1178,8 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins case pt_spark: if (!cl_particles_sparks.integer) continue;break; case pt_bubble: if (!cl_particles_bubbles.integer) continue;break; case pt_blood: if (!cl_particles_blood.integer) continue;break; + case pt_rain: if (!cl_particles_rain.integer) continue;break; + case pt_snow: if (!cl_particles_snow.integer) continue;break; default: break; } VectorCopy(originmins, trailpos); @@ -1291,12 +1365,12 @@ void CL_ParticleExplosion (const vec3_t org) if (i & 1) { color = particlepalette[ramp1[r]]; - particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 32 * (8 - r), 318, 0, 0, org[0], org[1], org[2], 0, 0, 0, -4, -4, 16, 256); + particle(particletype + pt_alphastatic, color, color, tex_particle, 1.5f, 0, 32 * (8 - r), 318, 0, 0, org[0], org[1], org[2], 0, 0, 0, -4, -4, 16, 256); } else { color = particlepalette[ramp2[r]]; - particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 32 * (8 - r), 478, 0, 0, org[0], org[1], org[2], 0, 0, 0, 1, 1, 16, 256); + particle(particletype + pt_alphastatic, color, color, tex_particle, 1.5f, 0, 32 * (8 - r), 478, 0, 0, org[0], org[1], org[2], 0, 0, 0, 1, 1, 16, 256); } } } @@ -1335,8 +1409,24 @@ void CL_ParticleExplosion (const vec3_t org) } if (cl_particles.integer && cl_particles_sparks.integer && cl_particles_explosions_sparks.integer) - for (i = 0;i < 128 * cl_particles_quality.value;i++) - particle(particletype + pt_spark, 0x903010, 0xFFD030, tex_particle, 1.0f, 0, lhrandom(0, 255), 512, 1, 0, org[0], org[1], org[2], 0, 0, 80, 0.2, 0.8, 0, 256); + { + for (i = 0;i < 512 * cl_particles_quality.value;i++) + { + int k; + vec3_t v, v2; + for (k = 0;k < 16;k++) + { + VectorRandom(v2); + VectorMA(org, 128, v2, v); + trace = CL_Move(org, vec3_origin, vec3_origin, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false); + if (trace.fraction >= 0.1) + break; + } + VectorSubtract(trace.endpos, org, v2); + VectorScale(v2, 2.0f, v2); + particle(particletype + pt_spark, 0x903010, 0xFFD030, tex_particle, 1.0f, 0, lhrandom(0, 255), 512, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0, 0, 0, 0); + } + } } } @@ -1365,19 +1455,23 @@ void CL_ParticleExplosion2 (const vec3_t org, int colorStart, int colorLength) } } -static void CL_Sparks(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float sparkcount, float smokecount) +static void CL_Sparks(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float sparkcount) { if (cl_particles_sparks.integer) { sparkcount *= cl_particles_quality.value; while(sparkcount-- > 0) - particle(particletype + pt_spark, particlepalette[0x68], particlepalette[0x6f], tex_particle, 0.4f, 0, lhrandom(64, 255), 512, 1, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]) + sv_gravity.value * 0.1, 0, 0, 0, 64); + particle(particletype + pt_spark, particlepalette[0x68], particlepalette[0x6f], tex_particle, 0.5f, 0, lhrandom(64, 255), 512, 1, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]) + cl.movevars_gravity * 0.1f, 0, 0, 0, 64); } +} + +static void CL_Smoke(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float smokecount) +{ if (cl_particles_smoke.integer) { smokecount *= cl_particles_quality.value; while(smokecount-- > 0) - particle(particletype + pt_smoke, 0x101010, 0x202020, tex_smoke[rand()&7], 3, 0, 255, 1024, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 0, 8); + particle(particletype + pt_smoke, 0x101010, 0x101010, tex_smoke[rand()&7], 2, 2, 255, 256, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 0, smokecount > 0 ? 16 : 0); } } @@ -1415,6 +1509,7 @@ void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, in switch(type) { case 0: + if (!cl_particles_rain.integer) break; count *= 4; // ick, this should be in the mod or maps? while(count--) @@ -1427,6 +1522,7 @@ void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, in } break; case 1: + if (!cl_particles_snow.integer) break; while(count--) { k = particlepalette[colorbase + (rand()&3)]; @@ -1465,7 +1561,7 @@ void CL_MoveParticles (void) } frametime = bound(0, cl.time - cl.oldtime, 0.1); - gravity = frametime * sv_gravity.value; + gravity = frametime * cl.movevars_gravity; dvel = 1+4*frametime; decalfade = frametime * 255 / cl_decals_fadetime.value; decaltype = particletype + pt_decal; @@ -1515,11 +1611,19 @@ void CL_MoveParticles (void) 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) + if (p->alpha <= 0 || p->die <= cl.time) { p->type = NULL; if (cl.free_particle > i) @@ -1532,7 +1636,7 @@ void CL_MoveParticles (void) VectorCopy(p->org, oldorg); VectorMA(p->org, frametime, p->vel, p->org); VectorCopy(p->org, org); - if (p->bounce) + 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->type == particletype + pt_rain ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, &hitent, false); // if the trace started in or hit something of SUPERCONTENTS_NODROP @@ -1563,10 +1667,10 @@ void CL_MoveParticles (void) p->liquidfriction = 0; p->gravity = 0; p->size *= 1.0f; - p->sizeincrease = p->size * 16; - count = rand() & 3; + p->sizeincrease = p->size * 20; + count = (int)lhrandom(1, 10); 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, 0, 32); + 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, cl.movevars_gravity * 0.04 + p->vel[2]*16, 0, 0, 0, 32); } else if (p->type == bloodtype) { @@ -1576,6 +1680,8 @@ void CL_MoveParticles (void) p->type = NULL; 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->type = NULL; @@ -1584,8 +1690,6 @@ void CL_MoveParticles (void) // 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]; @@ -2071,19 +2175,21 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh R_Mesh_Matrix(&identitymatrix); R_Mesh_ResetTextureState(); - R_Mesh_VertexPointer(particle_vertex3f); - R_Mesh_TexCoordPointer(0, 2, particle_texcoord2f); - R_Mesh_ColorPointer(particle_color4f); + R_Mesh_VertexPointer(particle_vertex3f, 0, 0); + R_Mesh_TexCoordPointer(0, 2, particle_texcoord2f, 0, 0); + R_Mesh_ColorPointer(particle_color4f, 0, 0); GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_PolygonOffset(0, 0); GL_DepthTest(true); - GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces + GL_CullFace(GL_NONE); // first generate all the vertices at once for (surfacelistindex = 0, v3f = particle_vertex3f, t2f = particle_texcoord2f, c4f = particle_color4f;surfacelistindex < numsurfaces;surfacelistindex++, v3f += 3*4, t2f += 2*4, c4f += 4*4) { particletexture_t *tex; const float *org; - float up2[3], v[3], right[3], up[3], fog, ifog, cr, cg, cb, ca, size; + float up2[3], v[3], right[3], up[3], fog, cr, cg, cb, ca, size; p = cl.particles + surfacelist[surfacelistindex]; @@ -2103,7 +2209,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh cb = min(cb, 1); ca = 1; } - ca /= cl_particles_quality.value; + ca *= cl_particles_alpha.value; if (p->type->lighting) { float ambient[3], diffuse[3], diffusenormal[3]; @@ -2114,13 +2220,13 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh } if (r_refdef.fogenabled) { - fog = VERTEXFOGTABLE(VectorDistance(p->org, r_view.origin)); - ifog = 1 - fog; - cr = cr * ifog; - cg = cg * ifog; - cb = cb * ifog; + fog = FogPoint_World(p->org); + cr = cr * fog; + cg = cg * fog; + cb = cb * fog; if (blendmode == PBLEND_ALPHA) { + fog = 1 - fog; cr += r_refdef.fogcolor[0] * fog * r_view.colorscale; cg += r_refdef.fogcolor[1] * fog * r_view.colorscale; cb += r_refdef.fogcolor[2] * fog * r_view.colorscale; @@ -2157,14 +2263,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh } else if (p->type->orientation == PARTICLE_ORIENTED_DOUBLESIDED) { - // double-sided - if (DotProduct(p->vel, r_view.origin) > DotProduct(p->vel, org)) - { - VectorNegate(p->vel, v); - VectorVectors(v, right, up); - } - else - VectorVectors(p->vel, right, up); + VectorVectors(p->vel, right, up); VectorScale(right, size, right); VectorScale(up, size, up); v3f[ 0] = org[0] - right[0] - up[0]; @@ -2228,7 +2327,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh if (blendmode != p->type->blendmode) { if (batchcount > 0) - R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6); + R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6, 0, 0); batchcount = 0; batchstart = surfacelistindex; blendmode = p->type->blendmode; @@ -2242,7 +2341,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh if (texture != particletexture[p->texnum].texture) { if (batchcount > 0) - R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6); + R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6, 0, 0); batchcount = 0; batchstart = surfacelistindex; texture = particletexture[p->texnum].texture; @@ -2252,7 +2351,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh batchcount++; } if (batchcount > 0) - R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6); + R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6, 0, 0); GL_LockArrays(0, 0); } @@ -2271,7 +2370,7 @@ void R_DrawParticles (void) // LordHavoc: only render if not too close for (i = 0, p = cl.particles;i < cl.num_particles;i++, p++) { - if (p->type) + if (p->type && !p->delayedspawn) { r_refdef.stats.particles++; if (DotProduct(p->org, r_view.forward) >= minparticledist || p->type->orientation == PARTICLE_BEAM)