X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=cl_particles.c;h=941c638ec5e856db865649fd94bfb933f2b49621;hb=1a700cf9b44c8561c251534f14ec5959e5987f33;hp=a11671209ddaa136d9779855aaa6ac588f34acc1;hpb=93ee242c05da6c2b71a6eaf4e393435988ca6c5a;p=xonotic%2Fdarkplaces.git diff --git a/cl_particles.c b/cl_particles.c index a1167120..941c638e 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -101,7 +101,9 @@ typedef struct particleeffectinfo_s float stretchfactor; // stretch velocity factor (used for sparks) float originoffset[3]; + float relativeoriginoffset[3]; float velocityoffset[3]; + float relativevelocityoffset[3]; float originjitter[3]; float velocityjitter[3]; float velocitymultiplier; @@ -112,6 +114,7 @@ typedef struct particleeffectinfo_s float lightcolor[3]; qboolean lightshadow; int lightcubemapnum; + float lightcorona[2]; unsigned int staincolor[2]; // note: 0x808080 = neutral (particle's own color), these are modding factors for the particle's original color! int staintex[2]; float stainalpha[2]; @@ -248,7 +251,9 @@ particleeffectinfo_t baselineparticleeffectinfo = 1.0f, //float stretchfactor; // stretch velocity factor (used for sparks) {0.0f, 0.0f, 0.0f}, //float originoffset[3]; + {0.0f, 0.0f, 0.0f}, //float relativeoriginoffset[3]; {0.0f, 0.0f, 0.0f}, //float velocityoffset[3]; + {0.0f, 0.0f, 0.0f}, //float relativevelocityoffset[3]; {0.0f, 0.0f, 0.0f}, //float originjitter[3]; {0.0f, 0.0f, 0.0f}, //float velocityjitter[3]; 0.0f, //float velocitymultiplier; @@ -259,6 +264,7 @@ particleeffectinfo_t baselineparticleeffectinfo = {1.0f, 1.0f, 1.0f}, //float lightcolor[3]; true, //qboolean lightshadow; 0, //int lightcubemapnum; + {1.0f, 0.25f}, //float lightcorona[2]; {(unsigned int)-1, (unsigned int)-1}, //unsigned int staincolor[2]; // note: 0x808080 = neutral (particle's own color), these are modding factors for the particle's original color! {-1, -1}, //int staintex[2]; {1.0f, 1.0f}, //float stainalpha[2]; @@ -297,6 +303,7 @@ cvar_t cl_decals_fadetime = {CVAR_SAVE, "cl_decals_fadetime", "1", "how long dec 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"}; @@ -422,7 +429,9 @@ static void CL_Particles_ParseEffectInfo(const char *textstart, const char *text else if (!strcmp(argv[0], "airfriction")) {readfloat(info->airfriction);} else if (!strcmp(argv[0], "liquidfriction")) {readfloat(info->liquidfriction);} else if (!strcmp(argv[0], "originoffset")) {readfloats(info->originoffset, 3);} + else if (!strcmp(argv[0], "relativeoriginoffset")) {readfloats(info->relativeoriginoffset, 3);} else if (!strcmp(argv[0], "velocityoffset")) {readfloats(info->velocityoffset, 3);} + else if (!strcmp(argv[0], "relativevelocityoffset")) {readfloats(info->relativevelocityoffset, 3);} else if (!strcmp(argv[0], "originjitter")) {readfloats(info->originjitter, 3);} else if (!strcmp(argv[0], "velocityjitter")) {readfloats(info->velocityjitter, 3);} else if (!strcmp(argv[0], "velocitymultiplier")) {readfloat(info->velocitymultiplier);} @@ -432,6 +441,7 @@ static void CL_Particles_ParseEffectInfo(const char *textstart, const char *text else if (!strcmp(argv[0], "lightcolor")) {readfloats(info->lightcolor, 3);} else if (!strcmp(argv[0], "lightshadow")) {readbool(info->lightshadow);} else if (!strcmp(argv[0], "lightcubemapnum")) {readint(info->lightcubemapnum);} + else if (!strcmp(argv[0], "lightcorona")) {readints(info->lightcorona, 2);} else if (!strcmp(argv[0], "underwater")) {checkparms(1);info->flags |= PARTICLEEFFECT_UNDERWATER;} else if (!strcmp(argv[0], "notunderwater")) {checkparms(1);info->flags |= PARTICLEEFFECT_NOTUNDERWATER;} else if (!strcmp(argv[0], "trailspacing")) {readfloat(info->trailspacing);if (info->trailspacing > 0) info->countmultiplier = 1.0f / info->trailspacing;} @@ -509,7 +519,7 @@ static const char *standardeffectnames[EFFECT_TOTAL] = "SVC_PARTICLE" }; -static void CL_Particles_LoadEffectInfo(void) +static void CL_Particles_LoadEffectInfo(const char *customfile) { int i; int filepass; @@ -524,10 +534,15 @@ static void CL_Particles_LoadEffectInfo(void) for (filepass = 0;;filepass++) { if (filepass == 0) - dpsnprintf(filename, sizeof(filename), "effectinfo.txt"); + { + if (customfile) + strlcpy(filename, customfile, sizeof(filename)); + else + strlcpy(filename, "effectinfo.txt", sizeof(filename)); + } else if (filepass == 1) { - if (!cl.worldbasename[0]) + if (!cl.worldbasename[0] || customfile) continue; dpsnprintf(filename, sizeof(filename), "%s_effectinfo.txt", cl.worldnamenoextension); } @@ -541,6 +556,11 @@ static void CL_Particles_LoadEffectInfo(void) } } +static void CL_Particles_LoadEffectInfo_f(void) +{ + CL_Particles_LoadEffectInfo(Cmd_Argc() > 1 ? Cmd_Argv(1) : NULL); +} + /* =============== CL_InitParticles @@ -550,7 +570,7 @@ void CL_ReadPointFile_f (void); void CL_Particles_Init (void) { Cmd_AddCommand ("pointfile", CL_ReadPointFile_f, "display point file produced by qbsp when a leak was detected in the map (a line leading through the leak hole, to an entity inside the level)"); - Cmd_AddCommand ("cl_particles_reloadeffects", CL_Particles_LoadEffectInfo, "reloads effectinfo.txt and maps/levelname_effectinfo.txt (where levelname is the current map)"); + Cmd_AddCommand ("cl_particles_reloadeffects", CL_Particles_LoadEffectInfo_f, "reloads effectinfo.txt and maps/levelname_effectinfo.txt (where levelname is the current map) if parameter is given, loads from custom file (no levelname_effectinfo are loaded in this case)"); Cvar_RegisterVariable (&cl_particles); Cvar_RegisterVariable (&cl_particles_quality); @@ -582,6 +602,7 @@ void CL_Particles_Init (void) 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); @@ -865,8 +886,10 @@ void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t 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; @@ -896,6 +919,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v 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) @@ -1187,6 +1211,8 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v } 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); @@ -1194,6 +1220,8 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v } 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); @@ -1433,6 +1461,11 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins vec3_t traildir; vec3_t trailpos; vec3_t rvec; + vec3_t angles; + vec3_t velocity; + vec3_t forward; + vec3_t right; + vec3_t up; vec_t traillen; vec_t trailstep; qboolean underwater; @@ -1476,7 +1509,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins { // light flash (explosion, etc) // called when effect starts - CL_AllocLightFlash(NULL, &tempmatrix, info->lightradiusstart, info->lightcolor[0]*avgtint[0]*avgtint[3], info->lightcolor[1]*avgtint[1]*avgtint[3], info->lightcolor[2]*avgtint[2]*avgtint[3], info->lightradiusfade, info->lighttime, info->lightcubemapnum, -1, info->lightshadow, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &tempmatrix, info->lightradiusstart, info->lightcolor[0]*avgtint[0]*avgtint[3], info->lightcolor[1]*avgtint[1]*avgtint[3], info->lightcolor[2]*avgtint[2]*avgtint[3], info->lightradiusfade, info->lighttime, info->lightcubemapnum, -1, info->lightshadow, info->lightcorona[0], info->lightcorona[1], 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); } else if (r_refdef.scene.numlights < MAX_DLIGHTS) { @@ -1486,7 +1519,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins rvec[0] = info->lightcolor[0]*avgtint[0]*avgtint[3]; rvec[1] = info->lightcolor[1]*avgtint[1]*avgtint[3]; rvec[2] = info->lightcolor[2]*avgtint[2]*avgtint[3]; - R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, rvec, -1, info->lightcubemapnum > 0 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", info->lightcubemapnum) : NULL, info->lightshadow, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, rvec, -1, info->lightcubemapnum > 0 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", info->lightcubemapnum) : NULL, info->lightshadow, info->lightcorona[0], info->lightcorona[1], 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++; } } @@ -1509,9 +1542,22 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins staintex = min(staintex, info->staintex[1] - 1); } 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])*avgtint[3], tex, info->color[0], info->color[1]); + { + VectorMAM(0.5f, velocitymins, 0.5f, velocitymaxs, velocity); + AnglesFromVectors(angles, velocity, NULL, false); + AngleVectors(angles, forward, right, up); + VectorMAMAMAM(1.0f, center, info->relativeoriginoffset[0], forward, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); + + CL_SpawnDecalParticleForPoint(trailpos, info->originjitter[0], lhrandom(info->size[0], info->size[1]), lhrandom(info->alpha[0], info->alpha[1])*avgtint[3], tex, info->color[0], info->color[1]); + } else if (info->orientation == PARTICLE_HBEAM) - CL_NewParticle(center, 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, false, lhrandom(info->time[0], info->time[1]), info->stretchfactor, info->blendmode, info->orientation, info->staincolor[0], info->staincolor[1], staintex, lhrandom(info->stainalpha[0], info->stainalpha[1]), lhrandom(info->stainsize[0], info->stainsize[1]), 0, 0, tintmins ? avgtint : NULL); + { + AnglesFromVectors(angles, traildir, NULL, false); + AngleVectors(angles, forward, right, up); + VectorMAMAM(info->relativeoriginoffset[0], forward, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); + + CL_NewParticle(center, 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] + trailpos[0], originmins[1] + trailpos[1], originmins[2] + trailpos[2], originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, 0, false, lhrandom(info->time[0], info->time[1]), info->stretchfactor, info->blendmode, info->orientation, info->staincolor[0], info->staincolor[1], staintex, lhrandom(info->stainalpha[0], info->stainalpha[1]), lhrandom(info->stainsize[0], info->stainsize[1]), 0, 0, tintmins ? avgtint : NULL); + } else { if (!cl_particles.integer) @@ -1529,9 +1575,14 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins 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); + AngleVectors(angles, forward, right, up); + VectorMAMAMAM(1.0f, trailpos, info->relativeoriginoffset[0], forward, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); + VectorMAMAM(info->relativevelocityoffset[0], forward, info->relativevelocityoffset[1], right, info->relativevelocityoffset[2], up, velocity); } else { @@ -1541,6 +1592,12 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins ((cl_decals_newsystem_immediatebloodstain.integer >= 1) && (info->particletype == pt_blood)) || ((cl_decals_newsystem_immediatebloodstain.integer >= 2) && staintex); + + VectorMAM(0.5f, velocitymins, 0.5f, velocitymaxs, velocity); + AnglesFromVectors(angles, velocity, NULL, false); + AngleVectors(angles, forward, right, up); + VectorMAMAMAM(1.0f, trailpos, info->relativeoriginoffset[0], traildir, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); + VectorMAMAM(info->relativevelocityoffset[0], traildir, info->relativevelocityoffset[1], right, info->relativevelocityoffset[2], up, velocity); } info->particleaccumulator = bound(0, info->particleaccumulator, 16384); for (;info->particleaccumulator >= 1;info->particleaccumulator--) @@ -1562,7 +1619,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins Vector4Lerp(tintmins, tintlerp, tintmaxs, tint); } VectorRandom(rvec); - part = CL_NewParticle(center, 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, info->countabsolute <= 0, lhrandom(info->time[0], info->time[1]), info->stretchfactor, info->blendmode, info->orientation, info->staincolor[0], info->staincolor[1], staintex, lhrandom(info->stainalpha[0], info->stainalpha[1]), lhrandom(info->stainsize[0], info->stainsize[1]), lhrandom(info->rotate[0], info->rotate[1]), lhrandom(info->rotate[2], info->rotate[3]), tintmins ? tint : NULL); + part = CL_NewParticle(center, 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] + velocity[0], lhrandom(velocitymins[1], velocitymaxs[1]) * info->velocitymultiplier + info->velocityoffset[1] + info->velocityjitter[1] * rvec[1] + velocity[1], lhrandom(velocitymins[2], velocitymaxs[2]) * info->velocitymultiplier + info->velocityoffset[2] + info->velocityjitter[2] * rvec[2] + velocity[2], info->airfriction, info->liquidfriction, 0, 0, info->countabsolute <= 0, lhrandom(info->time[0], info->time[1]), info->stretchfactor, info->blendmode, info->orientation, info->staincolor[0], info->staincolor[1], staintex, lhrandom(info->stainalpha[0], info->stainalpha[1]), lhrandom(info->stainsize[0], info->stainsize[1]), lhrandom(info->rotate[0], info->rotate[1]), lhrandom(info->rotate[2], info->rotate[3]), tintmins ? tint : NULL); if (immediatebloodstain && part) { immediatebloodstain = false; @@ -1591,8 +1648,9 @@ CL_EntityParticles */ void CL_EntityParticles (const entity_t *ent) { - int i; - float pitch, yaw, dist = 64, beamlength = 16, org[3], v[3]; + int i, j; + 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 @@ -1600,8 +1658,9 @@ void CL_EntityParticles (const entity_t *ent) Matrix4x4_OriginFromMatrix(&ent->render.matrix, org); if (!avelocities[0][0]) - for (i = 0;i < NUMVERTEXNORMALS * 3;i++) - avelocities[0][i] = lhrandom(0, 2.55); + for (i = 0;i < NUMVERTEXNORMALS;i++) + for (j = 0;j < 3;j++) + avelocities[i][j] = lhrandom(0, 2.55); for (i = 0;i < NUMVERTEXNORMALS;i++) { @@ -1617,7 +1676,8 @@ void CL_EntityParticles (const entity_t *ent) 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]; @@ -1652,7 +1712,8 @@ void CL_ReadPointFile_f (void) #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) @@ -1664,16 +1725,16 @@ void CL_ReadPointFile_f (void) 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); } /* @@ -2331,7 +2392,7 @@ static void r_part_start(void) particlepalette[i] = palette_rgb[i][0] * 65536 + palette_rgb[i][1] * 256 + palette_rgb[i][2]; particletexturepool = R_AllocTexturePool(); R_InitParticleTexture (); - CL_Particles_LoadEffectInfo(); + CL_Particles_LoadEffectInfo(NULL); } static void r_part_shutdown(void) @@ -2343,7 +2404,7 @@ static void r_part_newmap(void) { if (decalskinframe) R_SkinFrame_MarkUsed(decalskinframe); - CL_Particles_LoadEffectInfo(); + CL_Particles_LoadEffectInfo(NULL); } unsigned short particle_elements[MESHQUEUE_TRANSPARENT_BATCHSIZE*6]; @@ -2377,12 +2438,12 @@ static void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rt 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); @@ -2498,7 +2559,7 @@ void R_DrawDecals (void) 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; @@ -2519,11 +2580,12 @@ killdecal: 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; @@ -2533,7 +2595,7 @@ static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const 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; @@ -2542,7 +2604,7 @@ static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const 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); @@ -2601,7 +2663,12 @@ static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const 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) { @@ -2662,7 +2729,10 @@ static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const 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); @@ -2791,7 +2861,7 @@ void R_DrawParticles (void) 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; @@ -2880,7 +2950,14 @@ void R_DrawParticles (void) { // 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! } } } @@ -2896,7 +2973,14 @@ void R_DrawParticles (void) 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; @@ -2977,7 +3061,7 @@ void R_DrawParticles (void) { 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) @@ -2991,7 +3075,7 @@ void R_DrawParticles (void) } // 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; }