X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=cl_particles.c;h=853c25e20afd58315ff0f97815ae20e02c11d798;hp=d1a337eee5c4e45ec0c34c965318ad7eb85e995d;hb=366229127dad0794355c9daf8e17c833624b3d80;hpb=1e6e04bb72ba9bbb14bf9615252e7afcbc967180 diff --git a/cl_particles.c b/cl_particles.c index d1a337ee..853c25e2 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"}; @@ -317,7 +324,7 @@ static void CL_Particles_ParseEffectInfo(const char *textstart, const char *text argv[arrayindex][0] = 0; for (;;) { - if (!COM_ParseToken_Simple(&text, true, false)) + if (!COM_ParseToken_Simple(&text, true, false, true)) return; if (!strcmp(com_token, "\n")) break; @@ -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; @@ -1433,6 +1456,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 +1504,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 +1514,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 +1537,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 +1570,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 +1587,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 +1614,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; @@ -1592,7 +1644,8 @@ CL_EntityParticles 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 @@ -1617,7 +1670,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 +1706,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 +1719,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); } /* @@ -2262,7 +2317,7 @@ static void R_InitParticleTexture (void) bufptr = buf; for(;;) { - if(!COM_ParseToken_Simple(&bufptr, true, false)) + if(!COM_ParseToken_Simple(&bufptr, true, false, true)) break; if(!strcmp(com_token, "\n")) continue; // empty line @@ -2274,22 +2329,22 @@ static void R_InitParticleTexture (void) s2 = 1; t2 = 1; - if (COM_ParseToken_Simple(&bufptr, true, false) && strcmp(com_token, "\n")) + if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n")) { strlcpy(texturename, com_token, sizeof(texturename)); s1 = atof(com_token); - if (COM_ParseToken_Simple(&bufptr, true, false) && strcmp(com_token, "\n")) + if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n")) { texturename[0] = 0; t1 = atof(com_token); - if (COM_ParseToken_Simple(&bufptr, true, false) && strcmp(com_token, "\n")) + if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n")) { s2 = atof(com_token); - if (COM_ParseToken_Simple(&bufptr, true, false) && strcmp(com_token, "\n")) + if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n")) { t2 = atof(com_token); strlcpy(texturename, "particles/particlefont.tga", sizeof(texturename)); - if (COM_ParseToken_Simple(&bufptr, true, false) && strcmp(com_token, "\n")) + if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n")) strlcpy(texturename, com_token, sizeof(texturename)); } } @@ -2331,7 +2386,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 +2398,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 +2432,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 +2553,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(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 +2574,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 +2589,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 +2598,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 +2657,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 +2723,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 +2855,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 +2944,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 +2967,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 +3055,7 @@ void R_DrawParticles (void) { case pt_beam: // beams have no culling - R_MeshQueue_AddTransparent(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 +3069,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(p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL); + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL); break; }