X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=cl_particles.c;h=06716148f2deffca1eeedb7dee56255bc4372350;hb=4fcf642ab8c87b9cd34580c69c2bccded2d8fd83;hp=fb1c128284e49a56ccf3788955171b7f452eee07;hpb=b6f04e7a3b73a2b2449add51f1e48097c0feec8c;p=xonotic%2Fdarkplaces.git diff --git a/cl_particles.c b/cl_particles.c index fb1c1282..06716148 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"}; @@ -208,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)) return; if (!strcmp(com_token, "\n")) break; @@ -417,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); @@ -491,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; } @@ -1418,7 +1461,7 @@ static void CL_Sparks(const vec3_t originmins, const vec3_t originmaxs, const ve { sparkcount *= cl_particles_quality.value; while(sparkcount-- > 0) - 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]) + sv_gravity.value * 0.1f, 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); } } @@ -1518,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; @@ -1568,12 +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) @@ -1586,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 @@ -1617,10 +1667,10 @@ void CL_MoveParticles (void) p->liquidfriction = 0; p->gravity = 0; p->size *= 1.0f; - p->sizeincrease = p->size * 2; - 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, sv_gravity.value * 0.04 + 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) { @@ -2129,6 +2179,8 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh 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 @@ -2137,7 +2189,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh { 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]; @@ -2157,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]; @@ -2168,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; @@ -2325,7 +2377,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)