static const int tex_raindrop = 61;
static const int tex_beam = 60;
+particleeffectinfo_t baselineparticleeffectinfo =
+{
+ 0, //int effectnameindex; // which effect this belongs to
+ // PARTICLEEFFECT_* bits
+ 0, //int flags;
+ // blood effects may spawn very few particles, so proper fraction-overflow
+ // handling is very important, this variable keeps track of the fraction
+ 0.0, //double particleaccumulator;
+ // the math is: countabsolute + requestedcount * countmultiplier * quality
+ // absolute number of particles to spawn, often used for decals
+ // (unaffected by quality and requestedcount)
+ 0.0f, //float countabsolute;
+ // multiplier for the number of particles CL_ParticleEffect was told to
+ // spawn, most effects do not really have a count and hence use 1, so
+ // this is often the actual count to spawn, not merely a multiplier
+ 0.0f, //float countmultiplier;
+ // if > 0 this causes the particle to spawn in an evenly spaced line from
+ // originmins to originmaxs (causing them to describe a trail, not a box)
+ 0.0f, //float trailspacing;
+ // type of particle to spawn (defines some aspects of behavior)
+ pt_alphastatic, //ptype_t particletype;
+ // blending mode used on this particle type
+ PBLEND_ALPHA, //pblend_t blendmode;
+ // orientation of this particle type (BILLBOARD, SPARK, BEAM, etc)
+ PARTICLE_BILLBOARD, //porientation_t orientation;
+ // range of colors to choose from in hex RRGGBB (like HTML color tags),
+ // randomly interpolated at spawn
+ {0xFFFFFF, 0xFFFFFF}, //unsigned int color[2];
+ // a random texture is chosen in this range (note the second value is one
+ // past the last choosable, so for example 8,16 chooses any from 8 up and
+ // including 15)
+ // if start and end of the range are the same, no randomization is done
+ {63, 63 /* tex_particle */}, //int tex[2];
+ // range of size values randomly chosen when spawning, plus size increase over time
+ {1, 1, 0.0f}, //float size[3];
+ // range of alpha values randomly chosen when spawning, plus alpha fade
+ {0.0f, 256.0f, 256.0f}, //float alpha[3];
+ // how long the particle should live (note it is also removed if alpha drops to 0)
+ {16777216.0f, 16777216.0f}, //float time[2];
+ // how much gravity affects this particle (negative makes it fly up!)
+ 0.0f, //float gravity;
+ // how much bounce the particle has when it hits a surface
+ // if negative the particle is removed on impact
+ 0.0f, //float bounce;
+ // if in air this friction is applied
+ // if negative the particle accelerates
+ 0.0f, //float airfriction;
+ // if in liquid (water/slime/lava) this friction is applied
+ // if negative the particle accelerates
+ 0.0f, //float liquidfriction;
+ // these offsets are added to the values given to particleeffect(), and
+ // then an ellipsoid-shaped jitter is added as defined by these
+ // (they are the 3 radii)
+ 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 velocityoffset[3];
+ {0.0f, 0.0f, 0.0f}, //float originjitter[3];
+ {0.0f, 0.0f, 0.0f}, //float velocityjitter[3];
+ 0.0f, //float velocitymultiplier;
+ // an effect can also spawn a dlight
+ 0.0f, //float lightradiusstart;
+ 0.0f, //float lightradiusfade;
+ 16777216.0f, //float lighttime;
+ {1.0f, 1.0f, 1.0f}, //float lightcolor[3];
+ true, //qboolean lightshadow;
+ 0, //int lightcubemapnum;
+ {(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];
+ {2.0f, 2.0f}, //float stainsize[2];
+ // other parameters
+ {0.0f, 360.0f, 0.0f, 0.0f}, //float rotate[4]; // min/max base angle, min/max rotation over time
+};
+
cvar_t cl_particles = {CVAR_SAVE, "cl_particles", "1", "enables particle effects"};
cvar_t cl_particles_quality = {CVAR_SAVE, "cl_particles_quality", "1", "multiplies number of particles"};
cvar_t cl_particles_alpha = {CVAR_SAVE, "cl_particles_alpha", "1", "multiplies opacity of particles"};
cvar_t cl_decals_max = {CVAR_SAVE, "cl_decals_max", "4096", "maximum number of decals allowed to exist in the world at once"};
-void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend, const char *filename)
+static void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend, const char *filename)
{
int arrayindex;
int argc;
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;
break;
}
info = particleeffectinfo + numparticleeffectinfo++;
+ // copy entire info from baseline, then fix up the nameindex
+ *info = baselineparticleeffectinfo;
info->effectnameindex = effectnameindex;
- info->particletype = pt_alphastatic;
- info->blendmode = particletype[info->particletype].blendmode;
- info->orientation = particletype[info->particletype].orientation;
- info->tex[0] = tex_particle;
- info->tex[1] = tex_particle;
- info->color[0] = 0xFFFFFF;
- info->color[1] = 0xFFFFFF;
- info->size[0] = 1;
- info->size[1] = 1;
- info->alpha[0] = 0;
- info->alpha[1] = 256;
- info->alpha[2] = 256;
- info->time[0] = 9999;
- info->time[1] = 9999;
- VectorSet(info->lightcolor, 1, 1, 1);
- info->lightshadow = true;
- info->lighttime = 9999;
- info->stretchfactor = 1;
- info->staincolor[0] = (unsigned int)-1;
- info->staincolor[1] = (unsigned int)-1;
- info->staintex[0] = -1;
- info->staintex[1] = -1;
- info->stainalpha[0] = 1;
- info->stainalpha[1] = 1;
- info->stainsize[0] = 2;
- info->stainsize[1] = 2;
- info->rotate[0] = 0;
- info->rotate[1] = 360;
- info->rotate[2] = 0;
- info->rotate[3] = 0;
}
else if (info == NULL)
{
"SVC_PARTICLE"
};
-void CL_Particles_LoadEffectInfo(void)
+static void CL_Particles_LoadEffectInfo(void)
{
int i;
int filepass;
part->color[0] = ((((pcolor1 >> 16) & 0xFF) * l1 + ((pcolor2 >> 16) & 0xFF) * l2) >> 8) & 0xFF;
part->color[1] = ((((pcolor1 >> 8) & 0xFF) * l1 + ((pcolor2 >> 8) & 0xFF) * l2) >> 8) & 0xFF;
part->color[2] = ((((pcolor1 >> 0) & 0xFF) * l1 + ((pcolor2 >> 0) & 0xFF) * l2) >> 8) & 0xFF;
+ if (vid.sRGB3D)
+ {
+ part->color[0] = (unsigned char)floor(Image_LinearFloatFromsRGB(part->color[0]) * 255.0f + 0.5f);
+ part->color[1] = (unsigned char)floor(Image_LinearFloatFromsRGB(part->color[1]) * 255.0f + 0.5f);
+ part->color[2] = (unsigned char)floor(Image_LinearFloatFromsRGB(part->color[2]) * 255.0f + 0.5f);
+ }
part->alpha = palpha;
part->alphafade = palphafade;
part->staintexnum = staintex;
if (cl_decals_newsystem.integer)
{
- R_DecalSystem_SplatEntities(org, normal, color[0]*(1.0f/255.0f), color[1]*(1.0f/255.0f), color[2]*(1.0f/255.0f), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size);
+ if (vid.sRGB3D)
+ R_DecalSystem_SplatEntities(org, normal, Image_LinearFloatFromsRGB(color[0]), Image_LinearFloatFromsRGB(color[1]), Image_LinearFloatFromsRGB(color[2]), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size);
+ else
+ R_DecalSystem_SplatEntities(org, normal, color[0]*(1.0f/255.0f), color[1]*(1.0f/255.0f), color[2]*(1.0f/255.0f), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size);
return;
}
decal->color[0] = color[0];
decal->color[1] = color[1];
decal->color[2] = color[2];
+ if (vid.sRGB3D)
+ {
+ decal->color[0] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[0]) * 256.0f);
+ decal->color[1] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[1]) * 256.0f);
+ decal->color[2] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[2]) * 256.0f);
+ }
decal->owner = hitent;
decal->clusterindex = -1000; // no vis culling unless we're sure
if (hitent)
static void CL_Sparks(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float sparkcount);
static void CL_Smoke(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float smokecount);
-void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles)
+static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles)
{
vec3_t center;
matrix4x4_t tempmatrix;
void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, float tintmins[4], float tintmaxs[4])
{
qboolean found = false;
+ char vabuf[1024];
if (effectnameindex < 1 || effectnameindex >= MAX_PARTICLEEFFECTNAME || !particleeffectname[effectnameindex][0])
{
Con_DPrintf("Unknown effect number %i received from server\n", effectnameindex);
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("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, 1, 0.25, 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++;
}
}
vec3_t org, dir;
int i, count, msgcount, color;
- MSG_ReadVector(org, cls.protocol);
+ MSG_ReadVector(&cl_message, org, cls.protocol);
for (i=0 ; i<3 ; i++)
- dir[i] = MSG_ReadChar () * (1.0 / 16.0);
- msgcount = MSG_ReadByte ();
- color = MSG_ReadByte ();
+ dir[i] = MSG_ReadChar(&cl_message) * (1.0 / 16.0);
+ msgcount = MSG_ReadByte(&cl_message);
+ color = MSG_ReadByte(&cl_message);
if (msgcount == 255)
count = 1024;
}
}
-static cvar_t r_drawparticles = {0, "r_drawparticles", "1", "enables drawing of particles"};
+cvar_t r_drawparticles = {0, "r_drawparticles", "1", "enables drawing of particles"};
static cvar_t r_drawparticles_drawdistance = {CVAR_SAVE, "r_drawparticles_drawdistance", "2000", "particles further than drawdistance*size will not be drawn"};
static cvar_t r_drawparticles_nearclip_min = {CVAR_SAVE, "r_drawparticles_nearclip_min", "4", "particles closer than drawnearclip_min will not be drawn"};
static cvar_t r_drawparticles_nearclip_max = {CVAR_SAVE, "r_drawparticles_nearclip_max", "4", "particles closer than drawnearclip_min will be faded"};
-static cvar_t r_drawdecals = {0, "r_drawdecals", "1", "enables drawing of decals"};
+cvar_t r_drawdecals = {0, "r_drawdecals", "1", "enables drawing of decals"};
static cvar_t r_drawdecals_drawdistance = {CVAR_SAVE, "r_drawdecals_drawdistance", "500", "decals further than drawdistance*size will not be drawn"};
#define PARTICLETEXTURESIZE 64
}
int particlefontwidth, particlefontheight, particlefontcellwidth, particlefontcellheight, particlefontrows, particlefontcols;
-void CL_Particle_PixelCoordsForTexnum(int texnum, int *basex, int *basey, int *width, int *height)
+static void CL_Particle_PixelCoordsForTexnum(int texnum, int *basex, int *basey, int *width, int *height)
{
*basex = (texnum % particlefontcols) * particlefontcellwidth;
*basey = ((texnum / particlefontcols) % particlefontrows) * particlefontcellheight;
memcpy(particletexturedata + ((basey + y) * PARTICLEFONTSIZE + basex) * 4, data + y * PARTICLETEXTURESIZE * 4, PARTICLETEXTURESIZE * 4);
}
-void particletextureblotch(unsigned char *data, float radius, float red, float green, float blue, float alpha)
+static void particletextureblotch(unsigned char *data, float radius, float red, float green, float blue, float alpha)
{
int x, y;
float cx, cy, dx, dy, f, iradius;
}
}
-void particletextureclamp(unsigned char *data, int minr, int ming, int minb, int maxr, int maxg, int maxb)
+#if 0
+static void particletextureclamp(unsigned char *data, int minr, int ming, int minb, int maxr, int maxg, int maxb)
{
int i;
for (i = 0;i < PARTICLETEXTURESIZE*PARTICLETEXTURESIZE;i++, data += 4)
data[2] = bound(minr, data[2], maxr);
}
}
+#endif
-void particletextureinvert(unsigned char *data)
+static void particletextureinvert(unsigned char *data)
{
int i;
for (i = 0;i < PARTICLETEXTURESIZE*PARTICLETEXTURESIZE;i++, data += 4)
}
#ifndef DUMPPARTICLEFONT
- particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, r_texture_sRGB_skin_diffuse.integer != 0);
+ particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, vid.sRGB3D);
if (!particletexture[tex_beam].texture)
#endif
{
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));
}
}
Con_Printf("particles/particlefont.txt: texnum %i outside valid range (0 to %i)\n", i, MAX_PARTICLETEXTURES);
continue;
}
- sf = R_SkinFrame_LoadExternal(texturename, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true);
+ sf = R_SkinFrame_LoadExternal(texturename, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true); // note: this loads as sRGB if sRGB is active!
if(!sf)
{
// R_SkinFrame_LoadExternal already complained
R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap, NULL, NULL);
}
-void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+static void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
int surfacelistindex;
const decal_t *d;
// now render the decals all at once
// (this assumes they all use one particle font texture!)
GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
- R_SetupShader_Generic(particletexture[63].texture, NULL, GL_MODULATE, 1);
+ R_SetupShader_Generic(particletexture[63].texture, NULL, GL_MODULATE, 1, false, false, true);
R_Mesh_PrepareVertices_Generic_Arrays(numsurfaces * 4, particle_vertex3f, particle_color4f, particle_texcoord2f);
R_Mesh_Draw(0, numsurfaces * 4, 0, numsurfaces * 2, NULL, NULL, 0, particle_elements, NULL, 0);
}
r_refdef.stats.totaldecals = cl.num_decals;
}
-void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
int surfacelistindex;
int batchstart, batchcount;
if (texture != particletexture[p->texnum].texture)
{
texture = particletexture[p->texnum].texture;
- R_SetupShader_Generic(texture, NULL, GL_MODULATE, 1);
+ R_SetupShader_Generic(texture, NULL, GL_MODULATE, 1, false, false, false);
}
if (p->blendmode == PBLEND_INVMOD)