cvar_t cl_decals_newsystem = {CVAR_SAVE, "cl_decals_newsystem", "1", "enables new advanced decal system"};
cvar_t cl_decals_newsystem_intensitymultiplier = {CVAR_SAVE, "cl_decals_newsystem_intensitymultiplier", "2", "boosts intensity of decals (because the distance fade can make them hard to see otherwise)"};
cvar_t cl_decals_newsystem_immediatebloodstain = {CVAR_SAVE, "cl_decals_newsystem_immediatebloodstain", "2", "0: no on-spawn blood stains; 1: on-spawn blood stains for pt_blood; 2: always use on-spawn blood stains"};
+cvar_t cl_decals_newsystem_bloodsmears = {CVAR_SAVE, "cl_decals_newsystem_bloodsmears", "1", "enable use of particle velocity as decal projection direction rather than surface normal"};
cvar_t cl_decals_models = {CVAR_SAVE, "cl_decals_models", "0", "enables decals on animated models (if newsystem is also 1)"};
cvar_t cl_decals_bias = {CVAR_SAVE, "cl_decals_bias", "0.125", "distance to bias decals from surface to prevent depth fighting"};
cvar_t cl_decals_max = {CVAR_SAVE, "cl_decals_max", "4096", "maximum number of decals allowed to exist in the world at once"};
if (filepass == 0)
{
if (customfile)
- dpsnprintf(filename, sizeof(filename), customfile);
+ strlcpy(filename, customfile, sizeof(filename));
else
- dpsnprintf(filename, sizeof(filename), "effectinfo.txt");
+ strlcpy(filename, "effectinfo.txt", sizeof(filename));
}
else if (filepass == 1)
{
}
}
-void CL_Particles_LoadEffectInfo_f(void)
+static void CL_Particles_LoadEffectInfo_f(void)
{
CL_Particles_LoadEffectInfo(Cmd_Argc() > 1 ? Cmd_Argv(1) : NULL);
}
Cvar_RegisterVariable (&cl_decals_newsystem);
Cvar_RegisterVariable (&cl_decals_newsystem_intensitymultiplier);
Cvar_RegisterVariable (&cl_decals_newsystem_immediatebloodstain);
+ Cvar_RegisterVariable (&cl_decals_newsystem_bloodsmears);
Cvar_RegisterVariable (&cl_decals_models);
Cvar_RegisterVariable (&cl_decals_bias);
Cvar_RegisterVariable (&cl_decals_max);
void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, float alpha, int texnum, int color1, int color2)
{
int i;
- float bestfrac, bestorg[3], bestnormal[3];
- float org2[3];
+ vec_t bestfrac;
+ vec3_t bestorg;
+ vec3_t bestnormal;
+ vec3_t org2;
int besthitent = 0, hitent;
trace_t trace;
bestfrac = 10;
vec3_t center;
matrix4x4_t tempmatrix;
particle_t *part;
+
VectorLerp(originmins, 0.5, originmaxs, center);
Matrix4x4_CreateTranslate(&tempmatrix, center[0], center[1], center[2]);
if (effectnameindex == EFFECT_SVC_PARTICLE)
}
else if (effectnameindex == EFFECT_EF_FLAME)
{
+ if (!spawnparticles)
+ count = 0;
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);
}
else if (effectnameindex == EFFECT_EF_STARDUST)
{
+ if (!spawnparticles)
+ count = 0;
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);
VectorCopy(originmins, trailpos);
if (info->trailspacing > 0)
{
- info->particleaccumulator += traillen / info->trailspacing * cl_particles_quality.value * pcount;
- trailstep = info->trailspacing / cl_particles_quality.value / max(0.001, pcount);
+ info->particleaccumulator += traillen / info->trailspacing * cl_particles_quality.value;
+ trailstep = info->trailspacing / cl_particles_quality.value;
immediatebloodstain = false;
AnglesFromVectors(angles, traildir, NULL, false);
void CL_EntityParticles (const entity_t *ent)
{
int i;
- float pitch, yaw, dist = 64, beamlength = 16, org[3], v[3];
+ vec_t pitch, yaw, dist = 64, beamlength = 16;
+ vec3_t org, v;
static vec3_t avelocities[NUMVERTEXNORMALS];
if (!cl_particles.integer) return;
if (cl.time <= cl.oldtime) return; // don't spawn new entity particles while paused
void CL_ReadPointFile_f (void)
{
- vec3_t org, leakorg;
+ double org[3], leakorg[3];
+ vec3_t vecorg;
int r, c, s;
char *pointfile = NULL, *pointfilepos, *t, tchar;
char name[MAX_QPATH];
#if _MSC_VER >= 1400
#define sscanf sscanf_s
#endif
- r = sscanf (pointfilepos,"%f %f %f", &org[0], &org[1], &org[2]);
+ r = sscanf (pointfilepos,"%lf %lf %lf", &org[0], &org[1], &org[2]);
+ VectorCopy(org, vecorg);
*t = tchar;
pointfilepos = t;
if (r != 3)
if (cl.num_particles < cl.max_particles - 3)
{
s++;
- CL_NewParticle(org, pt_alphastatic, 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, true, 1<<30, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewParticle(vecorg, pt_alphastatic, 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, true, 1<<30, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
}
}
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]);
+ 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]);
- CL_NewParticle(org, 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(org, 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(org, 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);
+ 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);
}
/*
const decal_t *d;
float *v3f, *t2f, *c4f;
particletexture_t *tex;
- float right[3], up[3], size, ca;
+ vec_t right[3], up[3], size, ca;
float alphascale = (1.0f / 65536.0f) * cl_particles_alpha.value;
RSurf_ActiveWorldEntity();
- r_refdef.stats.drawndecals += numsurfaces;
+ r_refdef.stats[r_stat_drawndecals] += numsurfaces;
// R_Mesh_ResetTextureState();
GL_DepthMask(false);
GL_DepthRange(0, 1);
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))
- R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, decal->org, R_DrawDecal_TransparentCallback, NULL, i, NULL);
+ R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, decal->org, R_DrawDecal_TransparentCallback, NULL, i, NULL);
continue;
killdecal:
decal->typeindex = 0;
Mem_Free(olddecals);
}
- r_refdef.stats.totaldecals = cl.num_decals;
+ r_refdef.stats[r_stat_totaldecals] = cl.num_decals;
}
static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
+ vec3_t vecorg, vecvel, baseright, baseup;
int surfacelistindex;
int batchstart, batchcount;
const particle_t *p;
particletexture_t *tex;
float up2[3], v[3], right[3], up[3], fog, ifog, size, len, lenfactor, alpha;
// float ambient[3], diffuse[3], diffusenormal[3];
- float palpha, spintime, spinrad, spincos, spinsin, spinm1, spinm2, spinm3, spinm4, baseright[3], baseup[3];
+ float palpha, spintime, spinrad, spincos, spinsin, spinm1, spinm2, spinm3, spinm4;
vec4_t colormultiplier;
float minparticledist_start, minparticledist_end;
qboolean dofade;
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));
- r_refdef.stats.particles += numsurfaces;
+ r_refdef.stats[r_stat_particles] += numsurfaces;
// R_Mesh_ResetTextureState();
GL_DepthMask(false);
GL_DepthRange(0, 1);
c4f[3] = alpha;
// note: lighting is not cheap!
if (particletype[p->typeindex].lighting)
- R_LightPoint(c4f, p->org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT);
+ {
+ 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);
+ }
// mix in the fog color
if (r_refdef.fogenabled)
{
t2f[6] = tex->s2;t2f[7] = tex->t2;
break;
case PARTICLE_ORIENTED_DOUBLESIDED:
- VectorVectors(p->vel, baseright, baseup);
+ vecvel[0] = p->vel[0];
+ vecvel[1] = p->vel[1];
+ vecvel[2] = p->vel[2];
+ VectorVectors(vecvel, baseright, baseup);
if (p->angle + p->spin)
{
spinrad = (p->angle + p->spin * (spintime - p->delayedspawn)) * (float)(M_PI / 180.0f);
int drawparticles = r_drawparticles.integer;
float minparticledist_start;
particle_t *p;
- float gravity, frametime, f, dist, oldorg[3];
+ float gravity, frametime, f, dist, oldorg[3], decaldir[3];
float drawdist2;
int hitent;
trace_t trace;
{
// create a decal for the blood splat
a = 0xFFFFFF ^ (p->staincolor[0]*65536+p->staincolor[1]*256+p->staincolor[2]);
- CL_SpawnDecalParticleForSurface(hitent, p->org, trace.plane.normal, a, a, p->staintexnum, p->stainsize, p->stainalpha); // staincolor needs to be inverted for decals!
+ if (cl_decals_newsystem_bloodsmears.integer)
+ {
+ VectorCopy(p->vel, decaldir);
+ VectorNormalize(decaldir);
+ }
+ else
+ VectorCopy(trace.plane.normal, decaldir);
+ CL_SpawnDecalParticleForSurface(hitent, p->org, decaldir, a, a, p->staintexnum, p->stainsize, p->stainalpha); // staincolor needs to be inverted for decals!
}
}
}
if (cl_decals.integer)
{
// 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 * lhrandom(cl_particles_blood_decal_scalemin.value, cl_particles_blood_decal_scalemax.value), cl_particles_blood_decal_alpha.value * 768);
+ if (cl_decals_newsystem_bloodsmears.integer)
+ {
+ VectorCopy(p->vel, decaldir);
+ VectorNormalize(decaldir);
+ }
+ else
+ VectorCopy(trace.plane.normal, decaldir);
+ CL_SpawnDecalParticleForSurface(hitent, p->org, decaldir, 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 * lhrandom(cl_particles_blood_decal_scalemin.value, cl_particles_blood_decal_scalemax.value), cl_particles_blood_decal_alpha.value * 768);
}
}
goto killparticle;
{
case pt_beam:
// beams have no culling
- R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
+ R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
break;
default:
if(cl_particles_visculling.integer)
}
// 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))
- R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
+ R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
break;
}