#define PARTICLEEFFECT_UNDERWATER 1
#define PARTICLEEFFECT_NOTUNDERWATER 2
+#define PARTICLEEFFECT_FORCENEAREST 4
#define PARTICLEEFFECT_DEFINED 2147483648U
typedef struct particleeffectinfo_s
float lightradiusfade;
float lighttime;
float lightcolor[3];
- qboolean lightshadow;
+ qbool 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!
static const int tex_blooddecal[8] = {16, 17, 18, 19, 20, 21, 22, 23};
static const int tex_bloodparticle[8] = {24, 25, 26, 27, 28, 29, 30, 31};
static const int tex_rainsplash = 32;
-static const int tex_particle = 63;
+static const int tex_square = 33;
+static const int tex_beam = 60;
static const int tex_bubble = 62;
static const int tex_raindrop = 61;
-static const int tex_beam = 60;
+static const int tex_particle = 63;
particleeffectinfo_t baselineparticleeffectinfo =
{
0.0f, //float lightradiusfade;
16777216.0f, //float lighttime;
{1.0f, 1.0f, 1.0f}, //float lightcolor[3];
- true, //qboolean lightshadow;
+ true, //qbool 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!
{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_CLIENT | CVAR_SAVE, "cl_particles", "1", "enables particle effects"};
-cvar_t cl_particles_quality = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_quality", "1", "multiplies number of particles"};
-cvar_t cl_particles_alpha = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_alpha", "1", "multiplies opacity of particles"};
-cvar_t cl_particles_size = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_size", "1", "multiplies particle size"};
-cvar_t cl_particles_quake = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_quake", "0", "makes particle effects look mostly like the ones in Quake"};
-cvar_t cl_particles_blood = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_blood", "1", "enables blood effects"};
-cvar_t cl_particles_blood_alpha = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_blood_alpha", "1", "opacity of blood, does not affect decals"};
-cvar_t cl_particles_blood_decal_alpha = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_blood_decal_alpha", "1", "opacity of blood decal"};
-cvar_t cl_particles_blood_decal_scalemin = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_blood_decal_scalemin", "1.5", "minimal random scale of decal"};
-cvar_t cl_particles_blood_decal_scalemax = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_blood_decal_scalemax", "2", "maximal random scale of decal"};
-cvar_t cl_particles_blood_bloodhack = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_blood_bloodhack", "1", "make certain quake particle() calls create blood effects instead"};
-cvar_t cl_particles_bulletimpacts = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_bulletimpacts", "1", "enables bulletimpact effects"};
-cvar_t cl_particles_explosions_sparks = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_explosions_sparks", "1", "enables sparks from explosions"};
-cvar_t cl_particles_explosions_shell = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_explosions_shell", "0", "enables polygonal shell from explosions"};
-cvar_t cl_particles_rain = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_rain", "1", "enables rain effects"};
-cvar_t cl_particles_snow = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_snow", "1", "enables snow effects"};
-cvar_t cl_particles_smoke = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_smoke", "1", "enables smoke (used by multiple effects)"};
-cvar_t cl_particles_smoke_alpha = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_smoke_alpha", "0.5", "smoke brightness"};
-cvar_t cl_particles_smoke_alphafade = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_smoke_alphafade", "0.55", "brightness fade per second"};
-cvar_t cl_particles_sparks = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_sparks", "1", "enables sparks (used by multiple effects)"};
-cvar_t cl_particles_bubbles = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_bubbles", "1", "enables bubbles (used by multiple effects)"};
-cvar_t cl_particles_visculling = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_visculling", "0", "perform a costly check if each particle is visible before drawing"};
-cvar_t cl_particles_collisions = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_collisions", "1", "allow costly collision detection on particles (sparks that bounce, particles not going through walls, blood hitting surfaces, etc)"};
-cvar_t cl_particles_forcetraileffects = {CVAR_CLIENT, "cl_particles_forcetraileffects", "0", "force trails to be displayed even if a non-trail draw primitive was used (debug/compat feature)"};
-cvar_t cl_decals = {CVAR_CLIENT | CVAR_SAVE, "cl_decals", "1", "enables decals (bullet holes, blood, etc)"};
-cvar_t cl_decals_visculling = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_visculling", "1", "perform a very cheap check if each decal is visible before drawing"};
-cvar_t cl_decals_time = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_time", "20", "how long before decals start to fade away"};
-cvar_t cl_decals_fadetime = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_fadetime", "1", "how long decals take to fade away"};
-cvar_t cl_decals_newsystem = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_newsystem", "1", "enables new advanced decal system"};
-cvar_t cl_decals_newsystem_intensitymultiplier = {CVAR_CLIENT | 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_CLIENT | 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_CLIENT | 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_CLIENT | CVAR_SAVE, "cl_decals_models", "0", "enables decals on animated models (if newsystem is also 1)"};
-cvar_t cl_decals_bias = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_bias", "0.125", "distance to bias decals from surface to prevent depth fighting"};
-cvar_t cl_decals_max = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_max", "4096", "maximum number of decals allowed to exist in the world at once"};
+cvar_t cl_particles = {CF_CLIENT | CF_ARCHIVE, "cl_particles", "1", "enables particle effects"};
+cvar_t cl_particles_quality = {CF_CLIENT | CF_ARCHIVE, "cl_particles_quality", "1", "multiplies number of particles"};
+cvar_t cl_particles_alpha = {CF_CLIENT | CF_ARCHIVE, "cl_particles_alpha", "1", "multiplies opacity of particles"};
+cvar_t cl_particles_size = {CF_CLIENT | CF_ARCHIVE, "cl_particles_size", "1", "multiplies particle size"};
+cvar_t cl_particles_quake = {CF_CLIENT | CF_ARCHIVE, "cl_particles_quake", "0", "0: Fancy particles; 1: Disc particles like GLQuake; 2: Square particles like software-rendered Quake"};
+cvar_t cl_particles_blood = {CF_CLIENT | CF_ARCHIVE, "cl_particles_blood", "1", "enables blood effects"};
+cvar_t cl_particles_blood_alpha = {CF_CLIENT | CF_ARCHIVE, "cl_particles_blood_alpha", "1", "opacity of blood, does not affect decals"};
+cvar_t cl_particles_blood_decal_alpha = {CF_CLIENT | CF_ARCHIVE, "cl_particles_blood_decal_alpha", "1", "opacity of blood decal"};
+cvar_t cl_particles_blood_decal_scalemin = {CF_CLIENT | CF_ARCHIVE, "cl_particles_blood_decal_scalemin", "1.5", "minimal random scale of decal"};
+cvar_t cl_particles_blood_decal_scalemax = {CF_CLIENT | CF_ARCHIVE, "cl_particles_blood_decal_scalemax", "2", "maximal random scale of decal"};
+cvar_t cl_particles_blood_bloodhack = {CF_CLIENT | CF_ARCHIVE, "cl_particles_blood_bloodhack", "1", "make certain quake particle() calls create blood effects instead"};
+cvar_t cl_particles_bulletimpacts = {CF_CLIENT | CF_ARCHIVE, "cl_particles_bulletimpacts", "1", "enables bulletimpact effects"};
+cvar_t cl_particles_explosions_sparks = {CF_CLIENT | CF_ARCHIVE, "cl_particles_explosions_sparks", "1", "enables sparks from explosions"};
+cvar_t cl_particles_explosions_shell = {CF_CLIENT | CF_ARCHIVE, "cl_particles_explosions_shell", "0", "enables polygonal shell from explosions"};
+cvar_t cl_particles_rain = {CF_CLIENT | CF_ARCHIVE, "cl_particles_rain", "1", "enables rain effects"};
+cvar_t cl_particles_snow = {CF_CLIENT | CF_ARCHIVE, "cl_particles_snow", "1", "enables snow effects"};
+cvar_t cl_particles_smoke = {CF_CLIENT | CF_ARCHIVE, "cl_particles_smoke", "1", "enables smoke (used by multiple effects)"};
+cvar_t cl_particles_smoke_alpha = {CF_CLIENT | CF_ARCHIVE, "cl_particles_smoke_alpha", "0.5", "smoke brightness"};
+cvar_t cl_particles_smoke_alphafade = {CF_CLIENT | CF_ARCHIVE, "cl_particles_smoke_alphafade", "0.55", "brightness fade per second"};
+cvar_t cl_particles_sparks = {CF_CLIENT | CF_ARCHIVE, "cl_particles_sparks", "1", "enables sparks (used by multiple effects)"};
+cvar_t cl_particles_bubbles = {CF_CLIENT | CF_ARCHIVE, "cl_particles_bubbles", "1", "enables bubbles (used by multiple effects)"};
+cvar_t cl_particles_visculling = {CF_CLIENT | CF_ARCHIVE, "cl_particles_visculling", "0", "perform a costly check if each particle is visible before drawing"};
+cvar_t cl_particles_collisions = {CF_CLIENT | CF_ARCHIVE, "cl_particles_collisions", "1", "allow costly collision detection on particles (sparks that bounce, particles not going through walls, blood hitting surfaces, etc)"};
+cvar_t cl_particles_forcetraileffects = {CF_CLIENT, "cl_particles_forcetraileffects", "0", "force trails to be displayed even if a non-trail draw primitive was used (debug/compat feature)"};
+cvar_t cl_decals = {CF_CLIENT | CF_ARCHIVE, "cl_decals", "1", "enables decals (bullet holes, blood, etc)"};
+cvar_t cl_decals_time = {CF_CLIENT | CF_ARCHIVE, "cl_decals_time", "20", "how long before decals start to fade away"};
+cvar_t cl_decals_fadetime = {CF_CLIENT | CF_ARCHIVE, "cl_decals_fadetime", "1", "how long decals take to fade away"};
+cvar_t cl_decals_newsystem_intensitymultiplier = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "cl_decals_newsystem_bloodsmears", "1", "enable use of particle velocity as decal projection direction rather than surface normal"};
+cvar_t cl_decals_models = {CF_CLIENT | CF_ARCHIVE, "cl_decals_models", "0", "enables decals on animated models"};
+cvar_t cl_decals_bias = {CF_CLIENT | CF_ARCHIVE, "cl_decals_bias", "0.125", "distance to bias decals from surface to prevent depth fighting"};
+cvar_t cl_decals_max = {CF_CLIENT | CF_ARCHIVE, "cl_decals_max", "4096", "maximum number of decals allowed to exist in the world at once"};
static void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend, const char *filename)
break;
if (argc < 16)
{
- strlcpy(argv[argc], com_token, sizeof(argv[argc]));
+ dp_strlcpy(argv[argc], com_token, sizeof(argv[argc]));
argc++;
}
}
}
else
{
- strlcpy(particleeffectname[effectnameindex], argv[1], sizeof(particleeffectname[effectnameindex]));
+ dp_strlcpy(particleeffectname[effectnameindex], argv[1], sizeof(particleeffectname[effectnameindex]));
break;
}
}
else if (!strcmp(argv[0], "staintex")) {readints(info->staintex, 2);}
else if (!strcmp(argv[0], "stainless")) {info->staintex[0] = -2; info->staincolor[0] = (unsigned int)-1; info->staincolor[1] = (unsigned int)-1; info->stainalpha[0] = 1; info->stainalpha[1] = 1; info->stainsize[0] = 2; info->stainsize[1] = 2; }
else if (!strcmp(argv[0], "rotate")) {readfloats(info->rotate, 4);}
+ else if (!strcmp(argv[0], "forcenearest")) {checkparms(1);info->flags |= PARTICLEEFFECT_FORCENEAREST;}
else
Con_Printf("%s:%i: skipping unknown command %s\n", filename, linenumber, argv[0]);
#undef checkparms
memset(particleeffectinfo, 0, sizeof(particleeffectinfo));
memset(particleeffectname, 0, sizeof(particleeffectname));
for (i = 0;i < EFFECT_TOTAL;i++)
- strlcpy(particleeffectname[i], standardeffectnames[i], sizeof(particleeffectname[i]));
+ dp_strlcpy(particleeffectname[i], standardeffectnames[i], sizeof(particleeffectname[i]));
for (filepass = 0;;filepass++)
{
if (filepass == 0)
{
if (customfile)
- strlcpy(filename, customfile, sizeof(filename));
+ dp_strlcpy(filename, customfile, sizeof(filename));
else
- strlcpy(filename, "effectinfo.txt", sizeof(filename));
+ dp_strlcpy(filename, "effectinfo.txt", sizeof(filename));
}
else if (filepass == 1)
{
void CL_ReadPointFile_f(cmd_state_t *cmd);
void CL_Particles_Init (void)
{
- Cmd_AddCommand(&cmd_client, "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(&cmd_client, "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)");
+ Cmd_AddCommand(CF_CLIENT, "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(CF_CLIENT, "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);
Cvar_RegisterVariable (&cl_particles_collisions);
Cvar_RegisterVariable (&cl_particles_forcetraileffects);
Cvar_RegisterVariable (&cl_decals);
- Cvar_RegisterVariable (&cl_decals_visculling);
Cvar_RegisterVariable (&cl_decals_time);
Cvar_RegisterVariable (&cl_decals_fadetime);
- Cvar_RegisterVariable (&cl_decals_newsystem);
Cvar_RegisterVariable (&cl_decals_newsystem_intensitymultiplier);
Cvar_RegisterVariable (&cl_decals_newsystem_immediatebloodstain);
Cvar_RegisterVariable (&cl_decals_newsystem_bloodsmears);
void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t normal, int color1, int color2, int texnum, float size, float alpha);
void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, float alpha, int texnum, int color1, int color2);
-// list of all 26 parameters:
-// ptype - any of the pt_ enum values (pt_static, pt_blood, etc), see ptype_t near the top of this file
-// pcolor1,pcolor2 - minimum and maximum ranges of color, randomly interpolated to decide particle color
-// ptex - any of the tex_ values such as tex_smoke[rand()&7] or tex_particle
-// psize - size of particle (or thickness for PARTICLE_SPARK and PARTICLE_*BEAM)
-// palpha - opacity of particle as 0-255 (can be more than 255)
-// palphafade - rate of fade per second (so 256 would mean a 256 alpha particle would fade to nothing in 1 second)
-// ptime - how long the particle can live (note it is also removed if alpha drops to nothing)
-// pgravity - how much effect gravity has on the particle (0-1)
-// pbounce - how much bounce the particle has when it hits a surface (0-1), -1 makes a blood splat when it hits a surface, 0 does not even check for collisions
-// px,py,pz - starting origin of particle
-// pvx,pvy,pvz - starting velocity of particle
-// pfriction - how much the particle slows down per second (0-1 typically, can slowdown faster than 1)
-// blendmode - one of the PBLEND_ values
-// orientation - one of the PARTICLE_ values
-// staincolor1, staincolor2: minimum and maximum ranges of stain color, randomly interpolated to decide stain color (-1 to use none)
-// staintex: any of the tex_ values such as tex_smoke[rand()&7] or tex_particle (-1 to use none)
-// stainalpha: opacity of the stain as factor for alpha
-// stainsize: size of the stain as factor for palpha
-// angle: base rotation of the particle geometry around its center normal
-// spin: rotation speed of the particle geometry around its center normal
-particle_t *CL_NewParticle(const vec3_t sortorigin, unsigned short ptypeindex, int pcolor1, int pcolor2, int ptex, float psize, float psizeincrease, float palpha, float palphafade, float pgravity, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz, float pairfriction, float pliquidfriction, float originjitter, float velocityjitter, qboolean pqualityreduction, float lifetime, float stretch, pblend_t blendmode, porientation_t orientation, int staincolor1, int staincolor2, int staintex, float stainalpha, float stainsize, float angle, float spin, float tint[4])
+
+
+/**
+ * @brief Creates a new particle and returns a pointer to it
+ *
+ * @param[in] sortorigin ?
+ * @param[in] ptypeindex Any of the pt_ enum values (pt_static, pt_blood, etc), see ptype_t near the top of this file
+ * @param[in] pcolor1,pcolor2 Minimum and maximum range of color, randomly interpolated with pcolor2 to decide particle color
+ * @param[in] ptex Any of the tex_ values such as tex_smoke[rand()&7] or tex_particle
+ * @param[in] psize Size of particle (or thickness for PARTICLE_SPARK and PARTICLE_*BEAM)
+ * @param[in] psizeincrease ?
+ * @param[in] palpha Opacity of particle as 0-255 (can be more than 255)
+ * @param[in] palphafade Rate of fade per second (so 256 would mean a 256 alpha particle would fade to nothing in 1 second)
+ * @param[in] pgravity How much effect gravity has on the particle (0-1)
+ * @param[in] pbounce How much bounce the particle has when it hits a surface (0-1), -1 makes a blood splat when it hits a surface, 0 does not even check for collisions
+ * @param[in] px,py,pz Starting origin of particle
+ * @param[in] pvx,pvy,pvz Starting velocity of particle
+ * @param[in] pairfriction How much the particle slows down, in air, per second (0-1 typically, can slowdown faster than 1)
+ * @param[in] pliquidfriction How much the particle slows down, in liquids, per second (0-1 typically, can slowdown faster than 1)
+ * @param[in] originjitter ?
+ * @param[in] velocityjitter ?
+ * @param[in] pqualityreduction ?
+ * @param[in] lifetime How long the particle can live (note it is also removed if alpha drops to nothing)
+ * @param[in] stretch ?
+ * @param[in] blendmode One of the PBLEND_ values
+ * @param[in] orientation One of the PARTICLE_ values
+ * @param[in] staincolor1 Minimum and maximum ranges of stain color, randomly interpolated to decide stain color (-1 to use none)
+ * @param[in] staincolor2 Minimum and maximum ranges of stain color, randomly interpolated to decide stain color (-1 to use none)
+ * @param[in] staintex Any of the tex_ values such as tex_smoke[rand()&7] or tex_particle
+ * @param[in] angle Base rotation of the particle geometry around its center normal
+ * @param[in] spin Rotation speed of the particle geometry around its center normal
+ * @param[in] tint The tint
+ *
+ * @return Pointer to the new particle
+ */
+particle_t *CL_NewParticle(
+ const vec3_t sortorigin,
+ unsigned short ptypeindex,
+ int pcolor1, int pcolor2,
+ int ptex,
+ float psize,
+ float psizeincrease,
+ float palpha,
+ float palphafade,
+ float pgravity,
+ float pbounce,
+ float px, float py, float pz,
+ float pvx, float pvy, float pvz,
+ float pairfriction,
+ float pliquidfriction,
+ float originjitter,
+ float velocityjitter,
+ qbool pqualityreduction,
+ float lifetime,
+ float stretch,
+ pblend_t blendmode,
+ porientation_t orientation,
+ int staincolor1,
+ int staincolor2,
+ int staintex,
+ float stainalpha,
+ float stainsize,
+ float angle,
+ float spin,
+ float tint[4])
{
int l1, l2, r, g, b;
particle_t *part;
part2->die += part->die - cl.time;
for (i = rand() & 7;i < 10;i++)
{
- part2 = CL_NewParticle(endvec, pt_spark, pcolor1, pcolor2, tex_particle, 0.25f, 0, part->alpha * 2, part->alpha * 4, 1, 0, trace.endpos[0] + trace.plane.normal[0], trace.endpos[1] + trace.plane.normal[1], trace.endpos[2] + trace.plane.normal[2], trace.plane.normal[0] * 16, trace.plane.normal[1] * 16, trace.plane.normal[2] * 16 + cl.movevars_gravity * 0.04, 0, 0, 0, 32, pqualityreduction, 0, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL);
+ part2 = CL_NewParticle(endvec, pt_spark, pcolor1, pcolor2, tex_particle, 0.25f, 0, part->alpha * 2, part->alpha * 4, 1, 0.1, trace.endpos[0] + trace.plane.normal[0], trace.endpos[1] + trace.plane.normal[1], trace.endpos[2] + trace.plane.normal[2], trace.plane.normal[0] * 16, trace.plane.normal[1] * 16, trace.plane.normal[2] * 16 + cl.movevars_gravity * 0.04, 0, 0, 0, 32, pqualityreduction, 0, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL);
if (part2)
{
part2->delayedspawn = part->die;
return part;
}
+
+
+/**
+ * @brief Creates a simple particle, a square like Quake, or a disc like GLQuake
+ *
+ * @param[in] origin ?
+ * @param[in] color_1,color_2 Minimum and maximum range of color, randomly interpolated with pcolor2 to decide particle color
+ * @param[in] gravity How much effect gravity has on the particle (0-1)
+ * @param[in] offset_x,offset_y,offset_z Starting origin of particle
+ * @param[in] velocity_offset_x,velocity_offset_y,velocity_offset_z Starting velocity of particle
+ * @param[in] air_friction How much the particle slows down, in air, per second (0-1 typically, can slowdown faster than 1)
+ * @param[in] liquid_friction How much the particle slows down, in liquids, per second (0-1 typically, can slowdown faster than 1)
+ * @param[in] origin_jitter ?
+ * @param[in] velocity_jitter ?
+ * @param[in] lifetime How long the particle can live (note it is also removed if alpha drops to nothing)
+ *
+ * @return Pointer to the new particle
+ */
+particle_t *CL_NewQuakeParticle(
+ const vec3_t origin,
+ const int color_1,
+ const int color_2,
+ const float gravity,
+ const float offset_x,
+ const float offset_y,
+ const float offset_z,
+ const float velocity_offset_x,
+ const float velocity_offset_y,
+ const float velocity_offset_z,
+ const float air_friction,
+ const float liquid_friction,
+ const float origin_jitter,
+ const float velocity_jitter,
+ const float lifetime)
+{
+ int texture;
+
+ // Set the particle texture based on the value of cl_particles_quake; defaulting to the GLQuake disc
+ if (cl_particles_quake.integer == 2)
+ texture = tex_square;
+ else
+ texture = tex_particle;
+
+ return CL_NewParticle(
+ origin,
+ pt_alphastatic, // type
+ color_1,
+ color_2,
+ texture,
+ 0.8f, // size
+ 0, // size increase
+ 255, // alpha
+ 0, // alpha fade
+ gravity,
+ 0, // bounce
+ offset_x,
+ offset_y,
+ offset_z,
+ velocity_offset_x,
+ velocity_offset_y,
+ velocity_offset_z,
+ air_friction,
+ liquid_friction,
+ origin_jitter,
+ velocity_jitter,
+ true, // quality reduction
+ lifetime,
+ 1, // stretch
+ PBLEND_ALPHA, // blend mode
+ PARTICLE_BILLBOARD, // orientation
+ -1, // stain color 1
+ -1, // stain color 2
+ -1, // stain texture
+ 1, // stain alpha
+ 1, // stain size
+ 0, // angle
+ 0, // spin
+ NULL // tint
+ );
+}
+
+
+
static void CL_ImmediateBloodStain(particle_t *part)
{
vec3_t v;
int staintex;
// blood creates a splash at spawn, not just at impact, this makes monsters bloody where they are shot
- if (part->staintexnum >= 0 && cl_decals_newsystem.integer && cl_decals.integer)
+ if (part->staintexnum >= 0 && cl_decals.integer)
{
VectorCopy(part->vel, v);
VectorNormalize(v);
}
// blood creates a splash at spawn, not just at impact, this makes monsters bloody where they are shot
- if (part->typeindex == pt_blood && cl_decals_newsystem.integer && cl_decals.integer)
+ if (part->typeindex == pt_blood && cl_decals.integer)
{
VectorCopy(part->vel, v);
VectorNormalize(v);
void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t normal, int color1, int color2, int texnum, float size, float alpha)
{
int l1, l2;
- decal_t *decal;
entity_render_t *ent = &cl.entities[hitent].render;
unsigned char color[3];
if (!cl_decals.integer)
color[1] = ((((color1 >> 8) & 0xFF) * l1 + ((color2 >> 8) & 0xFF) * l2) >> 8) & 0xFF;
color[2] = ((((color1 >> 0) & 0xFF) * l1 + ((color2 >> 0) & 0xFF) * l2) >> 8) & 0xFF;
- if (cl_decals_newsystem.integer)
- {
- 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;
- }
-
- for (;cl.free_decal < cl.max_decals && cl.decals[cl.free_decal].typeindex;cl.free_decal++);
- if (cl.free_decal >= cl.max_decals)
- return;
- decal = &cl.decals[cl.free_decal++];
- if (cl.num_decals < cl.free_decal)
- cl.num_decals = cl.free_decal;
- memset(decal, 0, sizeof(*decal));
- decal->decalsequence = cl.decalsequence++;
- decal->typeindex = pt_decal;
- decal->texnum = texnum;
- VectorMA(org, cl_decals_bias.value, normal, decal->org);
- VectorCopy(normal, decal->normal);
- decal->size = size;
- decal->alpha = alpha;
- decal->time2 = cl.time;
- 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)
- {
- // these relative things are only used to regenerate p->org and p->vel if decal->owner is not world (0)
- decal->ownermodel = cl.entities[decal->owner].render.model;
- Matrix4x4_Transform(&cl.entities[decal->owner].render.inversematrix, org, decal->relativeorigin);
- Matrix4x4_Transform3x3(&cl.entities[decal->owner].render.inversematrix, normal, decal->relativenormal);
- }
+ 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
- {
- if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.PointInLeaf)
- {
- mleaf_t *leaf = r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, decal->org);
- if(leaf)
- decal->clusterindex = leaf->clusterindex;
- }
- }
+ 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);
}
void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, float alpha, int texnum, int color1, int color2)
CL_SpawnDecalParticleForSurface(besthitent, bestorg, bestnormal, color1, color2, texnum, size, alpha);
}
+// generates a cubemap name with prefix flags based on info flags (for now only `!`)
+static char *LightCubemapNumToName(char *vabuf, size_t vasize, int lightcubemapnum, int flags)
+{
+ if (lightcubemapnum <= 0)
+ return NULL;
+ // `!` is prepended if the cubemap must be nearest-filtered
+ if (flags & PARTICLEEFFECT_FORCENEAREST)
+ return va(vabuf, vasize, "!cubemaps/%i", lightcubemapnum);
+ return va(vabuf, vasize, "cubemaps/%i", lightcubemapnum);
+}
+
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);
-static void CL_NewParticlesFromEffectinfo(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], float fade, qboolean wanttrail);
-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, qboolean wanttrail)
+static void CL_NewParticlesFromEffectinfo(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, qbool spawndlight, qbool spawnparticles, float tintmins[4], float tintmaxs[4], float fade, qbool wanttrail);
+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, qbool spawndlight, qbool spawnparticles, qbool wanttrail)
{
vec3_t center;
matrix4x4_t lightmatrix;
for (;count > 0;count--)
{
int k = particlepalette[(palettecolor & ~7) + (rand()&7)];
- CL_NewParticle(center, pt_alphastatic, k, k, tex_particle, 1.5, 0, 255, 0, 0.05, 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, 0, 8, 0, true, lhrandom(0.1, 0.5), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewQuakeParticle(
+ center, // origin
+ k, // color 1
+ k, // color 2
+ 0.15, // gravity
+ lhrandom(originmins[0], originmaxs[0]), // offset x
+ lhrandom(originmins[1], originmaxs[1]), // offset y
+ lhrandom(originmins[2], originmaxs[2]), // offset z
+ lhrandom(velocitymins[0], velocitymaxs[0]), // velocity offset x
+ lhrandom(velocitymins[1], velocitymaxs[1]), // velocity offset y
+ lhrandom(velocitymins[2], velocitymaxs[2]), // velocity offset z
+ 0, // air friction
+ 0, // liquid friction
+ 8, // origin jitter
+ 3, // velocity jitter
+ lhrandom(0.1, 0.4) // lifetime
+ );
}
}
}
// bullet hole
R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64);
CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
- CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, NULL, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (effectnameindex == EFFECT_TE_SUPERSPIKE)
{
// bullet hole
R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64);
CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
- CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, NULL, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (effectnameindex == EFFECT_TE_BLOOD)
{
else
{
static double bloodaccumulator = 0;
- qboolean immediatebloodstain = (cl_decals_newsystem_immediatebloodstain.integer >= 1);
+ qbool immediatebloodstain = (cl_decals_newsystem_immediatebloodstain.integer >= 1);
//CL_NewParticle(center, pt_alphastatic, 0x4f0000,0x7f0000, tex_particle, 2.5, 0, 256, 256, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), 0, 0, 0, 1, 4, 0, 0, true, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, NULL);
bloodaccumulator += count * 0.333 * cl_particles_quality.value;
for (;bloodaccumulator > 0;bloodaccumulator--)
// plasma scorch mark
R_Stain(center, 40, 40, 40, 40, 64, 88, 88, 88, 64);
CL_SpawnDecalParticleForPoint(center, 6, 6, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
- CL_AllocLightFlash(NULL, &lightmatrix, 200, 1, 1, 1, 1000, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 200, 1, 1, 1, 1000, 0.2, NULL, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (effectnameindex == EFFECT_TE_GUNSHOT)
{
// bullet hole
R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64);
CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
- CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, NULL, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (effectnameindex == EFFECT_TE_EXPLOSION)
{
CL_ParticleExplosion(center);
- CL_AllocLightFlash(NULL, &lightmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (effectnameindex == EFFECT_TE_EXPLOSIONQUAD)
{
CL_ParticleExplosion(center);
- CL_AllocLightFlash(NULL, &lightmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (effectnameindex == EFFECT_TE_TAREXPLOSION)
{
}
else
CL_ParticleExplosion(center);
- CL_AllocLightFlash(NULL, &lightmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (effectnameindex == EFFECT_TE_SMALLFLASH)
- CL_AllocLightFlash(NULL, &lightmatrix, 200, 2, 2, 2, 1000, 0.2, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 200, 2, 2, 2, 1000, 0.2, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
else if (effectnameindex == EFFECT_TE_FLAMEJET)
{
count *= cl_particles_quality.value;
}
if (!cl_particles_quake.integer)
CL_NewParticle(center, pt_static, 0xffffff, 0xffffff, tex_particle, 30, 0, 256, 512, 0, 0, center[0], center[1], center[2], 0, 0, 0, 0, 0, 0, 0, false, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
- CL_AllocLightFlash(NULL, &lightmatrix, 200, 2.0f, 2.0f, 2.0f, 400, 99.0f, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 200, 2.0f, 2.0f, 2.0f, 400, 99.0f, NULL, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (effectnameindex == EFFECT_TE_TEI_G3)
CL_NewParticle(center, pt_beam, 0xFFFFFF, 0xFFFFFF, tex_beam, 8, 0, 256, 256, 0, 0, originmins[0], originmins[1], originmins[2], originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, 0, false, 0, 1, PBLEND_ADD, PARTICLE_HBEAM, -1, -1, -1, 1, 1, 0, 0, NULL);
else if (effectnameindex == EFFECT_TE_TEI_BIGEXPLOSION)
{
CL_ParticleExplosion(center);
- CL_AllocLightFlash(NULL, &lightmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, -1, true, 1, 0.25, 0.5, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, NULL, -1, true, 1, 0.25, 0.5, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (effectnameindex == EFFECT_TE_TEI_PLASMAHIT)
{
if (cl_particles_sparks.integer)
for (f = 0;f < count;f += 1.0f / cl_particles_quality.value)
CL_NewParticle(center, pt_spark, 0x2030FF, 0x80C0FF, tex_particle, 2.0f, 0, lhrandom(64, 255), 512, 0, 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, 0, 0, 465, true, 0, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL);
- CL_AllocLightFlash(NULL, &lightmatrix, 500, 0.6f, 1.2f, 2.0f, 2000, 9999, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 500, 0.6f, 1.2f, 2.0f, 2000, 9999, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (effectnameindex == EFFECT_EF_FLAME)
{
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);
- CL_AllocLightFlash(NULL, &lightmatrix, 200, 2.0f, 1.5f, 0.5f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 200, 2.0f, 1.5f, 0.5f, 0, 0, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (effectnameindex == EFFECT_EF_STARDUST)
{
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);
- CL_AllocLightFlash(NULL, &lightmatrix, 200, 1.0f, 0.7f, 0.3f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ CL_AllocLightFlash(NULL, &lightmatrix, 200, 1.0f, 0.7f, 0.3f, 0, 0, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
}
else if (!strncmp(particleeffectname[effectnameindex], "TR_", 3))
{
if (cl_particles_quake.integer)
{
color = particlepalette[67 + (rand()&3)];
- CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0.05, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, true, 2, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewQuakeParticle(center, color, color, 0.25, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, 2);
}
else
{
{
dec = 6;
color = particlepalette[67 + (rand()&3)];
- CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0.05, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, true, 2, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewQuakeParticle(center, color, color, 0.25, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, 2);
}
else
{
{
r = rand()&3;
color = particlepalette[ramp3[r]];
- CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, -0.05, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, true, 0.1372549*(6-r), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewQuakeParticle(center, color, color, -0.10, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, 0.1372549 * (6 - r));
}
else
{
{
if (cl_particles_quake.integer)
{
- r = 2 + (rand()%5);
+ r = 2 + (rand()%4);
color = particlepalette[ramp3[r]];
- CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, -0.05, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, true, 0.1372549*(6-r), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewQuakeParticle(center, color, color, -0.15, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, 0.1372549 * (6 - r));
}
else
{
{
dec = 6;
color = particlepalette[52 + (rand()&7)];
- CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, pos[0], pos[1], pos[2], 30*dir[1], 30*-dir[0], 0, 0, 0, 0, 0, true, 0.5, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
- CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, pos[0], pos[1], pos[2], 30*-dir[1], 30*dir[0], 0, 0, 0, 0, 0, true, 0.5, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewQuakeParticle(center, color, color, 0, pos[0], pos[1], pos[2], 30*dir[1], 30*-dir[0], 0, 0, 0, 0, 0, 0.5);
+ CL_NewQuakeParticle(center, color, color, 0, pos[0], pos[1], pos[2], 30*-dir[1], 30*dir[0], 0, 0, 0, 0, 0, 0.5);
}
else if (gamemode == GAME_GOODVSBAD2)
{
{
dec = 6;
color = particlepalette[230 + (rand()&7)];
- CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, pos[0], pos[1], pos[2], 30*dir[1], 30*-dir[0], 0, 0, 0, 0, 0, true, 0.5, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
- CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, pos[0], pos[1], pos[2], 30*-dir[1], 30*dir[0], 0, 0, 0, 0, 0, true, 0.5, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewQuakeParticle(center, color, color, 0, pos[0], pos[1], pos[2], 30 * dir[1], 30 * -dir[0], 0, 0, 0, 0, 0, 0.5);
+ CL_NewQuakeParticle(center, color, color, 0, pos[0], pos[1], pos[2], 30 * -dir[1], 30 * dir[0], 0, 0, 0, 0, 0, 0.5);
}
else
{
if (cl_particles_quake.integer)
{
color = particlepalette[152 + (rand()&3)];
- CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 8, 0, true, 0.3, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewQuakeParticle(center, color, color, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 8, 0, 0.3);
}
else if (gamemode == GAME_GOODVSBAD2)
{
// this is also called on point effects with spawndlight = true and
// spawnparticles = true
-static void CL_NewParticlesFromEffectinfo(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], float fade, qboolean wanttrail)
+static void CL_NewParticlesFromEffectinfo(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, qbool spawndlight, qbool spawnparticles, float tintmins[4], float tintmaxs[4], float fade, qbool wanttrail)
{
- qboolean found = false;
+ qbool found = false;
char vabuf[1024];
if (effectnameindex < 1 || effectnameindex >= MAX_PARTICLEEFFECTNAME || !particleeffectname[effectnameindex][0])
{
vec3_t up;
vec_t traillen;
vec_t trailstep;
- qboolean underwater;
- qboolean immediatebloodstain;
+ qbool underwater;
+ qbool immediatebloodstain;
particle_t *part;
float avgtint[4], tint[4], tintlerp;
// note this runs multiple effects with the same name, each one spawns only one kind of particle, so some effects need more than one
{
if ((info->effectnameindex == effectnameindex) && (info->flags & PARTICLEEFFECT_DEFINED))
{
- qboolean definedastrail = info->trailspacing > 0;
+ qbool definedastrail = info->trailspacing > 0;
- qboolean drawastrail = wanttrail;
+ qbool drawastrail = wanttrail;
if (cl_particles_forcetraileffects.integer)
drawastrail = drawastrail || definedastrail;
{
// 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, info->lightcorona[0], info->lightcorona[1], 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, LightCubemapNumToName(vabuf, sizeof(vabuf), info->lightcubemapnum, info->flags), -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, info->lightcorona[0], info->lightcorona[1], 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, rvec, -1, LightCubemapNumToName(vabuf, sizeof(vabuf), info->lightcubemapnum, info->flags), 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++;
}
}
CL_ParticleEffect_Fallback(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles, wanttrail);
}
-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], float fade)
+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, qbool spawndlight, qbool spawnparticles, float tintmins[4], float tintmaxs[4], float fade)
{
CL_NewParticlesFromEffectinfo(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles, tintmins, tintmaxs, fade, true);
}
-void CL_ParticleBox(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], float fade)
+void CL_ParticleBox(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, qbool spawndlight, qbool spawnparticles, float tintmins[4], float tintmaxs[4], float fade)
{
CL_NewParticlesFromEffectinfo(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles, tintmins, tintmaxs, fade, false);
}
{
int i;
trace_t trace;
- //vec3_t v;
- //vec3_t v2;
+ particle_t *particle;
+
R_Stain(org, 96, 40, 40, 40, 64, 88, 88, 88, 64);
CL_SpawnDecalParticleForPoint(org, 40, 48, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
if (cl_particles_quake.integer)
{
- for (i = 0;i < 1024;i++)
+ for (i = 0; i < 1024; i++)
{
- int r, color;
- r = rand()&3;
+ int color;
+ int r = rand()&3;
+
if (i & 1)
{
color = particlepalette[ramp1[r]];
- CL_NewParticle(org, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, org[0], org[1], org[2], 0, 0, 0, -4, -4, 16, 256, true, 0.1006 * (8 - r), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+
+ particle = CL_NewQuakeParticle(
+ org,
+ color, color,
+ 0.05, // gravity
+ org[0], org[1], org[2], // offset
+ 0, 0, 0, // velocity
+ 2, // air friction
+ 0, // liquid friction
+ 16, // origin jitter
+ 256, // velocity jitter
+ 5 // lifetime
+ );
+ particle->typeindex = pt_explode;
}
else
{
color = particlepalette[ramp2[r]];
- CL_NewParticle(org, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, org[0], org[1], org[2], 0, 0, 0, 1, 1, 16, 256, true, 0.0669 * (8 - r), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+
+ particle = CL_NewQuakeParticle(
+ org,
+ color, color,
+ 0.05, // gravity
+ org[0], org[1], org[2], // offset
+ 0, 0, 0, // velocity
+ 0, // air friction
+ 0, // liquid friction
+ 16, // origin jitter
+ 256, // velocity jitter
+ 5 // lifetime
+ );
+
+ particle->typeindex = pt_explode2;
}
+
+ particle->time2 = r; // time2 is used to progress the colour ramp index
}
}
else
VectorMA(org, 128, v2, v);
trace = CL_TraceLine(org, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value, true, false, NULL, false, false);
}
- while (k < 16 && trace.fraction < 0.1f);
+ while (k++ < 16 && trace.fraction < 0.1f);
VectorSubtract(trace.endpos, org, v2);
VectorScale(v2, 2.0f, v2);
CL_NewParticle(org, pt_spark, 0x903010, 0xFFD030, tex_particle, 1.0f, 0, lhrandom(0, 255), 512, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL);
{
k = particlepalette[colorStart + (i % colorLength)];
if (cl_particles_quake.integer)
- CL_NewParticle(org, pt_alphastatic, k, k, tex_particle, 1, 0, 255, 0, 0, 0, org[0], org[1], org[2], 0, 0, 0, -4, -4, 16, 256, true, 0.3, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewQuakeParticle(org, k, k, 0, org[0], org[1], org[2], 0, 0, 0, -4, -4, 16, 256, 0.3);
else
CL_NewParticle(org, pt_alphastatic, k, k, tex_particle, lhrandom(0.5, 1.5), 0, 255, 512, 0, 0, org[0], org[1], org[2], 0, 0, 0, lhrandom(1.5, 3), lhrandom(1.5, 3), 8, 192, true, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
}
{
int k;
float minz, maxz, lifetime = 30;
+ float particle_size;
vec3_t org;
+
if (!cl_particles.integer) return;
if (dir[2] < 0) // falling
{
{
case 0:
if (!cl_particles_rain.integer) break;
+
count *= 4; // ick, this should be in the mod or maps?
+ particle_size = (gamemode == GAME_GOODVSBAD2) ? 20 : 0.5;
while(count--)
{
k = particlepalette[colorbase + (rand()&3)];
VectorSet(org, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz));
- if (gamemode == GAME_GOODVSBAD2)
- CL_NewParticle(org, pt_rain, k, k, tex_particle, 20, 0, lhrandom(32, 64), 0, 0, -1, org[0], org[1], org[2], dir[0], dir[1], dir[2], 0, 0, 0, 0, true, lifetime, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL);
- else
- CL_NewParticle(org, pt_rain, k, k, tex_particle, 0.5, 0, lhrandom(32, 64), 0, 0, -1, org[0], org[1], org[2], dir[0], dir[1], dir[2], 0, 0, 0, 0, true, lifetime, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewParticle(org, pt_rain, k, k, tex_particle, particle_size, 0, lhrandom(32, 64), 0, 0, -1, org[0], org[1], org[2], dir[0], dir[1], dir[2], 0, 0, 0, 0, true, lifetime, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL);
}
break;
case 1:
if (!cl_particles_snow.integer) break;
+
+ particle_size = (gamemode == GAME_GOODVSBAD2) ? 20 : 1.0;
+
while(count--)
{
k = particlepalette[colorbase + (rand()&3)];
VectorSet(org, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz));
- if (gamemode == GAME_GOODVSBAD2)
- CL_NewParticle(org, pt_snow, k, k, tex_particle, 20, 0, lhrandom(64, 128), 0, 0, -1, org[0], org[1], org[2], dir[0], dir[1], dir[2], 0, 0, 0, 0, true, lifetime, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
- else
- CL_NewParticle(org, pt_snow, k, k, tex_particle, 1, 0, lhrandom(64, 128), 0, 0, -1, org[0], org[1], org[2], dir[0], dir[1], dir[2], 0, 0, 0, 0, true, lifetime, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
+ CL_NewParticle(org, pt_snow, k, k, tex_particle, 1, 0, lhrandom(64, 128), 0, 0, -1, org[0], org[1], org[2], dir[0], dir[1], dir[2], 0, 0, 0, 0, true, lifetime, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
}
break;
default:
}
}
-cvar_t r_drawparticles = {CVAR_CLIENT, "r_drawparticles", "1", "enables drawing of particles"};
-static cvar_t r_drawparticles_drawdistance = {CVAR_CLIENT | CVAR_SAVE, "r_drawparticles_drawdistance", "2000", "particles further than drawdistance*size will not be drawn"};
-static cvar_t r_drawparticles_nearclip_min = {CVAR_CLIENT | CVAR_SAVE, "r_drawparticles_nearclip_min", "4", "particles closer than drawnearclip_min will not be drawn"};
-static cvar_t r_drawparticles_nearclip_max = {CVAR_CLIENT | CVAR_SAVE, "r_drawparticles_nearclip_max", "4", "particles closer than drawnearclip_min will be faded"};
-cvar_t r_drawdecals = {CVAR_CLIENT, "r_drawdecals", "1", "enables drawing of decals"};
-static cvar_t r_drawdecals_drawdistance = {CVAR_CLIENT | CVAR_SAVE, "r_drawdecals_drawdistance", "500", "decals further than drawdistance*size will not be drawn"};
+cvar_t r_drawparticles = {CF_CLIENT, "r_drawparticles", "1", "enables drawing of particles"};
+static cvar_t r_drawparticles_drawdistance = {CF_CLIENT | CF_ARCHIVE, "r_drawparticles_drawdistance", "2000", "particles further than drawdistance*size will not be drawn"};
+static cvar_t r_drawparticles_nearclip_min = {CF_CLIENT | CF_ARCHIVE, "r_drawparticles_nearclip_min", "4", "particles closer than drawnearclip_min will not be drawn"};
+static cvar_t r_drawparticles_nearclip_max = {CF_CLIENT | CF_ARCHIVE, "r_drawparticles_nearclip_max", "4", "particles closer than drawnearclip_min will be faded"};
+cvar_t r_drawdecals = {CF_CLIENT, "r_drawdecals", "1", "enables drawing of decals"};
+static cvar_t r_drawdecals_drawdistance = {CF_CLIENT | CF_ARCHIVE, "r_drawdecals_drawdistance", "500", "decals further than drawdistance*size will not be drawn"};
#define PARTICLETEXTURESIZE 64
#define PARTICLEFONTSIZE (PARTICLETEXTURESIZE*8)
if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n"))
{
- strlcpy(texturename, com_token, sizeof(texturename));
+ dp_strlcpy(texturename, com_token, sizeof(texturename));
s1 = atof(com_token);
if (COM_ParseToken_Simple(&bufptr, true, false, true) && 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));
+ dp_strlcpy(texturename, "particles/particlefont.tga", sizeof(texturename));
if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n"))
- strlcpy(texturename, com_token, sizeof(texturename));
+ dp_strlcpy(texturename, com_token, sizeof(texturename));
}
}
}
R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap, NULL, NULL);
}
-static void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
-{
- int surfacelistindex;
- const decal_t *d;
- float *v3f, *t2f, *c4f;
- particletexture_t *tex;
- vec_t right[3], up[3], size, ca;
- float alphascale = (1.0f / 65536.0f) * cl_particles_alpha.value;
-
- RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
-
- r_refdef.stats[r_stat_drawndecals] += numsurfaces;
-// R_Mesh_ResetTextureState();
- GL_DepthMask(false);
- GL_DepthRange(0, 1);
- GL_PolygonOffset(0, 0);
- GL_DepthTest(true);
- GL_CullFace(GL_NONE);
-
- // generate all the vertices at once
- for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
- {
- d = cl.decals + surfacelist[surfacelistindex];
-
- // calculate color
- c4f = particle_color4f + 16*surfacelistindex;
- ca = d->alpha * alphascale;
- // ensure alpha multiplier saturates properly
- if (ca > 1.0f / 256.0f)
- ca = 1.0f / 256.0f;
- if (r_refdef.fogenabled)
- ca *= RSurf_FogVertex(d->org);
- Vector4Set(c4f, d->color[0] * ca, d->color[1] * ca, d->color[2] * ca, 1);
- Vector4Copy(c4f, c4f + 4);
- Vector4Copy(c4f, c4f + 8);
- Vector4Copy(c4f, c4f + 12);
-
- // calculate vertex positions
- size = d->size * cl_particles_size.value;
- VectorVectors(d->normal, right, up);
- VectorScale(right, size, right);
- VectorScale(up, size, up);
- v3f = particle_vertex3f + 12*surfacelistindex;
- v3f[ 0] = d->org[0] - right[0] - up[0];
- v3f[ 1] = d->org[1] - right[1] - up[1];
- v3f[ 2] = d->org[2] - right[2] - up[2];
- v3f[ 3] = d->org[0] - right[0] + up[0];
- v3f[ 4] = d->org[1] - right[1] + up[1];
- v3f[ 5] = d->org[2] - right[2] + up[2];
- v3f[ 6] = d->org[0] + right[0] + up[0];
- v3f[ 7] = d->org[1] + right[1] + up[1];
- v3f[ 8] = d->org[2] + right[2] + up[2];
- v3f[ 9] = d->org[0] + right[0] - up[0];
- v3f[10] = d->org[1] + right[1] - up[1];
- v3f[11] = d->org[2] + right[2] - up[2];
-
- // calculate texcoords
- tex = &particletexture[d->texnum];
- t2f = particle_texcoord2f + 8*surfacelistindex;
- t2f[0] = tex->s1;t2f[1] = tex->t2;
- t2f[2] = tex->s1;t2f[3] = tex->t1;
- t2f[4] = tex->s2;t2f[5] = tex->t1;
- t2f[6] = tex->s2;t2f[7] = tex->t2;
- }
-
- // 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, 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);
-}
-
-void R_DrawDecals (void)
-{
- int i;
- int drawdecals = r_drawdecals.integer;
- decal_t *decal;
- float frametime;
- float decalfade;
- float drawdist2;
- unsigned int killsequence = cl.decalsequence - bound(0, (unsigned int) cl_decals_max.integer, cl.decalsequence);
-
- frametime = bound(0, cl.time - cl.decals_updatetime, 1);
- cl.decals_updatetime = bound(cl.time - 1, cl.decals_updatetime + frametime, cl.time + 1);
-
- // LadyHavoc: early out conditions
- if (!cl.num_decals)
- return;
-
- decalfade = frametime * 256 / cl_decals_fadetime.value;
- drawdist2 = r_drawdecals_drawdistance.value * r_refdef.view.quality;
- drawdist2 = drawdist2*drawdist2;
-
- for (i = 0, decal = cl.decals;i < cl.num_decals;i++, decal++)
- {
- if (!decal->typeindex)
- continue;
-
- if (killsequence > decal->decalsequence)
- goto killdecal;
-
- if (cl.time > decal->time2 + cl_decals_time.value)
- {
- decal->alpha -= decalfade;
- if (decal->alpha <= 0)
- goto killdecal;
- }
-
- if (decal->owner)
- {
- if (cl.entities[decal->owner].render.model == decal->ownermodel)
- {
- Matrix4x4_Transform(&cl.entities[decal->owner].render.matrix, decal->relativeorigin, decal->org);
- Matrix4x4_Transform3x3(&cl.entities[decal->owner].render.matrix, decal->relativenormal, decal->normal);
- }
- else
- goto killdecal;
- }
-
- if(cl_decals_visculling.integer && decal->clusterindex > -1000 && !CHECKPVSBIT(r_refdef.viewcache.world_pvsbits, decal->clusterindex))
- continue;
-
- if (!drawdecals)
- continue;
-
- if (!r_refdef.view.useperspective || (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(TRANSPARENTSORT_DISTANCE, decal->org, R_DrawDecal_TransparentCallback, NULL, i, NULL);
- continue;
-killdecal:
- decal->typeindex = 0;
- if (cl.free_decal > i)
- cl.free_decal = i;
- }
-
- // reduce cl.num_decals if possible
- while (cl.num_decals > 0 && cl.decals[cl.num_decals - 1].typeindex == 0)
- cl.num_decals--;
-
- if (cl.num_decals == cl.max_decals && cl.max_decals < MAX_DECALS)
- {
- decal_t *olddecals = cl.decals;
- cl.max_decals = min(cl.max_decals * 2, MAX_DECALS);
- cl.decals = (decal_t *) Mem_Alloc(cls.levelmempool, cl.max_decals * sizeof(decal_t));
- memcpy(cl.decals, olddecals, cl.num_decals * sizeof(decal_t));
- Mem_Free(olddecals);
- }
-
- 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;
float palpha, spintime, spinrad, spincos, spinsin, spinm1, spinm2, spinm3, spinm4;
vec4_t colormultiplier;
float minparticledist_start, minparticledist_end;
- qboolean dofade;
+ qbool dofade;
RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
float drawdist2;
int hitent;
trace_t trace;
- qboolean update;
+ qbool update;
+ float pt_explode_frame_interval, pt_explode2_frame_interval;
+ int color;
frametime = bound(0, cl.time - cl.particles_updatetime, 1);
cl.particles_updatetime = bound(cl.time - 1, cl.particles_updatetime + frametime, cl.time + 1);
+ // Handling of the colour ramp for pt_explode and pt_explode2
+ pt_explode_frame_interval = frametime * 10;
+ pt_explode2_frame_interval = frametime * 15;
+
// LadyHavoc: early out conditions
if (!cl.num_particles)
return;
a = CL_PointSuperContents(p->org);
if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK))
goto killparticle;
- break;
+ case pt_explode:
+ // Progress the particle colour up the ramp
+ p->time2 += pt_explode_frame_interval;
+ if (p->time2 >= 8)
+ {
+ p->die = -1;
+ }
+ else {
+ color = particlepalette[ramp1[(int)p->time2]];
+ p->color[0] = color >> 16;
+ p->color[1] = color >> 8;
+ p->color[2] = color >> 0;
+ }
+ break;
+
+ case pt_explode2:
+ // Progress the particle colour up the ramp
+ p->time2 += pt_explode2_frame_interval;
+ if (p->time2 >= 8)
+ {
+ p->die = -1;
+ }
+ else {
+ color = particlepalette[ramp2[(int)p->time2]];
+ p->color[0] = color >> 16;
+ p->color[1] = color >> 8;
+ p->color[2] = color >> 0;
+ }
+ break;
default:
break;
}