X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=cl_particles.c;h=49654d823c3d44482c904bf07eb3fb79ff042e8b;hb=3161ae840da309834bd08f39be63777836fade71;hp=d4febd9aac69905cdb08d3cfd2d4fd7327a8089b;hpb=19018c02ab3e3ede834c428ecba810b250699dbd;p=xonotic%2Fdarkplaces.git diff --git a/cl_particles.c b/cl_particles.c index d4febd9a..49654d82 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -44,6 +44,7 @@ particletype_t particletype[pt_total] = #define PARTICLEEFFECT_UNDERWATER 1 #define PARTICLEEFFECT_NOTUNDERWATER 2 +#define PARTICLEEFFECT_DEFINED 2147483648U typedef struct particleeffectinfo_s { @@ -296,6 +297,7 @@ cvar_t cl_particles_sparks = {CVAR_SAVE, "cl_particles_sparks", "1", "enables sp cvar_t cl_particles_bubbles = {CVAR_SAVE, "cl_particles_bubbles", "1", "enables bubbles (used by multiple effects)"}; cvar_t cl_particles_visculling = {CVAR_SAVE, "cl_particles_visculling", "0", "perform a costly check if each particle is visible before drawing"}; cvar_t cl_particles_collisions = {CVAR_SAVE, "cl_particles_collisions", "1", "allow costly collision detection on particles (sparks that bounce, particles not going through walls, blood hitting surfaces, etc)"}; +cvar_t cl_particles_forcetraileffects = {0, "cl_particles_forcetraileffects", "0", "force trails to be displayed even if a non-trail draw primitive was used (debug/compat feature)"}; cvar_t cl_decals = {CVAR_SAVE, "cl_decals", "1", "enables decals (bullet holes, blood, etc)"}; cvar_t cl_decals_visculling = {CVAR_SAVE, "cl_decals_visculling", "1", "perform a very cheap check if each decal is visible before drawing"}; cvar_t cl_decals_time = {CVAR_SAVE, "cl_decals_time", "20", "how long before decals start to fade away"}; @@ -313,6 +315,7 @@ static void CL_Particles_ParseEffectInfo(const char *textstart, const char *text { int arrayindex; int argc; + int i; int linenumber; particleeffectinfo_t *info = NULL; const char *text = textstart; @@ -370,17 +373,29 @@ static void CL_Particles_ParseEffectInfo(const char *textstart, const char *text Con_Printf("%s:%i: too many effects!\n", filename, linenumber); break; } + for(i = 0; i < numparticleeffectinfo; ++i) + { + info = particleeffectinfo + i; + if(!(info->flags & PARTICLEEFFECT_DEFINED)) + if(info->effectnameindex == effectnameindex) + break; + } + if(i < numparticleeffectinfo) + continue; info = particleeffectinfo + numparticleeffectinfo++; // copy entire info from baseline, then fix up the nameindex *info = baselineparticleeffectinfo; info->effectnameindex = effectnameindex; + continue; } else if (info == NULL) { Con_Printf("%s:%i: command %s encountered before effect\n", filename, linenumber, argv[0]); break; } - else if (!strcmp(argv[0], "countabsolute")) {readfloat(info->countabsolute);} + + info->flags |= PARTICLEEFFECT_DEFINED; + if (!strcmp(argv[0], "countabsolute")) {readfloat(info->countabsolute);} else if (!strcmp(argv[0], "count")) {readfloat(info->countmultiplier);} else if (!strcmp(argv[0], "type")) { @@ -595,6 +610,7 @@ void CL_Particles_Init (void) Cvar_RegisterVariable (&cl_particles_bubbles); Cvar_RegisterVariable (&cl_particles_visculling); Cvar_RegisterVariable (&cl_particles_collisions); + Cvar_RegisterVariable (&cl_particles_forcetraileffects); Cvar_RegisterVariable (&cl_decals); Cvar_RegisterVariable (&cl_decals_visculling); Cvar_RegisterVariable (&cl_decals_time); @@ -749,14 +765,13 @@ particle_t *CL_NewParticle(const vec3_t sortorigin, unsigned short ptypeindex, i { 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->typeindex = pt_spark; part->bounce = 0; VectorMA(part->org, lifetime, part->vel, endvec); - trace = CL_TraceLine(part->org, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK, true, false, NULL, false, false); + trace = CL_TraceLine(part->org, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK, 0, 0, collision_extendmovelength.value, true, false, NULL, false, false); part->die = cl.time + lifetime * trace.fraction; part2 = CL_NewParticle(endvec, 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, pqualityreduction, 0, 1, PBLEND_ADD, PARTICLE_ORIENTED_DOUBLESIDED, -1, -1, -1, 1, 1, 0, 0, NULL); if (part2) @@ -897,7 +912,7 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, { VectorRandom(org2); VectorMA(org, maxdist, org2, org2); - trace = CL_TraceLine(org, org2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, true, false, &hitent, false, true); + trace = CL_TraceLine(org, org2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, 0, 0, collision_extendmovelength.value, true, false, &hitent, false, true); // take the closest trace result that doesn't end up hitting a NOMARKS // surface (sky for example) if (bestfrac > trace.fraction && !(trace.hitq3surfaceflags & Q3SURFACEFLAG_NOMARKS)) @@ -914,23 +929,24 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, 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); -static 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) +static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, 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, float tintmins[4], float tintmaxs[4], float fade, qboolean wanttrail); +static 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, qboolean wanttrail) { vec3_t center; - matrix4x4_t tempmatrix; + matrix4x4_t lightmatrix; particle_t *part; VectorLerp(originmins, 0.5, originmaxs, center); - Matrix4x4_CreateTranslate(&tempmatrix, center[0], center[1], center[2]); + Matrix4x4_CreateTranslate(&lightmatrix, center[0], center[1], center[2]); if (effectnameindex == EFFECT_SVC_PARTICLE) { if (cl_particles.integer) { // bloodhack checks if this effect's color matches regular or lightning blood and if so spawns a blood effect instead if (count == 1024) - CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + CL_NewParticlesFromEffectinfo(EFFECT_TE_EXPLOSION, 1, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail); else if (cl_particles_blood_bloodhack.integer && !cl_particles_quake.integer && (palettecolor == 73 || palettecolor == 225)) - CL_ParticleEffect(EFFECT_TE_BLOOD, count / 2.0f, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + CL_NewParticlesFromEffectinfo(EFFECT_TE_BLOOD, count / 2.0f, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail); else { count *= cl_particles_quality.value; @@ -943,9 +959,9 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v } } else if (effectnameindex == EFFECT_TE_WIZSPIKE) - CL_ParticleEffect(EFFECT_SVC_PARTICLE, 30*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 20); + CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 30*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 20, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail); else if (effectnameindex == EFFECT_TE_KNIGHTSPIKE) - CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 226); + CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 226, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail); else if (effectnameindex == EFFECT_TE_SPIKE) { if (cl_particles_bulletimpacts.integer) @@ -953,7 +969,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v if (cl_particles_quake.integer) { if (cl_particles_smoke.integer) - CL_ParticleEffect(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail); } else { @@ -973,7 +989,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v if (cl_particles_quake.integer) { if (cl_particles_smoke.integer) - CL_ParticleEffect(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail); } else { @@ -985,7 +1001,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v // bullet hole R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64); CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); - CL_AllocLightFlash(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (effectnameindex == EFFECT_TE_SUPERSPIKE) { @@ -994,7 +1010,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v if (cl_particles_quake.integer) { if (cl_particles_smoke.integer) - CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail); } else { @@ -1014,7 +1030,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v if (cl_particles_quake.integer) { if (cl_particles_smoke.integer) - CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail); } else { @@ -1026,14 +1042,14 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v // bullet hole R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64); CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); - CL_AllocLightFlash(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (effectnameindex == EFFECT_TE_BLOOD) { if (!cl_particles_blood.integer) return; if (cl_particles_quake.integer) - CL_ParticleEffect(EFFECT_SVC_PARTICLE, 2*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 73); + CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 2*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 73, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail); else { static double bloodaccumulator = 0; @@ -1058,14 +1074,14 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v // plasma scorch mark R_Stain(center, 40, 40, 40, 40, 64, 88, 88, 88, 64); CL_SpawnDecalParticleForPoint(center, 6, 6, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); - CL_AllocLightFlash(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 200, 1, 1, 1, 1000, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (effectnameindex == EFFECT_TE_GUNSHOT) { if (cl_particles_bulletimpacts.integer) { if (cl_particles_quake.integer) - CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail); else { CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count); @@ -1082,7 +1098,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v if (cl_particles_bulletimpacts.integer) { if (cl_particles_quake.integer) - CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail); else { CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count); @@ -1093,17 +1109,17 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v // bullet hole R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64); CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); - CL_AllocLightFlash(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (effectnameindex == EFFECT_TE_EXPLOSION) { CL_ParticleExplosion(center); - CL_AllocLightFlash(NULL, &tempmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (effectnameindex == EFFECT_TE_EXPLOSIONQUAD) { CL_ParticleExplosion(center); - CL_AllocLightFlash(NULL, &tempmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (effectnameindex == EFFECT_TE_TAREXPLOSION) { @@ -1120,10 +1136,10 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v } else CL_ParticleExplosion(center); - CL_AllocLightFlash(NULL, &tempmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (effectnameindex == EFFECT_TE_SMALLFLASH) - CL_AllocLightFlash(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 200, 2, 2, 2, 1000, 0.2, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); else if (effectnameindex == EFFECT_TE_FLAMEJET) { count *= cl_particles_quality.value; @@ -1178,7 +1194,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v } if (!cl_particles_quake.integer) CL_NewParticle(center, pt_static, 0xffffff, 0xffffff, tex_particle, 30, 0, 256, 512, 0, 0, center[0], center[1], center[2], 0, 0, 0, 0, 0, 0, 0, false, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); - CL_AllocLightFlash(NULL, &tempmatrix, 200, 2.0f, 2.0f, 2.0f, 400, 99.0f, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 200, 2.0f, 2.0f, 2.0f, 400, 99.0f, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (effectnameindex == EFFECT_TE_TEI_G3) CL_NewParticle(center, pt_beam, 0xFFFFFF, 0xFFFFFF, tex_beam, 8, 0, 256, 256, 0, 0, originmins[0], originmins[1], originmins[2], originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, 0, false, 0, 1, PBLEND_ADD, PARTICLE_HBEAM, -1, -1, -1, 1, 1, 0, 0, NULL); @@ -1194,7 +1210,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v else if (effectnameindex == EFFECT_TE_TEI_BIGEXPLOSION) { CL_ParticleExplosion(center); - CL_AllocLightFlash(NULL, &tempmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, -1, true, 1, 0.25, 0.5, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, -1, true, 1, 0.25, 0.5, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (effectnameindex == EFFECT_TE_TEI_PLASMAHIT) { @@ -1207,7 +1223,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v if (cl_particles_sparks.integer) for (f = 0;f < count;f += 1.0f / cl_particles_quality.value) CL_NewParticle(center, pt_spark, 0x2030FF, 0x80C0FF, tex_particle, 2.0f, 0, lhrandom(64, 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, 0, 465, true, 0, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL); - CL_AllocLightFlash(NULL, &tempmatrix, 500, 0.6f, 1.2f, 2.0f, 2000, 9999, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 500, 0.6f, 1.2f, 2.0f, 2000, 9999, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (effectnameindex == EFFECT_EF_FLAME) { @@ -1216,7 +1232,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v count *= 300 * cl_particles_quality.value; while (count-- > 0) CL_NewParticle(center, pt_smoke, 0x6f0f00, 0xe3974f, tex_particle, 4, 0, lhrandom(64, 128), 384, -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]), 1, 4, 16, 128, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); - CL_AllocLightFlash(NULL, &tempmatrix, 200, 2.0f, 1.5f, 0.5f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 200, 2.0f, 1.5f, 0.5f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (effectnameindex == EFFECT_EF_STARDUST) { @@ -1225,13 +1241,13 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v count *= 200 * cl_particles_quality.value; while (count-- > 0) CL_NewParticle(center, pt_static, 0x903010, 0xFFD030, tex_particle, 4, 0, lhrandom(64, 128), 128, 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]), 0.2, 0.8, 16, 128, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); - CL_AllocLightFlash(NULL, &tempmatrix, 200, 1.0f, 0.7f, 0.3f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &lightmatrix, 200, 1.0f, 0.7f, 0.3f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (!strncmp(particleeffectname[effectnameindex], "TR_", 3)) { vec3_t dir, pos; float len, dec, qd; - int smoke, blood, bubbles, r, color; + int smoke, blood, bubbles, r, color, spawnedcount; if (spawndlight && r_refdef.scene.numlights < MAX_DLIGHTS) { @@ -1252,9 +1268,9 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v if (light[3]) { - matrix4x4_t tempmatrix; - Matrix4x4_CreateFromQuakeEntity(&tempmatrix, originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, light[3]); - R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, light, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + matrix4x4_t traillightmatrix; + Matrix4x4_CreateFromQuakeEntity(&traillightmatrix, originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, light[3]); + R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &traillightmatrix, light, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++; } } @@ -1267,6 +1283,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v VectorSubtract(originmaxs, originmins, dir); len = VectorNormalizeLength(dir); + if (ent) { dec = -ent->persistent.trail_time; @@ -1288,8 +1305,9 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v blood = cl_particles.integer && cl_particles_blood.integer; bubbles = cl_particles.integer && cl_particles_bubbles.integer && !cl_particles_quake.integer && (CL_PointSuperContents(pos) & (SUPERCONTENTS_WATER | SUPERCONTENTS_SLIME)); qd = 1.0f / cl_particles_quality.value; + spawnedcount = 0; - while (len >= 0) + while (len >= 0 && ++spawnedcount <= 16384) { dec = 3; if (blood) @@ -1440,9 +1458,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v // this is also called on point effects with spawndlight = true and // spawnparticles = true -// it is called CL_ParticleTrail because most code does not want to supply -// these parameters, only trail handling does -void CL_ParticleTrail(int effectnameindex, float pcount, 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, float tintmins[4], float tintmaxs[4]) +static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, 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, float tintmins[4], float tintmaxs[4], float fade, qboolean wanttrail) { qboolean found = false; char vabuf[1024]; @@ -1489,8 +1505,14 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins } for (effectinfoindex = 0, info = particleeffectinfo;effectinfoindex < MAX_PARTICLEEFFECTINFO && info->effectnameindex;effectinfoindex++, info++) { - if (info->effectnameindex == effectnameindex) + if ((info->effectnameindex == effectnameindex) && (info->flags & PARTICLEEFFECT_DEFINED)) { + qboolean definedastrail = info->trailspacing > 0; + + qboolean drawastrail = wanttrail; + if (cl_particles_forcetraileffects.integer) + drawastrail = drawastrail || definedastrail; + found = true; if ((info->flags & PARTICLEEFFECT_UNDERWATER) && !underwater) continue; @@ -1501,7 +1523,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins if (info->lightradiusstart > 0 && spawndlight) { matrix4x4_t tempmatrix; - if (info->trailspacing > 0) + if (drawastrail) Matrix4x4_CreateTranslate(&tempmatrix, originmaxs[0], originmaxs[1], originmaxs[2]); else Matrix4x4_CreateTranslate(&tempmatrix, center[0], center[1], center[2]); @@ -1552,6 +1574,9 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins } else if (info->orientation == PARTICLE_HBEAM) { + if (!drawastrail) + continue; + AnglesFromVectors(angles, traildir, NULL, false); AngleVectors(angles, forward, right, up); VectorMAMAM(info->relativeoriginoffset[0], forward, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); @@ -1560,6 +1585,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins } else { + float cnt; if (!cl_particles.integer) continue; switch (info->particletype) @@ -1572,33 +1598,50 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins case pt_snow: if (!cl_particles_snow.integer) continue;break; default: break; } - VectorCopy(originmins, trailpos); - if (info->trailspacing > 0) - { - info->particleaccumulator += traillen / info->trailspacing * cl_particles_quality.value; - trailstep = info->trailspacing / cl_particles_quality.value; - immediatebloodstain = false; - AnglesFromVectors(angles, traildir, NULL, false); - AngleVectors(angles, forward, right, up); - VectorMAMAMAM(1.0f, trailpos, info->relativeoriginoffset[0], forward, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); - VectorMAMAM(info->relativevelocityoffset[0], forward, info->relativevelocityoffset[1], right, info->relativevelocityoffset[2], up, velocity); - } + cnt = info->countabsolute; + cnt += (pcount * info->countmultiplier) * cl_particles_quality.value; + // if drawastrail is not set, we will + // use the regular cnt-based random + // particle spawning at the center; so + // do NOT apply trailspacing then! + if (drawastrail && definedastrail) + cnt += (traillen / info->trailspacing) * cl_particles_quality.value; + cnt *= fade; + if (cnt == 0) + continue; // nothing to draw + info->particleaccumulator += cnt; + + if (drawastrail || definedastrail) + immediatebloodstain = false; else - { - info->particleaccumulator += info->countabsolute + pcount * info->countmultiplier * cl_particles_quality.value; - trailstep = 0; immediatebloodstain = ((cl_decals_newsystem_immediatebloodstain.integer >= 1) && (info->particletype == pt_blood)) || ((cl_decals_newsystem_immediatebloodstain.integer >= 2) && staintex); + if (drawastrail) + { + VectorCopy(originmins, trailpos); + trailstep = traillen / cnt; + } + else + { + VectorCopy(center, trailpos); + trailstep = 0; + } + + if (trailstep == 0) + { VectorMAM(0.5f, velocitymins, 0.5f, velocitymaxs, velocity); AnglesFromVectors(angles, velocity, NULL, false); - AngleVectors(angles, forward, right, up); - VectorMAMAMAM(1.0f, trailpos, info->relativeoriginoffset[0], traildir, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); - VectorMAMAM(info->relativevelocityoffset[0], traildir, info->relativevelocityoffset[1], right, info->relativevelocityoffset[2], up, velocity); } + else + AnglesFromVectors(angles, traildir, NULL, false); + + AngleVectors(angles, forward, right, up); + VectorMAMAMAM(1.0f, trailpos, info->relativeoriginoffset[0], forward, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); + VectorMAMAM(info->relativevelocityoffset[0], forward, info->relativevelocityoffset[1], right, info->relativevelocityoffset[2], up, velocity); info->particleaccumulator = bound(0, info->particleaccumulator, 16384); for (;info->particleaccumulator >= 1;info->particleaccumulator--) { @@ -1607,7 +1650,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins tex = (int)lhrandom(info->tex[0], info->tex[1]); tex = min(tex, info->tex[1] - 1); } - if (!trailstep) + if (!(drawastrail || definedastrail)) { trailpos[0] = lhrandom(originmins[0], originmaxs[0]); trailpos[1] = lhrandom(originmins[1], originmaxs[1]); @@ -1633,12 +1676,23 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins } } if (!found) - CL_ParticleEffect_Fallback(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles); + CL_ParticleEffect_Fallback(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles, wanttrail); +} + +void CL_ParticleTrail(int effectnameindex, float pcount, 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, float tintmins[4], float tintmaxs[4], float fade) +{ + CL_NewParticlesFromEffectinfo(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles, tintmins, tintmaxs, fade, true); } +void CL_ParticleBox(int effectnameindex, float pcount, 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, float tintmins[4], float tintmaxs[4], float fade) +{ + CL_NewParticlesFromEffectinfo(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles, tintmins, tintmaxs, fade, false); +} + +// note: this one ONLY does boxes! void CL_ParticleEffect(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor) { - CL_ParticleTrail(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, true, true, NULL, NULL); + CL_ParticleBox(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, true, true, NULL, NULL, 1); } /* @@ -1648,7 +1702,7 @@ CL_EntityParticles */ void CL_EntityParticles (const entity_t *ent) { - int i; + int i, j; vec_t pitch, yaw, dist = 64, beamlength = 16; vec3_t org, v; static vec3_t avelocities[NUMVERTEXNORMALS]; @@ -1658,8 +1712,9 @@ void CL_EntityParticles (const entity_t *ent) Matrix4x4_OriginFromMatrix(&ent->render.matrix, org); if (!avelocities[0][0]) - for (i = 0;i < NUMVERTEXNORMALS * 3;i++) - avelocities[0][i] = lhrandom(0, 2.55); + for (i = 0;i < NUMVERTEXNORMALS;i++) + for (j = 0;j < 3;j++) + avelocities[i][j] = lhrandom(0, 2.55); for (i = 0;i < NUMVERTEXNORMALS;i++) { @@ -1731,6 +1786,11 @@ void CL_ReadPointFile_f (void) VectorCopy(leakorg, vecorg); Con_Printf("%i points read (%i particles spawned)\nLeak at %f %f %f\n", c, s, leakorg[0], leakorg[1], leakorg[2]); + if (c == 0) + { + return; + } + CL_NewParticle(vecorg, pt_beam, 0xFF0000, 0xFF0000, tex_beam, 64, 0, 255, 0, 0, 0, org[0] - 4096, org[1], org[2], org[0] + 4096, org[1], org[2], 0, 0, 0, 0, false, 1<<30, 1, PBLEND_ADD, PARTICLE_HBEAM, -1, -1, -1, 1, 1, 0, 0, NULL); CL_NewParticle(vecorg, pt_beam, 0x00FF00, 0x00FF00, tex_beam, 64, 0, 255, 0, 0, 0, org[0], org[1] - 4096, org[2], org[0], org[1] + 4096, org[2], 0, 0, 0, 0, false, 1<<30, 1, PBLEND_ADD, PARTICLE_HBEAM, -1, -1, -1, 1, 1, 0, 0, NULL); CL_NewParticle(vecorg, pt_beam, 0x0000FF, 0x0000FF, tex_beam, 64, 0, 255, 0, 0, 0, org[0], org[1], org[2] - 4096, org[0], org[1], org[2] + 4096, 0, 0, 0, 0, false, 1<<30, 1, PBLEND_ADD, PARTICLE_HBEAM, -1, -1, -1, 1, 1, 0, 0, NULL); @@ -1816,7 +1876,7 @@ void CL_ParticleExplosion (const vec3_t org) { VectorRandom(v2); VectorMA(org, 128, v2, v); - trace = CL_TraceLine(org, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, false); + trace = CL_TraceLine(org, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value, true, false, NULL, false, false); } while (k < 16 && trace.fraction < 0.1f); VectorSubtract(trace.endpos, org, v2); @@ -2120,7 +2180,7 @@ static void R_InitParticleTexture (void) // we invert it again during the blendfunc to make it work... #ifndef DUMPPARTICLEFONT - decalskinframe = R_SkinFrame_LoadExternal("particles/particlefont.tga", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, false); + decalskinframe = R_SkinFrame_LoadExternal("particles/particlefont.tga", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, false, false); if (decalskinframe) { particlefonttexture = decalskinframe->base; @@ -2367,12 +2427,7 @@ static void R_InitParticleTexture (void) Con_Printf("particles/particlefont.txt: texnum %i outside valid range (0 to %i)\n", i, MAX_PARTICLETEXTURES); continue; } - sf = R_SkinFrame_LoadExternal(texturename, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true); // note: this loads as sRGB if sRGB is active! - if(!sf) - { - // R_SkinFrame_LoadExternal already complained - continue; - } + sf = R_SkinFrame_LoadExternal(texturename, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, true); // note: this loads as sRGB if sRGB is active! particletexture[i].texture = sf->base; particletexture[i].s1 = s1; particletexture[i].t1 = t1; @@ -2440,7 +2495,7 @@ static void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rt vec_t right[3], up[3], size, ca; float alphascale = (1.0f / 65536.0f) * cl_particles_alpha.value; - RSurf_ActiveWorldEntity(); + RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false); r_refdef.stats[r_stat_drawndecals] += numsurfaces; // R_Mesh_ResetTextureState(); @@ -2499,7 +2554,7 @@ static void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rt // now render the decals all at once // (this assumes they all use one particle font texture!) GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - R_SetupShader_Generic(particletexture[63].texture, NULL, GL_MODULATE, 1, false, false, true); + R_SetupShader_Generic(particletexture[63].texture, false, false, true); R_Mesh_PrepareVertices_Generic_Arrays(numsurfaces * 4, particle_vertex3f, particle_color4f, particle_texcoord2f); R_Mesh_Draw(0, numsurfaces * 4, 0, numsurfaces * 2, NULL, NULL, 0, particle_elements, NULL, 0); } @@ -2512,7 +2567,7 @@ void R_DrawDecals (void) float frametime; float decalfade; float drawdist2; - int killsequence = cl.decalsequence - max(0, cl_decals_max.integer); + unsigned int killsequence = cl.decalsequence - bound(0, (unsigned int) cl_decals_max.integer, cl.decalsequence); frametime = bound(0, cl.time - cl.decals_updatetime, 1); cl.decals_updatetime = bound(cl.time - 1, cl.decals_updatetime + frametime, cl.time + 1); @@ -2530,7 +2585,7 @@ void R_DrawDecals (void) if (!decal->typeindex) continue; - if (killsequence - decal->decalsequence > 0) + if (killsequence > decal->decalsequence) goto killdecal; if (cl.time > decal->time2 + cl_decals_time.value) @@ -2557,7 +2612,7 @@ void R_DrawDecals (void) if (!drawdecals) continue; - if (DotProduct(r_refdef.view.origin, decal->normal) > DotProduct(decal->org, decal->normal) && VectorDistance2(decal->org, r_refdef.view.origin) < drawdist2 * (decal->size * decal->size)) + if (!r_refdef.view.useperspective || (DotProduct(r_refdef.view.origin, decal->normal) > DotProduct(decal->org, decal->normal) && VectorDistance2(decal->org, r_refdef.view.origin) < drawdist2 * (decal->size * decal->size))) R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, decal->org, R_DrawDecal_TransparentCallback, NULL, i, NULL); continue; killdecal: @@ -2599,7 +2654,7 @@ static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const float minparticledist_start, minparticledist_end; qboolean dofade; - RSurf_ActiveWorldEntity(); + RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false); Vector4Set(colormultiplier, r_refdef.view.colorscale * (1.0 / 256.0f), r_refdef.view.colorscale * (1.0 / 256.0f), r_refdef.view.colorscale * (1.0 / 256.0f), cl_particles_alpha.value * (1.0 / 256.0f)); @@ -2663,10 +2718,14 @@ static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const // note: lighting is not cheap! if (particletype[p->typeindex].lighting) { + float a[3], c[3], dir[3]; vecorg[0] = p->org[0]; vecorg[1] = p->org[1]; vecorg[2] = p->org[2]; - R_LightPoint(c4f, vecorg, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT); + R_CompleteLightPoint(a, c, dir, vecorg, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity); + c4f[0] = p->color[0] * colormultiplier[0] * (a[0] + 0.25f * c[0]); + c4f[1] = p->color[1] * colormultiplier[1] * (a[1] + 0.25f * c[1]); + c4f[2] = p->color[2] * colormultiplier[2] * (a[2] + 0.25f * c[2]); } // mix in the fog color if (r_refdef.fogenabled) @@ -2803,6 +2862,13 @@ static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const t2f[6] = v[1];t2f[7] = tex->t1; break; } + if (r_showparticleedges.integer) + { + R_DebugLine(v3f, v3f + 3); + R_DebugLine(v3f + 3, v3f + 6); + R_DebugLine(v3f + 6, v3f + 9); + R_DebugLine(v3f + 9, v3f); + } } // now render batches of particles based on blendmode and texture @@ -2818,7 +2884,7 @@ static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const if (texture != particletexture[p->texnum].texture) { texture = particletexture[p->texnum].texture; - R_SetupShader_Generic(texture, NULL, GL_MODULATE, 1, false, false, false); + R_SetupShader_Generic(texture, false, false, false); } if (p->blendmode == PBLEND_INVMOD) @@ -2925,7 +2991,7 @@ void R_DrawParticles (void) // if (p->bounce && cl.time >= p->delayedcollisions) if (p->bounce && cl_particles_collisions.integer && VectorLength(p->vel)) { - trace = CL_TraceLine(oldorg, p->org, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, &hitent, false, false); + trace = CL_TraceLine(oldorg, p->org, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), 0, 0, collision_extendmovelength.value, true, false, &hitent, false, false); // if the trace started in or hit something of SUPERCONTENTS_NODROP // or if the trace hit something flagged as NOIMPACT // then remove the particle @@ -3029,7 +3095,7 @@ void R_DrawParticles (void) break; case pt_rain: a = CL_PointSuperContents(p->org); - if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK)) + if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK)) goto killparticle; break; case pt_snow: @@ -3041,7 +3107,7 @@ void R_DrawParticles (void) p->vel[1] = p->vel[0] * 0.9f + lhrandom(-32, 32); } a = CL_PointSuperContents(p->org); - if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK)) + if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK)) goto killparticle; break; default: @@ -3073,7 +3139,7 @@ void R_DrawParticles (void) continue; } // anything else just has to be in front of the viewer and visible at this distance - if (DotProduct(p->org, r_refdef.view.forward) >= minparticledist_start && VectorDistance2(p->org, r_refdef.view.origin) < drawdist2 * (p->size * p->size)) + if (!r_refdef.view.useperspective || (DotProduct(p->org, r_refdef.view.forward) >= minparticledist_start && VectorDistance2(p->org, r_refdef.view.origin) < drawdist2 * (p->size * p->size))) R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL); break; }