From a8ebe2e6a3993a953d3b9114d604c8278c3ceef3 Mon Sep 17 00:00:00 2001 From: havoc Date: Tue, 13 Nov 2007 15:28:54 +0000 Subject: [PATCH] added separate world surfaces and world triangles stats counters for r_speeds display, cleaned up some incorrect stat increments split particle system into particles and decals, this got a nice speed gain due to smaller structs involved increased blood alpha substantially git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@7694 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_main.c | 6 +- cl_particles.c | 594 +++++++++++++++++++++++++++++++++---------------- cl_screen.c | 3 +- client.h | 65 ++++-- gl_rmain.c | 26 +-- render.h | 1 + 6 files changed, 458 insertions(+), 237 deletions(-) diff --git a/cl_main.c b/cl_main.c index 79a6a1f2..04a34aaf 100644 --- a/cl_main.c +++ b/cl_main.c @@ -89,6 +89,7 @@ client_static_t cls; client_state_t cl; #define MAX_PARTICLES 32768 // default max # of particles at one time +#define MAX_DECALS 32768 // default max # of decals at one time #define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter what's on the command line /* @@ -134,6 +135,7 @@ void CL_ClearState(void) cl.max_lightstyle = MAX_LIGHTSTYLES; cl.max_brushmodel_entities = MAX_EDICTS; cl.max_particles = MAX_PARTICLES; + cl.max_decals = MAX_DECALS; cl.max_showlmps = 0; // COMMANDLINEOPTION: Client: -particles changes maximum number of particles at once, default 32768 @@ -159,6 +161,7 @@ void CL_ClearState(void) cl.lightstyle = (lightstyle_t *)Mem_Alloc(cls.levelmempool, cl.max_lightstyle * sizeof(lightstyle_t)); cl.brushmodel_entities = (int *)Mem_Alloc(cls.levelmempool, cl.max_brushmodel_entities * sizeof(int)); cl.particles = (particle_t *) Mem_Alloc(cls.levelmempool, cl.max_particles * sizeof(particle_t)); + cl.decals = (decal_t *) Mem_Alloc(cls.levelmempool, cl.max_decals * sizeof(decal_t)); cl.showlmps = NULL; // LordHavoc: have to set up the baseline info for alpha and other stuff @@ -1794,7 +1797,8 @@ void CL_UpdateWorld(void) CL_RelinkLightFlashes(); CSQC_RelinkAllEntities(ENTMASK_ENGINE | ENTMASK_ENGINEVIEWMODELS); - // move particles + // move decals, particles, and any other effects + CL_MoveDecals(); CL_MoveParticles(); R_MoveExplosions(); } diff --git a/cl_particles.c b/cl_particles.c index 0762614b..18541564 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // must match ptype_t values particletype_t particletype[pt_total] = { + {0, 0, false}, // pt_dead {PBLEND_ALPHA, PARTICLE_BILLBOARD, false}, //pt_alphastatic {PBLEND_ADD, PARTICLE_BILLBOARD, false}, //pt_static {PBLEND_ADD, PARTICLE_SPARK, false}, //pt_spark @@ -174,7 +175,7 @@ cvar_t cl_particles_alpha = {CVAR_SAVE, "cl_particles_alpha", "1", "multiplies o 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"}; -cvar_t cl_particles_blood_alpha = {CVAR_SAVE, "cl_particles_blood_alpha", "0.5", "opacity of blood"}; +cvar_t cl_particles_blood_alpha = {CVAR_SAVE, "cl_particles_blood_alpha", "1", "opacity of blood"}; cvar_t cl_particles_blood_bloodhack = {CVAR_SAVE, "cl_particles_blood_bloodhack", "1", "make certain quake particle() calls create blood effects instead"}; cvar_t cl_particles_bulletimpacts = {CVAR_SAVE, "cl_particles_bulletimpacts", "1", "enables bulletimpact effects"}; cvar_t cl_particles_explosions_smoke = {CVAR_SAVE, "cl_particles_explosions_smokes", "0", "enables smoke from explosions"}; @@ -457,19 +458,21 @@ void CL_Particles_Shutdown (void) // px,py,pz - starting origin of particle // pvx,pvy,pvz - starting velocity of particle // pfriction - how much the particle slows down per second (0-1 typically, can slowdown faster than 1) -static particle_t *particle(particletype_t *ptype, int pcolor1, int pcolor2, int ptex, float psize, float psizeincrease, float palpha, float palphafade, float pgravity, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz, float pairfriction, float pliquidfriction, float originjitter, float velocityjitter) +static particle_t *CL_NewParticle(unsigned short ptypeindex, int pcolor1, int pcolor2, int ptex, float psize, float psizeincrease, float palpha, float palphafade, float pgravity, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz, float pairfriction, float pliquidfriction, float originjitter, float velocityjitter) { int l1, l2; particle_t *part; vec3_t v; - for (;cl.free_particle < cl.max_particles && cl.particles[cl.free_particle].type;cl.free_particle++); + if (!cl_particles.integer) + return NULL; + for (;cl.free_particle < cl.max_particles && cl.particles[cl.free_particle].typeindex;cl.free_particle++); if (cl.free_particle >= cl.max_particles) return NULL; part = &cl.particles[cl.free_particle++]; if (cl.num_particles < cl.free_particle) cl.num_particles = cl.free_particle; memset(part, 0, sizeof(*part)); - part->type = ptype; + part->typeindex = ptypeindex; l2 = (int)lhrandom(0.5, 256.5); l1 = 256 - l2; part->color[0] = ((((pcolor1 >> 16) & 0xFF) * l1 + ((pcolor2 >> 16) & 0xFF) * l2) >> 8) & 0xFF; @@ -495,10 +498,10 @@ static particle_t *particle(particletype_t *ptype, int pcolor1, int pcolor2, int part->liquidfriction = pliquidfriction; part->die = cl.time + part->alpha / (part->alphafade ? part->alphafade : 1); part->delayedcollisions = 0; - if (part->type == particletype + pt_blood) + if (part->typeindex == pt_blood) part->gravity += 1; // FIXME: this is a legacy hack, effectinfo.txt doesn't have gravity on blood (nor do the particle calls in the engine) // 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) + if (part->typeindex == pt_rain) { int i; particle_t *part2; @@ -506,19 +509,19 @@ static particle_t *particle(particletype_t *ptype, int pcolor1, int pcolor2, int vec3_t endvec; trace_t trace; // turn raindrop into simple spark and create delayedspawn splash effect - part->type = particletype + pt_spark; + part->typeindex = 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); + trace = CL_Move(part->org, vec3_origin, vec3_origin, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK, 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); + part2 = CL_NewParticle(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); + part2 = CL_NewParticle(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; @@ -527,13 +530,13 @@ static particle_t *particle(particletype_t *ptype, int pcolor1, int pcolor2, int } } } - else if (part->bounce != 0 && part->gravity == 0) + else if (part->bounce != 0 && part->gravity == 0 && part->typeindex != pt_snow) { 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); + trace = CL_Move(part->org, vec3_origin, vec3_origin, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, true, false, NULL, false); part->delayedcollisions = cl.time + lifetime * trace.fraction - 0.1; } return part; @@ -541,20 +544,37 @@ static particle_t *particle(particletype_t *ptype, int pcolor1, int pcolor2, int void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t normal, int color1, int color2, int texnum, float size, float alpha) { - particle_t *p; + int l1, l2; + decal_t *decal; if (!cl_decals.integer) return; - p = particle(particletype + pt_decal, color1, color2, texnum, size, 0, alpha, 0, 0, 0, org[0] + normal[0], org[1] + normal[1], org[2] + normal[2], normal[0], normal[1], normal[2], 0, 0, 0, 0); - if (p) + for (;cl.free_decal < cl.max_decals && cl.decals[cl.free_decal].typeindex;cl.free_decal++); + if (cl.free_decal >= cl.max_decals) + return; + decal = &cl.decals[cl.free_decal++]; + if (cl.num_decals < cl.free_decal) + cl.num_decals = cl.free_decal; + memset(decal, 0, sizeof(*decal)); + decal->typeindex = pt_decal; + decal->texnum = texnum; + VectorAdd(org, normal, decal->org); + VectorCopy(normal, decal->normal); + decal->size = size; + decal->alpha = alpha; + decal->time2 = cl.time; + l2 = (int)lhrandom(0.5, 256.5); + l1 = 256 - l2; + decal->color[0] = ((((color1 >> 16) & 0xFF) * l1 + ((color2 >> 16) & 0xFF) * l2) >> 8) & 0xFF; + decal->color[1] = ((((color1 >> 8) & 0xFF) * l1 + ((color2 >> 8) & 0xFF) * l2) >> 8) & 0xFF; + decal->color[2] = ((((color1 >> 0) & 0xFF) * l1 + ((color2 >> 0) & 0xFF) * l2) >> 8) & 0xFF; + decal->color[3] = 0xFF; + decal->owner = hitent; + if (hitent) { - p->time2 = cl.time; - p->owner = hitent; - p->ownermodel = cl.entities[p->owner].render.model; - VectorAdd(org, normal, p->org); - VectorCopy(normal, p->vel); - // these relative things are only used to regenerate p->org and p->vel if p->owner is not world (0) - Matrix4x4_Transform(&cl.entities[p->owner].render.inversematrix, org, p->relativeorigin); - Matrix4x4_Transform3x3(&cl.entities[p->owner].render.inversematrix, normal, p->relativedirection); + // these relative things are only used to regenerate p->org and p->vel if decal->owner is not world (0) + decal->ownermodel = cl.entities[decal->owner].render.model; + Matrix4x4_Transform(&cl.entities[decal->owner].render.inversematrix, org, decal->relativeorigin); + Matrix4x4_Transform3x3(&cl.entities[decal->owner].render.inversematrix, normal, decal->relativenormal); } } @@ -609,11 +629,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.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); + CL_NewParticle(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); + CL_NewParticle(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.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); + CL_NewParticle(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); } } } @@ -711,7 +731,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o static double bloodaccumulator = 0; bloodaccumulator += count * 0.333 * cl_particles_quality.value; for (;bloodaccumulator > 0;bloodaccumulator--) - particle(particletype + pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, 0, cl_particles_blood_alpha.value * 768, cl_particles_blood_alpha.value * 384, 0, -1, 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, 0, 64); + CL_NewParticle(pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, 0, cl_particles_blood_alpha.value * 768, cl_particles_blood_alpha.value * 384, 0, -1, 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, 0, 64); } } else if (effectnameindex == EFFECT_TE_SPARK) @@ -774,9 +794,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.5f, 0, lhrandom(182, 255), 182, 0, 0, center[0], center[1], center[2], 0, 0, 0, -4, -4, 16, 256); + CL_NewParticle(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.5f, 0, lhrandom(182, 255), 182, 0, 0, center[0], center[1], center[2], 0, 0, lhrandom(-256, 256), 0, 0, 16, 0); + CL_NewParticle(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 @@ -789,7 +809,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o { count *= cl_particles_quality.value; while (count-- > 0) - particle(particletype + pt_smoke, 0x6f0f00, 0xe3974f, tex_particle, 4, 0, lhrandom(64, 128), 384, -1, 1.1, 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, 0, 128); + CL_NewParticle(pt_smoke, 0x6f0f00, 0xe3974f, tex_particle, 4, 0, lhrandom(64, 128), 384, -1, 1.1, 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, 0, 128); } else if (effectnameindex == EFFECT_TE_LAVASPLASH) { @@ -808,7 +828,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.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); + CL_NewParticle(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); } } } @@ -827,22 +847,22 @@ 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.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); + CL_NewParticle(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); } } } - particle(particletype + pt_static, particlepalette[14], particlepalette[14], tex_particle, 30, 0, 256, 512, 0, 0, center[0], center[1], center[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(pt_static, particlepalette[14], particlepalette[14], tex_particle, 30, 0, 256, 512, 0, 0, center[0], center[1], center[2], 0, 0, 0, 0, 0, 0, 0); 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); } else if (effectnameindex == EFFECT_TE_TEI_G3) - particle(particletype + 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); + CL_NewParticle(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); else if (effectnameindex == EFFECT_TE_TEI_SMOKE) { if (cl_particles_smoke.integer) { count *= 0.25f * cl_particles_quality.value; while (count-- > 0) - particle(particletype + pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 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, 1.5f, 6.0f); + CL_NewParticle(pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 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, 1.5f, 6.0f); } } else if (effectnameindex == EFFECT_TE_TEI_BIGEXPLOSION) @@ -858,24 +878,24 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o CL_SpawnDecalParticleForPoint(center, 6, 8, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); if (cl_particles_smoke.integer) for (f = 0;f < count;f += 4.0f / cl_particles_quality.value) - particle(particletype + pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 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, 20, 155); + CL_NewParticle(pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 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, 20, 155); if (cl_particles_sparks.integer) for (f = 0;f < count;f += 1.0f / cl_particles_quality.value) - particle(particletype + 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); + CL_NewParticle(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); 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); } else if (effectnameindex == EFFECT_EF_FLAME) { count *= 300 * cl_particles_quality.value; while (count-- > 0) - particle(particletype + 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); + CL_NewParticle(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); 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); } else if (effectnameindex == EFFECT_EF_STARDUST) { count *= 200 * cl_particles_quality.value; while (count-- > 0) - particle(particletype + 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); + CL_NewParticle(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); 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); } else if (!strncmp(particleeffectname[effectnameindex], "TR_", 3)) @@ -949,12 +969,12 @@ 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.5f, 0, 255, 128, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); + CL_NewParticle(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 { dec = 16; - particle(particletype + pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, 0, qd * cl_particles_blood_alpha.value * 768.0f, qd * cl_particles_blood_alpha.value * 384.0f, 0, -1, pos[0], pos[1], pos[2], lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 0, 64); + CL_NewParticle(pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, 0, qd * cl_particles_blood_alpha.value * 768.0f, qd * cl_particles_blood_alpha.value * 384.0f, 0, -1, pos[0], pos[1], pos[2], lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 0, 64); } } else if (effectnameindex == EFFECT_TR_SLIGHTBLOOD) @@ -963,12 +983,12 @@ 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.5f, 0, 255, 128, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); + CL_NewParticle(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 { dec = 32; - particle(particletype + pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, 0, qd * cl_particles_blood_alpha.value * 768.0f, qd * cl_particles_blood_alpha.value * 384.0f, 0, -1, pos[0], pos[1], pos[2], lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 0, 64); + CL_NewParticle(pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, 0, qd * cl_particles_blood_alpha.value * 768.0f, qd * cl_particles_blood_alpha.value * 384.0f, 0, -1, pos[0], pos[1], pos[2], lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 0, 64); } } } @@ -980,12 +1000,12 @@ 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.5f, 0, 42*(6-r), 306, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); + CL_NewParticle(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*62, cl_particles_smoke_alphafade.value*62, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); - particle(particletype + pt_static, 0x801010, 0xFFA020, tex_smoke[rand()&7], 3, 0, cl_particles_smoke_alpha.value*288, cl_particles_smoke_alphafade.value*1400, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 20); + CL_NewParticle(pt_smoke, 0x303030, 0x606060, tex_smoke[rand()&7], 3, 0, cl_particles_smoke_alpha.value*62, cl_particles_smoke_alphafade.value*62, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(pt_static, 0x801010, 0xFFA020, tex_smoke[rand()&7], 3, 0, cl_particles_smoke_alpha.value*288, cl_particles_smoke_alphafade.value*1400, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 20); } } else if (effectnameindex == EFFECT_TR_GRENADE) @@ -994,11 +1014,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.5f, 0, 42*(6-r), 306, 0, -0.05, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0); + CL_NewParticle(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*75, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(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) @@ -1007,18 +1027,18 @@ 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.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); + CL_NewParticle(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); + CL_NewParticle(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) { dec = 6; - particle(particletype + pt_static, 0x00002E, 0x000030, tex_particle, 6, 0, 128, 384, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(pt_static, 0x00002E, 0x000030, tex_particle, 6, 0, 128, 384, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); } else { color = particlepalette[20 + (rand()&7)]; - particle(particletype + pt_static, color, color, tex_particle, 2, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(pt_static, color, color, tex_particle, 2, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); } } else if (effectnameindex == EFFECT_TR_KNIGHTSPIKE) @@ -1027,13 +1047,13 @@ 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.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); + CL_NewParticle(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); + CL_NewParticle(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 { color = particlepalette[226 + (rand()&7)]; - particle(particletype + pt_static, color, color, tex_particle, 2, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(pt_static, color, color, tex_particle, 2, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); } } else if (effectnameindex == EFFECT_TR_VORESPIKE) @@ -1041,40 +1061,40 @@ 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.5f, 0, 255, 850, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 8, 0); + CL_NewParticle(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) { dec = 6; - particle(particletype + pt_alphastatic, particlepalette[0 + (rand()&255)], particlepalette[0 + (rand()&255)], tex_particle, 6, 0, 255, 384, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(pt_alphastatic, particlepalette[0 + (rand()&255)], particlepalette[0 + (rand()&255)], tex_particle, 6, 0, 255, 384, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); } else if (gamemode == GAME_PRYDON) { dec = 6; - particle(particletype + pt_static, 0x103040, 0x204050, tex_particle, 6, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(pt_static, 0x103040, 0x204050, tex_particle, 6, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); } else - particle(particletype + pt_static, 0x502030, 0x502030, tex_particle, 3, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(pt_static, 0x502030, 0x502030, tex_particle, 3, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); } else if (effectnameindex == EFFECT_TR_NEHAHRASMOKE) { dec = 7; - particle(particletype + pt_alphastatic, 0x303030, 0x606060, tex_smoke[rand()&7], 7, 0, 64, 320, 0, 0, pos[0], pos[1], pos[2], 0, 0, lhrandom(4, 12), 0, 0, 0, 4); + CL_NewParticle(pt_alphastatic, 0x303030, 0x606060, tex_smoke[rand()&7], 7, 0, 64, 320, 0, 0, pos[0], pos[1], pos[2], 0, 0, lhrandom(4, 12), 0, 0, 0, 4); } else if (effectnameindex == EFFECT_TR_NEXUIZPLASMA) { dec = 4; - particle(particletype + pt_static, 0x283880, 0x283880, tex_particle, 4, 0, 255, 1024, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 16); + CL_NewParticle(pt_static, 0x283880, 0x283880, tex_particle, 4, 0, 255, 1024, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 16); } else if (effectnameindex == EFFECT_TR_GLOWTRAIL) - particle(particletype + pt_alphastatic, particlepalette[palettecolor], particlepalette[palettecolor], tex_particle, 5, 0, 128, 320, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(pt_alphastatic, particlepalette[palettecolor], particlepalette[palettecolor], tex_particle, 5, 0, 128, 320, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0); } if (bubbles) { if (effectnameindex == EFFECT_TR_ROCKET) - particle(particletype + pt_bubble, 0x404040, 0x808080, tex_bubble, 2, 0, lhrandom(64, 255), 256, -0.25, 1.5, pos[0], pos[1], pos[2], 0, 0, 0, 0.0625, 0.25, 0, 16); + CL_NewParticle(pt_bubble, 0x404040, 0x808080, tex_bubble, 2, 0, lhrandom(64, 255), 256, -0.25, 1.5, pos[0], pos[1], pos[2], 0, 0, 0, 0.0625, 0.25, 0, 16); else if (effectnameindex == EFFECT_TR_GRENADE) - particle(particletype + pt_bubble, 0x404040, 0x808080, tex_bubble, 2, 0, lhrandom(64, 255), 256, -0.25, 1.5, pos[0], pos[1], pos[2], 0, 0, 0, 0.0625, 0.25, 0, 16); + CL_NewParticle(pt_bubble, 0x404040, 0x808080, tex_bubble, 2, 0, lhrandom(64, 255), 256, -0.25, 1.5, pos[0], pos[1], pos[2], 0, 0, 0, 0.0625, 0.25, 0, 16); } // advance to next time and position dec *= qd; @@ -1169,7 +1189,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins if (info->particletype == pt_decal) CL_SpawnDecalParticleForPoint(center, info->originjitter[0], lhrandom(info->size[0], info->size[1]), lhrandom(info->alpha[0], info->alpha[1]), tex, info->color[0], info->color[1]); else if (info->particletype == pt_beam) - particle(particletype + info->particletype, info->color[0], info->color[1], tex, lhrandom(info->size[0], info->size[1]), info->size[2], lhrandom(info->alpha[0], info->alpha[1]), info->alpha[2], 0, 0, originmins[0], originmins[1], originmins[2], originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, 0); + CL_NewParticle(info->particletype, info->color[0], info->color[1], tex, lhrandom(info->size[0], info->size[1]), info->size[2], lhrandom(info->alpha[0], info->alpha[1]), info->alpha[2], 0, 0, originmins[0], originmins[1], originmins[2], originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, 0); else { if (!cl_particles.integer) @@ -1210,7 +1230,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins trailpos[2] = lhrandom(originmins[2], originmaxs[2]); } VectorRandom(rvec); - particle(particletype + info->particletype, info->color[0], info->color[1], tex, lhrandom(info->size[0], info->size[1]), info->size[2], lhrandom(info->alpha[0], info->alpha[1]), info->alpha[2], info->gravity, info->bounce, trailpos[0] + info->originoffset[0] + info->originjitter[0] * rvec[0], trailpos[1] + info->originoffset[1] + info->originjitter[1] * rvec[1], trailpos[2] + info->originoffset[2] + info->originjitter[2] * rvec[2], lhrandom(velocitymins[0], velocitymaxs[0]) * info->velocitymultiplier + info->velocityoffset[0] + info->velocityjitter[0] * rvec[0], lhrandom(velocitymins[1], velocitymaxs[1]) * info->velocitymultiplier + info->velocityoffset[1] + info->velocityjitter[1] * rvec[1], lhrandom(velocitymins[2], velocitymaxs[2]) * info->velocitymultiplier + info->velocityoffset[2] + info->velocityjitter[2] * rvec[2], info->airfriction, info->liquidfriction, 0, 0); + CL_NewParticle(info->particletype, info->color[0], info->color[1], tex, lhrandom(info->size[0], info->size[1]), info->size[2], lhrandom(info->alpha[0], info->alpha[1]), info->alpha[2], info->gravity, info->bounce, trailpos[0] + info->originoffset[0] + info->originjitter[0] * rvec[0], trailpos[1] + info->originoffset[1] + info->originjitter[1] * rvec[1], trailpos[2] + info->originoffset[2] + info->originjitter[2] * rvec[2], lhrandom(velocitymins[0], velocitymaxs[0]) * info->velocitymultiplier + info->velocityoffset[0] + info->velocityjitter[0] * rvec[0], lhrandom(velocitymins[1], velocitymaxs[1]) * info->velocitymultiplier + info->velocityoffset[1] + info->velocityjitter[1] * rvec[1], lhrandom(velocitymins[2], velocitymaxs[2]) * info->velocitymultiplier + info->velocityoffset[2] + info->velocityjitter[2] * rvec[2], info->airfriction, info->liquidfriction, 0, 0); if (trailstep) VectorMA(trailpos, trailstep, traildir, trailpos); } @@ -1252,7 +1272,7 @@ void CL_EntityParticles (const entity_t *ent) v[0] = org[0] + m_bytenormals[i][0] * dist + (cos(pitch)*cos(yaw)) * beamlength; v[1] = org[1] + m_bytenormals[i][1] * dist + (cos(pitch)*sin(yaw)) * beamlength; v[2] = org[2] + m_bytenormals[i][2] * dist + (-sin(pitch)) * beamlength; - particle(particletype + pt_entityparticle, particlepalette[0x6f], particlepalette[0x6f], tex_particle, 1, 0, 255, 0, 0, 0, v[0], v[1], v[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(pt_entityparticle, particlepalette[0x6f], particlepalette[0x6f], tex_particle, 1, 0, 255, 0, 0, 0, v[0], v[1], v[2], 0, 0, 0, 0, 0, 0, 0); } } @@ -1304,16 +1324,16 @@ void CL_ReadPointFile_f (void) if (cl.num_particles < cl.max_particles - 3) { s++; - particle(particletype + pt_static, particlepalette[(-c)&15], particlepalette[(-c)&15], tex_particle, 2, 0, 255, 0, 0, 0, org[0], org[1], org[2], 0, 0, 0, 0, 0, 0, 0); + CL_NewParticle(pt_static, particlepalette[(-c)&15], particlepalette[(-c)&15], tex_particle, 2, 0, 255, 0, 0, 0, org[0], org[1], org[2], 0, 0, 0, 0, 0, 0, 0); } } Mem_Free(pointfile); VectorCopy(leakorg, org); Con_Printf("%i points read (%i particles spawned)\nLeak at %f %f %f\n", c, s, org[0], org[1], org[2]); - particle(particletype + 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); - particle(particletype + 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); - particle(particletype + 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); + CL_NewParticle(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); + CL_NewParticle(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); + CL_NewParticle(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); } /* @@ -1367,12 +1387,12 @@ void CL_ParticleExplosion (const vec3_t org) if (i & 1) { color = particlepalette[ramp1[r]]; - 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); + CL_NewParticle(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.5f, 0, 32 * (8 - r), 478, 0, 0, org[0], org[1], org[2], 0, 0, 0, 1, 1, 16, 256); + CL_NewParticle(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); } } } @@ -1383,7 +1403,7 @@ void CL_ParticleExplosion (const vec3_t org) { if (cl_particles.integer && cl_particles_bubbles.integer) for (i = 0;i < 128 * cl_particles_quality.value;i++) - particle(particletype + pt_bubble, 0x404040, 0x808080, tex_bubble, 2, 0, lhrandom(128, 255), 128, -0.125, 1.5, org[0], org[1], org[2], 0, 0, 0, 0.0625, 0.25, 16, 96); + CL_NewParticle(pt_bubble, 0x404040, 0x808080, tex_bubble, 2, 0, lhrandom(128, 255), 128, -0.125, 1.5, org[0], org[1], org[2], 0, 0, 0, 0.0625, 0.25, 16, 96); } else { @@ -1406,7 +1426,7 @@ void CL_ParticleExplosion (const vec3_t org) } VectorSubtract(trace.endpos, org, v2); VectorScale(v2, 2.0f, v2); - particle(particletype + pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 12, 0, 32, 64, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0, 0, 0, 0); + CL_NewParticle(pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 12, 0, 32, 64, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0, 0, 0, 0); } } @@ -1426,7 +1446,7 @@ void CL_ParticleExplosion (const vec3_t org) } 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); + CL_NewParticle(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); } } } @@ -1451,9 +1471,9 @@ void CL_ParticleExplosion2 (const vec3_t org, int colorStart, int colorLength) { k = particlepalette[colorStart + (i % colorLength)]; if (cl_particles_quake.integer) - particle(particletype + pt_static, k, k, tex_particle, 1, 0, 255, 850, 0, 0, org[0], org[1], org[2], 0, 0, 0, -4, -4, 8, 256); + CL_NewParticle(pt_static, k, k, tex_particle, 1, 0, 255, 850, 0, 0, org[0], org[1], org[2], 0, 0, 0, -4, -4, 8, 256); else - particle(particletype + pt_static, k, k, tex_particle, lhrandom(0.5, 1.5), 0, 255, 512, 0, 0, org[0], org[1], org[2], 0, 0, 0, lhrandom(1.5, 3), lhrandom(1.5, 3), 8, 192); + CL_NewParticle(pt_static, k, k, tex_particle, lhrandom(0.5, 1.5), 0, 255, 512, 0, 0, org[0], org[1], org[2], 0, 0, 0, lhrandom(1.5, 3), lhrandom(1.5, 3), 8, 192); } } @@ -1463,7 +1483,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]) + cl.movevars_gravity * 0.1f, 0, 0, 0, 64); + CL_NewParticle(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); } } @@ -1473,7 +1493,7 @@ static void CL_Smoke(const vec3_t originmins, const vec3_t originmaxs, const vec { smokecount *= cl_particles_quality.value; while(smokecount-- > 0) - 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); + CL_NewParticle(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); } } @@ -1486,7 +1506,7 @@ void CL_ParticleCube (const vec3_t mins, const vec3_t maxs, const vec3_t dir, in while (count--) { k = particlepalette[colorbase + (rand()&3)]; - particle(particletype + pt_alphastatic, k, k, tex_particle, 2, 0, 255, 128, gravity, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), dir[0], dir[1], dir[2], 0, 0, 0, randomvel); + CL_NewParticle(pt_alphastatic, k, k, tex_particle, 2, 0, 255, 128, gravity, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), dir[0], dir[1], dir[2], 0, 0, 0, randomvel); } } @@ -1494,7 +1514,6 @@ void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, in { int k; float z, minz, maxz; - particle_t *p; if (!cl_particles.integer) return; if (dir[2] < 0) // falling z = maxs[2]; @@ -1518,9 +1537,9 @@ void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, in { k = particlepalette[colorbase + (rand()&3)]; if (gamemode == GAME_GOODVSBAD2) - particle(particletype + pt_rain, k, k, tex_particle, 20, 0, lhrandom(8, 16), 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0, 0, 0, 0); + CL_NewParticle(pt_rain, k, k, tex_particle, 20, 0, lhrandom(8, 16), 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0, 0, 0, 0); else - particle(particletype + pt_rain, k, k, tex_particle, 0.5, 0, lhrandom(8, 16), 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0, 0, 0, 0); + CL_NewParticle(pt_rain, k, k, tex_particle, 0.5, 0, lhrandom(8, 16), 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0, 0, 0, 0); } break; case 1: @@ -1529,11 +1548,9 @@ void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, in { k = particlepalette[colorbase + (rand()&3)]; if (gamemode == GAME_GOODVSBAD2) - p = particle(particletype + pt_snow, k, k, tex_particle, 20, 0, lhrandom(64, 128), 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0, 0, 0, 0); + CL_NewParticle(pt_snow, k, k, tex_particle, 20, 0, lhrandom(64, 128), 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0, 0, 0, 0); else - p = particle(particletype + pt_snow, k, k, tex_particle, 1, 0, lhrandom(64, 128), 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0, 0, 0, 0); - if (p) - VectorCopy(p->vel, p->relativedirection); + CL_NewParticle(pt_snow, k, k, tex_particle, 1, 0, lhrandom(64, 128), 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0, 0, 0, 0); } break; default: @@ -1541,6 +1558,66 @@ void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, in } } +/* +=============== +CL_MoveDecals +=============== +*/ +void CL_MoveDecals (void) +{ + decal_t *decal; + int i; + float decalfade; + + // LordHavoc: early out condition + if (!cl.num_decals) + { + cl.free_decal = 0; + return; + } + + decalfade = bound(0, cl.time - cl.oldtime, 0.1) * 255 / cl_decals_fadetime.value; + + for (i = 0, decal = cl.decals;i < cl.num_decals;i++, decal++) + { + if (!decal->typeindex) + continue; + + // heavily optimized decal case + // FIXME: this has fairly wacky handling of alpha + if (cl.time > decal->time2 + cl_decals_time.value) + { + decal->alpha -= decalfade; + if (decal->alpha <= 0) + { + decal->typeindex = 0; + if (cl.free_decal > i) + cl.free_decal = i; + continue; + } + } + + if (decal->owner) + { + if (cl.entities[decal->owner].render.model == decal->ownermodel) + { + Matrix4x4_Transform(&cl.entities[decal->owner].render.matrix, decal->relativeorigin, decal->org); + Matrix4x4_Transform3x3(&cl.entities[decal->owner].render.matrix, decal->relativenormal, decal->normal); + } + else + { + decal->typeindex = 0; + if (cl.free_decal > i) + cl.free_decal = i; + } + } + } + + // reduce cl.num_decals if possible + while (cl.num_decals > 0 && cl.decals[cl.num_decals - 1].typeindex == 0) + cl.num_decals--; +} + /* =============== CL_MoveParticles @@ -1549,9 +1626,8 @@ CL_MoveParticles void CL_MoveParticles (void) { particle_t *p; - int i, maxparticle, j, a, content; + int i, j, a, content; float gravity, dvel, decalfade, frametime, f, dist, oldorg[3]; - particletype_t *decaltype, *bloodtype; int hitent; trace_t trace; @@ -1566,52 +1642,16 @@ void CL_MoveParticles (void) gravity = frametime * cl.movevars_gravity; dvel = 1+4*frametime; decalfade = frametime * 255 / cl_decals_fadetime.value; - decaltype = particletype + pt_decal; - bloodtype = particletype + pt_blood; - maxparticle = -1; j = 0; for (i = 0, p = cl.particles;i < cl.num_particles;i++, p++) { - if (!p->type) + if (!p->typeindex) { if (cl.free_particle > i) cl.free_particle = i; continue; } - maxparticle = i; - - // heavily optimized decal case - if (p->type == decaltype) - { - // FIXME: this has fairly wacky handling of alpha - if (cl.time > p->time2 + cl_decals_time.value) - { - p->alpha -= decalfade; - if (p->alpha <= 0) - { - p->type = NULL; - if (cl.free_particle > i) - cl.free_particle = i; - continue; - } - } - if (p->owner) - { - if (cl.entities[p->owner].render.model == p->ownermodel) - { - Matrix4x4_Transform(&cl.entities[p->owner].render.matrix, p->relativeorigin, p->org); - Matrix4x4_Transform3x3(&cl.entities[p->owner].render.matrix, p->relativedirection, p->vel); - } - else - { - p->type = NULL; - if (cl.free_particle > i) - cl.free_particle = i; - } - } - continue; - } if (p->delayedspawn) { @@ -1627,17 +1667,17 @@ void CL_MoveParticles (void) if (p->alpha <= 0 || p->die <= cl.time) { - p->type = NULL; + p->typeindex = 0; if (cl.free_particle > i) cl.free_particle = i; continue; } - if (p->type->orientation != PARTICLE_BEAM && frametime > 0) + if (particletype[p->typeindex].orientation != PARTICLE_BEAM && frametime > 0) { if (p->liquidfriction && (CL_PointSuperContents(p->org) & SUPERCONTENTS_LIQUIDSMASK)) { - if (p->type == bloodtype) + if (p->typeindex == pt_blood) p->size += frametime * 8; else p->vel[2] -= p->gravity * gravity; @@ -1658,13 +1698,15 @@ void CL_MoveParticles (void) VectorMA(p->org, frametime, p->vel, p->org); 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); + trace = CL_Move(oldorg, vec3_origin, vec3_origin, p->org, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, &hitent, 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 if (trace.hitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT || ((trace.startsupercontents | trace.hitsupercontents) & SUPERCONTENTS_NODROP) || (trace.startsupercontents & SUPERCONTENTS_SOLID)) { - p->type = NULL; + p->typeindex = 0; + if (cl.free_particle > i) + cl.free_particle = i; continue; } VectorCopy(trace.endpos, p->org); @@ -1672,14 +1714,14 @@ void CL_MoveParticles (void) if (trace.fraction < 1) { VectorCopy(trace.endpos, p->org); - if (p->type == particletype + pt_rain) + if (p->typeindex == pt_rain) { // raindrop - splash on solid/water/slime/lava int count; // convert from a raindrop particle to a rainsplash decal VectorCopy(trace.plane.normal, p->vel); VectorAdd(p->org, p->vel, p->org); - p->type = particletype + pt_raindecal; + p->typeindex = pt_raindecal; p->texnum = tex_rainsplash; p->time2 = cl.time; p->alphafade = p->alpha / 0.4; @@ -1691,48 +1733,37 @@ void CL_MoveParticles (void) 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, cl.movevars_gravity * 0.04 + p->vel[2]*16, 0, 0, 0, 32); + CL_NewParticle(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); continue; } - else if (p->type == bloodtype) + else if (p->typeindex == pt_blood) { // blood - splash on solid if (trace.hitq3surfaceflags & Q3SURFACEFLAG_NOMARKS) { - p->type = NULL; + p->typeindex = 0; 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; + p->typeindex = 0; continue; } - // convert from a blood particle to a blood decal - VectorCopy(trace.plane.normal, p->vel); - VectorAdd(p->org, p->vel, p->org); - - p->type = particletype + pt_decal; - p->texnum = tex_blooddecal[rand()&7]; - p->owner = hitent; - p->ownermodel = cl.entities[hitent].render.model; - // these relative things are only used to regenerate p->org and p->vel if p->owner is not world (0) - Matrix4x4_Transform(&cl.entities[hitent].render.inversematrix, p->org, p->relativeorigin); - Matrix4x4_Transform3x3(&cl.entities[hitent].render.inversematrix, p->vel, p->relativedirection); - p->time2 = cl.time; - p->alphafade = 0; - p->bounce = 0; - p->airfriction = 0; - p->liquidfriction = 0; - p->gravity = 0; - p->size *= 2.0f; + // create a decal for the blood splat + CL_SpawnDecalParticleForSurface(hitent, p->org, trace.plane.normal, p->color[0] * 65536 + p->color[1] * 256 + p->color[2], p->color[0] * 65536 + p->color[1] * 256 + p->color[2], tex_blooddecal[rand()&7], p->size * 2, p->alpha); + p->typeindex = 0; + if (cl.free_particle > i) + cl.free_particle = i; continue; } else if (p->bounce < 0) { // bounce -1 means remove on impact - p->type = NULL; + p->typeindex = 0; + if (cl.free_particle > i) + cl.free_particle = i; continue; } else @@ -1747,51 +1778,73 @@ void CL_MoveParticles (void) } } - if (p->type != particletype + pt_static) + if (p->typeindex != pt_static) { - switch (p->type - particletype) + switch (p->typeindex) { case pt_entityparticle: // particle that removes itself after one rendered frame if (p->time2) - p->type = NULL; + { + p->typeindex = 0; + if (cl.free_particle > i) + cl.free_particle = i; + } else p->time2 = 1; break; case pt_blood: a = CL_PointSuperContents(p->org); if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP)) - p->type = NULL; + { + p->typeindex = 0; + if (cl.free_particle > i) + cl.free_particle = i; + } break; case pt_bubble: a = CL_PointSuperContents(p->org); if (!(a & (SUPERCONTENTS_WATER | SUPERCONTENTS_SLIME))) - p->type = NULL; + { + p->typeindex = 0; + if (cl.free_particle > i) + cl.free_particle = i; + } break; case pt_rain: a = CL_PointSuperContents(p->org); if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK)) - p->type = NULL; + { + p->typeindex = 0; + if (cl.free_particle > i) + cl.free_particle = i; + } break; case pt_snow: if (cl.time > p->time2) { // snow flutter p->time2 = cl.time + (rand() & 3) * 0.1; - p->vel[0] = p->relativedirection[0] + lhrandom(-32, 32); - p->vel[1] = p->relativedirection[1] + lhrandom(-32, 32); - //p->vel[2] = p->relativedirection[2] + lhrandom(-32, 32); + p->vel[0] = p->vel[0] * 0.9f + lhrandom(-32, 32); + p->vel[1] = p->vel[0] * 0.9f + lhrandom(-32, 32); } a = CL_PointSuperContents(p->org); if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK)) - p->type = NULL; + { + p->typeindex = 0; + if (cl.free_particle > i) + cl.free_particle = i; + } break; default: break; } } } - cl.num_particles = maxparticle + 1; + + // reduce cl.num_particles if possible + while (cl.num_particles > 0 && cl.particles[cl.num_particles - 1].typeindex == 0) + cl.num_particles--; } #define MAX_PARTICLETEXTURES 64 @@ -1808,6 +1861,7 @@ static rtexture_t *particlefonttexture; static particletexture_t particletexture[MAX_PARTICLETEXTURES]; static cvar_t r_drawparticles = {0, "r_drawparticles", "1", "enables drawing of particles"}; +static cvar_t r_drawdecals = {0, "r_drawdecals", "1", "enables drawing of decals"}; #define PARTICLETEXTURESIZE 64 #define PARTICLEFONTSIZE (PARTICLETEXTURESIZE*8) @@ -1872,6 +1926,8 @@ void particletextureblotch(unsigned char *data, float radius, float red, float g f = (1.0f - sqrt(dx * dx + dy * dy) * iradius) * alpha; if (f > 0) { + if (f > 1) + f = 1; d = data + (y * PARTICLETEXTURESIZE + x) * 4; d[0] += (int)(f * (red - d[0])); d[1] += (int)(f * (green - d[1])); @@ -1927,7 +1983,7 @@ static void R_InitBloodTextures (unsigned char *particletexturedata) m = 8; for (j = 1;j < 10;j++) for (k = min(j, m - 1);k < m;k++) - particletextureblotch(&data[0][0][0], (float)j*PARTICLETEXTURESIZE/64.0f, 96, 0, 0, 192 - j * 8); + particletextureblotch(&data[0][0][0], (float)j*PARTICLETEXTURESIZE/64.0f, 96, 0, 0, 320 - j * 8); //particletextureclamp(&data[0][0][0], 32, 32, 32, 255, 255, 255); particletextureinvert(&data[0][0][0]); setuptex(tex_blooddecal[i], &data[0][0][0], particletexturedata); @@ -2162,9 +2218,145 @@ void R_Particles_Init (void) } Cvar_RegisterVariable(&r_drawparticles); + Cvar_RegisterVariable(&r_drawdecals); R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap); } +void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + int surfacelistindex; + int batchstart, batchcount; + const decal_t *d; + pblend_t blendmode; + rtexture_t *texture; + float *v3f, *t2f, *c4f; + + r_refdef.stats.decals += numsurfaces; + R_Mesh_Matrix(&identitymatrix); + R_Mesh_ResetTextureState(); + 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_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 right[3], up[3], fog, cr, cg, cb, ca, size; + + d = cl.decals + surfacelist[surfacelistindex]; + + //blendmode = particletype[d->typeindex].blendmode; + + cr = d->color[0] * (1.0f / 255.0f) * r_view.colorscale; + cg = d->color[1] * (1.0f / 255.0f) * r_view.colorscale; + cb = d->color[2] * (1.0f / 255.0f) * r_view.colorscale; + ca = d->alpha * (1.0f / 255.0f); + //if (blendmode == PBLEND_MOD) + { + cr *= ca; + cg *= ca; + cb *= ca; + cr = min(cr, 1); + cg = min(cg, 1); + cb = min(cb, 1); + ca = 1; + } + ca *= cl_particles_alpha.value; + if (r_refdef.fogenabled) + { + fog = FogPoint_World(d->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; + //} + } + c4f[0] = c4f[4] = c4f[8] = c4f[12] = cr; + c4f[1] = c4f[5] = c4f[9] = c4f[13] = cg; + c4f[2] = c4f[6] = c4f[10] = c4f[14] = cb; + c4f[3] = c4f[7] = c4f[11] = c4f[15] = ca; + + size = d->size * cl_particles_size.value; + org = d->org; + tex = &particletexture[d->texnum]; + + // PARTICLE_ORIENTED_DOUBLESIDED + VectorVectors(d->normal, right, up); + VectorScale(right, size, right); + VectorScale(up, size, up); + v3f[ 0] = org[0] - right[0] - up[0]; + v3f[ 1] = org[1] - right[1] - up[1]; + v3f[ 2] = org[2] - right[2] - up[2]; + v3f[ 3] = org[0] - right[0] + up[0]; + v3f[ 4] = org[1] - right[1] + up[1]; + v3f[ 5] = org[2] - right[2] + up[2]; + v3f[ 6] = org[0] + right[0] + up[0]; + v3f[ 7] = org[1] + right[1] + up[1]; + v3f[ 8] = org[2] + right[2] + up[2]; + v3f[ 9] = org[0] + right[0] - up[0]; + v3f[10] = org[1] + right[1] - up[1]; + v3f[11] = org[2] + right[2] - up[2]; + t2f[0] = tex->s1;t2f[1] = tex->t2; + t2f[2] = tex->s1;t2f[3] = tex->t1; + t2f[4] = tex->s2;t2f[5] = tex->t1; + t2f[6] = tex->s2;t2f[7] = tex->t2; + } + + // now render batches of particles based on blendmode and texture + blendmode = PBLEND_ADD; + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + texture = particletexture[63].texture; + R_Mesh_TexBind(0, R_GetTexture(texture)); + GL_LockArrays(0, numsurfaces*4); + batchstart = 0; + batchcount = 0; + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) + { + d = cl.decals + surfacelist[surfacelistindex]; + + if (blendmode != particletype[d->typeindex].blendmode) + { + if (batchcount > 0) + R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6, 0, 0); + batchcount = 0; + batchstart = surfacelistindex; + blendmode = particletype[d->typeindex].blendmode; + if (blendmode == PBLEND_ALPHA) + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + else if (blendmode == PBLEND_ADD) + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + else //if (blendmode == PBLEND_MOD) + GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + } + if (texture != particletexture[d->texnum].texture) + { + if (batchcount > 0) + R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6, 0, 0); + batchcount = 0; + batchstart = surfacelistindex; + texture = particletexture[d->texnum].texture; + R_Mesh_TexBind(0, R_GetTexture(texture)); + } + + batchcount++; + } + if (batchcount > 0) + R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6, 0, 0); + GL_LockArrays(0, 0); +} + void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) { int surfacelistindex; @@ -2174,6 +2366,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh rtexture_t *texture; float *v3f, *t2f, *c4f; + r_refdef.stats.particles += numsurfaces; R_Mesh_Matrix(&identitymatrix); R_Mesh_ResetTextureState(); R_Mesh_VertexPointer(particle_vertex3f, 0, 0); @@ -2194,7 +2387,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh p = cl.particles + surfacelist[surfacelistindex]; - blendmode = p->type->blendmode; + blendmode = particletype[p->typeindex].blendmode; cr = p->color[0] * (1.0f / 255.0f) * r_view.colorscale; cg = p->color[1] * (1.0f / 255.0f) * r_view.colorscale; @@ -2211,7 +2404,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh ca = 1; } ca *= cl_particles_alpha.value; - if (p->type->lighting) + if (particletype[p->typeindex].lighting) { float ambient[3], diffuse[3], diffusenormal[3]; R_CompleteLightPoint(ambient, diffuse, diffusenormal, p->org, true); @@ -2241,8 +2434,9 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh size = p->size * cl_particles_size.value; org = p->org; tex = &particletexture[p->texnum]; - if (p->type->orientation == PARTICLE_BILLBOARD) + switch(particletype[p->typeindex].orientation) { + case PARTICLE_BILLBOARD: VectorScale(r_view.left, -size, right); VectorScale(r_view.up, size, up); v3f[ 0] = org[0] - right[0] - up[0]; @@ -2261,9 +2455,8 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh t2f[2] = tex->s1;t2f[3] = tex->t1; t2f[4] = tex->s2;t2f[5] = tex->t1; t2f[6] = tex->s2;t2f[7] = tex->t2; - } - else if (p->type->orientation == PARTICLE_ORIENTED_DOUBLESIDED) - { + break; + case PARTICLE_ORIENTED_DOUBLESIDED: VectorVectors(p->vel, right, up); VectorScale(right, size, right); VectorScale(up, size, up); @@ -2283,9 +2476,8 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh t2f[2] = tex->s1;t2f[3] = tex->t1; t2f[4] = tex->s2;t2f[5] = tex->t1; t2f[6] = tex->s2;t2f[7] = tex->t2; - } - else if (p->type->orientation == PARTICLE_SPARK) - { + break; + case PARTICLE_SPARK: VectorMA(org, -0.02, p->vel, v); VectorMA(org, 0.02, p->vel, up2); R_CalcBeam_Vertex3f(v3f, v, up2, size); @@ -2293,9 +2485,8 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh t2f[2] = tex->s1;t2f[3] = tex->t1; t2f[4] = tex->s2;t2f[5] = tex->t1; t2f[6] = tex->s2;t2f[7] = tex->t2; - } - else if (p->type->orientation == PARTICLE_BEAM) - { + break; + case PARTICLE_BEAM: R_CalcBeam_Vertex3f(v3f, org, p->vel, size); VectorSubtract(p->vel, org, up); VectorNormalize(up); @@ -2305,11 +2496,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh t2f[2] = 0;t2f[3] = v[0]; t2f[4] = 0;t2f[5] = v[1]; t2f[6] = 1;t2f[7] = v[1]; - } - else - { - Con_Printf("R_DrawParticles: unknown particle orientation %i\n", p->type->orientation); - return; + break; } } @@ -2325,13 +2512,13 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh { p = cl.particles + surfacelist[surfacelistindex]; - if (blendmode != p->type->blendmode) + if (blendmode != particletype[p->typeindex].blendmode) { if (batchcount > 0) R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6, 0, 0); batchcount = 0; batchstart = surfacelistindex; - blendmode = p->type->blendmode; + blendmode = particletype[p->typeindex].blendmode; if (blendmode == PBLEND_ALPHA) GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); else if (blendmode == PBLEND_ADD) @@ -2356,6 +2543,26 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh GL_LockArrays(0, 0); } +void R_DrawDecals (void) +{ + int i; + const decal_t *d; + + // LordHavoc: early out conditions + if ((!cl.num_decals) || (!r_drawdecals.integer)) + return; + + // LordHavoc: only render if not too close + for (i = 0, d = cl.decals;i < cl.num_decals;i++, d++) + { + if (d->typeindex) + { + r_refdef.stats.decals++; + R_MeshQueue_AddTransparent(d->org, R_DrawDecal_TransparentCallback, NULL, i, NULL); + } + } +} + void R_DrawParticles (void) { int i; @@ -2370,13 +2577,6 @@ 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 && !p->delayedspawn) - { - r_refdef.stats.particles++; - if (DotProduct(p->org, r_view.forward) >= minparticledist || p->type->orientation == PARTICLE_BEAM) - R_MeshQueue_AddTransparent(p->org, R_DrawParticle_TransparentCallback, NULL, i, NULL); - } - } + if (p->typeindex && !p->delayedspawn && (DotProduct(p->org, r_view.forward) >= minparticledist || particletype[p->typeindex].orientation == PARTICLE_BEAM)) + R_MeshQueue_AddTransparent(p->org, R_DrawParticle_TransparentCallback, NULL, i, NULL); } - diff --git a/cl_screen.c b/cl_screen.c index ab5bafc6..1314f386 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -683,7 +683,8 @@ void R_TimeReport_Frame(void) if (loc) sprintf(r_speeds_string + strlen(r_speeds_string), "Location: %s\n", loc->name); sprintf(r_speeds_string + strlen(r_speeds_string), "org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n", r_view.origin[0], r_view.origin[1], r_view.origin[2], r_view.forward[0], r_view.forward[1], r_view.forward[2]); - sprintf(r_speeds_string + strlen(r_speeds_string), "%5i entities%6i surfaces%6i triangles%5i leafs%5i portals%6i particles\n", r_refdef.stats.entities, r_refdef.stats.entities_surfaces, r_refdef.stats.entities_triangles, r_refdef.stats.world_leafs, r_refdef.stats.world_portals, r_refdef.stats.particles); + sprintf(r_speeds_string + strlen(r_speeds_string), "%7i surfaces%7i triangles %5i entities (%7i surfaces%7i triangles)\n", r_refdef.stats.world_surfaces, r_refdef.stats.world_triangles, r_refdef.stats.entities, r_refdef.stats.entities_surfaces, r_refdef.stats.entities_triangles); + sprintf(r_speeds_string + strlen(r_speeds_string), "%5ileafs%5i portals%6i particles%6i decals\n", r_refdef.stats.world_leafs, r_refdef.stats.world_portals, r_refdef.stats.particles, r_refdef.stats.decals); sprintf(r_speeds_string + strlen(r_speeds_string), "%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n", r_refdef.stats.lights, r_refdef.stats.lights_clears, r_refdef.stats.lights_scissored, r_refdef.stats.lights_lighttriangles, r_refdef.stats.lights_shadowtriangles, r_refdef.stats.lights_dynamicshadowtriangles); if (r_refdef.stats.bloom) sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles bloompixels%8i copied%8i drawn\n", r_refdef.stats.meshes, r_refdef.stats.meshes_elements / 3, r_refdef.stats.bloom_copypixels, r_refdef.stats.bloom_drawpixels); diff --git a/client.h b/client.h index 559d0e94..3008887d 100644 --- a/client.h +++ b/client.h @@ -631,33 +631,46 @@ particletype_t; typedef enum { - pt_alphastatic, pt_static, pt_spark, pt_beam, pt_rain, pt_raindecal, pt_snow, pt_bubble, pt_blood, pt_smoke, pt_decal, pt_entityparticle, pt_total + pt_dead, pt_alphastatic, pt_static, pt_spark, pt_beam, pt_rain, pt_raindecal, pt_snow, pt_bubble, pt_blood, pt_smoke, pt_decal, pt_entityparticle, pt_total } ptype_t; +typedef struct decal_s +{ + unsigned short typeindex; + unsigned short texnum; + vec3_t org; + vec3_t normal; + float size; + float alpha; // 0-255 + float time2; // used for snow fluttering and decal fade + unsigned char color[4]; + unsigned int owner; // decal stuck to this entity + model_t *ownermodel; // model the decal is stuck to (used to make sure the entity is still alive) + vec3_t relativeorigin; // decal at this location in entity's coordinate space + vec3_t relativenormal; // decal oriented this way relative to entity's coordinate space +} +decal_t; + typedef struct particle_s { - particletype_t *type; - int texnum; - vec3_t org; - vec3_t vel; // velocity of particle, or orientation of decal, or end point of beam - float size; - float sizeincrease; // rate of size change per second - float alpha; // 0-255 - float alphafade; // how much alpha reduces per second - float time2; // used for snow fluttering and decal fade - 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) - float gravity; // how much gravity affects this particle (1.0 = normal gravity, 0.0 = none) - float airfriction; // how much air friction affects this object (objects with a low mass/size ratio tend to get more air friction) - float liquidfriction; // how much liquid friction affects this object (objects with a low mass/size ratio tend to get more liquid friction) - unsigned char color[4]; - unsigned int owner; // decal stuck to this entity - model_t *ownermodel; // model the decal is stuck to (used to make sure the entity is still alive) - vec3_t relativeorigin; // decal at this location in entity's coordinate space - vec3_t relativedirection; // decal oriented this way relative to entity's coordinate space - float delayedcollisions; // time that p->bounce becomes active - float delayedspawn; // time that particle appears and begins moving - float die; // time when this particle should be removed, regardless of alpha + unsigned short typeindex; + unsigned short texnum; + vec3_t org; + vec3_t vel; // velocity of particle, or orientation of decal, or end point of beam + float size; + float sizeincrease; // rate of size change per second + float alpha; // 0-255 + float alphafade; // how much alpha reduces per second + float time2; // used for snow fluttering and decal fade + 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) + float gravity; // how much gravity affects this particle (1.0 = normal gravity, 0.0 = none) + float airfriction; // how much air friction affects this object (objects with a low mass/size ratio tend to get more air friction) + float liquidfriction; // how much liquid friction affects this object (objects with a low mass/size ratio tend to get more liquid friction) + unsigned char color[4]; + float delayedcollisions; // time that p->bounce becomes active + float delayedspawn; // time that particle appears and begins moving + float die; // time when this particle should be removed, regardless of alpha } particle_t; @@ -913,6 +926,7 @@ typedef struct client_state_s int max_lightstyle; int max_brushmodel_entities; int max_particles; + int max_decals; int max_showlmps; entity_t *entities; @@ -925,6 +939,7 @@ typedef struct client_state_s lightstyle_t *lightstyle; int *brushmodel_entities; particle_t *particles; + decal_t *decals; showlmp_t *showlmps; int num_entities; @@ -935,9 +950,11 @@ typedef struct client_state_s int num_beams; int num_dlights; int num_particles; + int num_decals; int num_showlmps; int free_particle; + int free_decal; // cl_serverextension_download feature int loadmodel_current; @@ -1284,6 +1301,7 @@ void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, in void CL_EntityParticles (const entity_t *ent); void CL_ParticleExplosion (const vec3_t org); void CL_ParticleExplosion2 (const vec3_t org, int colorStart, int colorLength); +void CL_MoveDecals(void); void CL_MoveParticles(void); void R_MoveExplosions(void); void R_NewExplosion(const vec3_t org); @@ -1309,7 +1327,10 @@ typedef struct r_refdef_stats_s int entities_triangles; int world_leafs; int world_portals; + int world_surfaces; + int world_triangles; int particles; + int decals; int meshes; int meshes_elements; int lights; diff --git a/gl_rmain.c b/gl_rmain.c index fbff4205..577e6fb4 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -2231,7 +2231,6 @@ static void R_DrawModelsDepth(void) if (!r_viewcache.entityvisible[i]) continue; ent = r_refdef.entities[i]; - r_refdef.stats.entities++; if (ent->model && ent->model->DrawDepth != NULL) ent->model->DrawDepth(ent); } @@ -2250,7 +2249,6 @@ static void R_DrawModelsDebug(void) if (!r_viewcache.entityvisible[i]) continue; ent = r_refdef.entities[i]; - r_refdef.stats.entities++; if (ent->model && ent->model->DrawDebug != NULL) ent->model->DrawDebug(ent); } @@ -2269,7 +2267,6 @@ static void R_DrawModelsAddWaterPlanes(void) if (!r_viewcache.entityvisible[i]) continue; ent = r_refdef.entities[i]; - r_refdef.stats.entities++; if (ent->model && ent->model->DrawAddWaterPlanes != NULL) ent->model->DrawAddWaterPlanes(ent); } @@ -3418,6 +3415,10 @@ void R_RenderScene(qboolean addwaterplanes) if (r_timereport_active) R_TimeReport("lightning"); + R_DrawDecals(); + if (r_timereport_active) + R_TimeReport("decals"); + R_DrawParticles(); if (r_timereport_active) R_TimeReport("particles"); @@ -5823,7 +5824,6 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); - r_refdef.stats.entities_surfaces += texturenumsurfaces; } else if (r_depthfirst.integer == 3) return; @@ -5848,7 +5848,6 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur R_Mesh_ResetTextureState(); RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist); - r_refdef.stats.entities_surfaces += texturenumsurfaces; } else if (gl_lightmaps.integer) { @@ -5876,13 +5875,9 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false); else RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false); - r_refdef.stats.entities_surfaces += texturenumsurfaces; } else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) - { R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); - r_refdef.stats.entities_surfaces += texturenumsurfaces; - } else if (rsurface.texture->currentnumlayers) { // write depth for anything we skipped on the depth-only pass earlier @@ -5901,7 +5896,6 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist); else R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist); - r_refdef.stats.entities_surfaces += texturenumsurfaces; } CHECKGLERROR GL_LockArrays(0, 0); @@ -6211,7 +6205,6 @@ extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface); void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug) { int i, j, endj, f, flagsmask; - int counttriangles = 0; msurface_t *surface, **surfacechain; texture_t *t; model_t *model = r_refdef.worldmodel; @@ -6272,25 +6265,25 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep R_BuildLightMap(r_refdef.worldentity, surface); // add face to draw list surfacelist[numsurfacelist++] = surface; - counttriangles += surface->num_triangles; + r_refdef.stats.world_triangles += surface->num_triangles; if (numsurfacelist >= maxsurfacelist) { + r_refdef.stats.world_surfaces += numsurfacelist; R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); numsurfacelist = 0; } } } } + r_refdef.stats.world_surfaces += numsurfacelist; if (numsurfacelist) R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); - r_refdef.stats.entities_triangles += counttriangles; RSurf_CleanUp(); } void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug) { int i, f, flagsmask; - int counttriangles = 0; msurface_t *surface, *endsurface, **surfacechain; texture_t *t; model_t *model = ent->model; @@ -6351,16 +6344,17 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr R_BuildLightMap(ent, surface); // add face to draw list surfacelist[numsurfacelist++] = surface; - counttriangles += surface->num_triangles; + r_refdef.stats.entities_triangles += surface->num_triangles; if (numsurfacelist >= maxsurfacelist) { + r_refdef.stats.entities_surfaces += numsurfacelist; R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); numsurfacelist = 0; } } } + r_refdef.stats.entities_surfaces += numsurfacelist; if (numsurfacelist) R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); - r_refdef.stats.entities_triangles += counttriangles; RSurf_CleanUp(); } diff --git a/render.h b/render.h index 830666f7..a2696fe6 100644 --- a/render.h +++ b/render.h @@ -136,6 +136,7 @@ skinframe_t *R_SkinFrame_LoadInternal(const char *name, int textureflags, int lo skinframe_t *R_SkinFrame_LoadMissing(void); void R_View_WorldVisibility(qboolean forcenovis); +void R_DrawDecals(void); void R_DrawParticles(void); void R_DrawExplosions(void); -- 2.39.2