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;
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];
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;
{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];
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;
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);}
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;}
"SVC_PARTICLE"
};
-static void CL_Particles_LoadEffectInfo(void)
+static void CL_Particles_LoadEffectInfo(const char *customfile)
{
int i;
int filepass;
for (filepass = 0;;filepass++)
{
if (filepass == 0)
- dpsnprintf(filename, sizeof(filename), "effectinfo.txt");
+ {
+ if (customfile)
+ dpsnprintf(filename, sizeof(filename), customfile);
+ else
+ dpsnprintf(filename, sizeof(filename), "effectinfo.txt");
+ }
else if (filepass == 1)
{
- if (!cl.worldbasename[0])
+ if (!cl.worldbasename[0] || customfile)
continue;
dpsnprintf(filename, sizeof(filename), "%s_effectinfo.txt", cl.worldnamenoextension);
}
}
}
+void CL_Particles_LoadEffectInfo_f(void)
+{
+ CL_Particles_LoadEffectInfo(Cmd_Argc() > 1 ? Cmd_Argv(1) : NULL);
+}
+
/*
===============
CL_InitParticles
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);
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;
{
// 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)
{
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++;
}
}
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)
info->particleaccumulator += traillen / info->trailspacing * cl_particles_quality.value * pcount;
trailstep = info->trailspacing / cl_particles_quality.value / max(0.001, pcount);
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
{
((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--)
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;
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
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));
}
}
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)
{
if (decalskinframe)
R_SkinFrame_MarkUsed(decalskinframe);
- CL_Particles_LoadEffectInfo();
+ CL_Particles_LoadEffectInfo(NULL);
}
unsigned short particle_elements[MESHQUEUE_TRANSPARENT_BATCHSIZE*6];
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(MESHQUEUE_SORT_DISTANCE, decal->org, R_DrawDecal_TransparentCallback, NULL, i, NULL);
continue;
killdecal:
decal->typeindex = 0;
{
case pt_beam:
// beams have no culling
- R_MeshQueue_AddTransparent(p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
+ R_MeshQueue_AddTransparent(MESHQUEUE_SORT_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(p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
+ R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
break;
}