#include "quakedef.h"
#include "cl_collision.h"
-#define MAX_PARTICLES 16384 // default max # of particles at one time
+#define MAX_PARTICLES 8192 // default max # of particles at one time
#define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter what's on the command line
typedef enum
}
ptype_t;
+#define PARTICLE_INVALID 0
+#define PARTICLE_BILLBOARD 1
+#define PARTICLE_BEAM 2
+#define PARTICLE_ORIENTED_DOUBLESIDED 3
+
#define P_TEXNUM_FIRSTBIT 0
#define P_TEXNUM_BITS 6
#define P_ORIENTATION_FIRSTBIT (P_TEXNUM_FIRSTBIT + P_TEXNUM_BITS)
#define P_ORIENTATION_BITS 2
#define P_FLAGS_FIRSTBIT (P_ORIENTATION_FIRSTBIT + P_ORIENTATION_BITS)
-#define P_DYNLIGHT (1 << (P_FLAGS_FIRSTBIT + 0))
+//#define P_DYNLIGHT (1 << (P_FLAGS_FIRSTBIT + 0))
#define P_ADDITIVE (1 << (P_FLAGS_FIRSTBIT + 1))
typedef struct particle_s
partflags = ((porientation) << P_ORIENTATION_FIRSTBIT) | ((ptex) << P_TEXNUM_FIRSTBIT);\
if (padditive)\
partflags |= P_ADDITIVE;\
- if (plight)\
- partflags |= P_DYNLIGHT;\
+ /*if (plight)*/\
+ /* partflags |= P_DYNLIGHT;*/\
tempcolor = (pcolor1);\
tempcolor2 = (pcolor2);\
cr2 = ((tempcolor2) >> 16) & 0xFF;\
if (cl_stainmaps.integer)
R_Stain(org, 96, 80, 80, 80, 64, 176, 176, 176, 64);
- i = Mod_PointInLeaf(org, cl.worldmodel)->contents;
+ i = Mod_PointContents(org, cl.worldmodel);
if ((i == CONTENTS_SLIME || i == CONTENTS_WATER) && cl_particles.integer && cl_particles_bubbles.integer)
{
for (i = 0;i < 128;i++)
if (!cl_particles.integer) return;
if (cl_stainmaps.integer)
- R_Stain(org, 32, 96, 96, 96, 2, 128, 128, 128, 2);
+ R_Stain(org, 32, 96, 96, 96, 24, 128, 128, 128, 24);
if (cl_particles_bulletimpacts.integer)
{
while(count--)
{
k = particlepalette[0x68 + (rand() & 7)];
- particle(pt_static, PARTICLE_BILLBOARD, k, k, tex_particle, false, true, 1, 1, lhrandom(64, 255), 512, 9999, 1, 0, org[0], org[1], org[2], lhrandom(-64, 64) + dir[0], lhrandom(-64, 64) + dir[1], lhrandom(0, 128) + dir[2], 0, 0, 0, 0, 0, 0);
+ particle(pt_static, PARTICLE_BEAM, k, k, tex_particle, false, true, 0.4f, 0.015f, lhrandom(64, 255), 512, 9999, 1, 0, org[0], org[1], org[2], lhrandom(-64, 64) + dir[0], lhrandom(-64, 64) + dir[1], lhrandom(0, 128) + dir[2], 0, 0, 0, 0, 0, 0);
}
}
}
void CL_PlasmaBurn (vec3_t org)
{
if (cl_stainmaps.integer)
- R_Stain(org, 48, 96, 96, 96, 3, 128, 128, 128, 3);
+ R_Stain(org, 48, 96, 96, 96, 32, 128, 128, 128, 32);
}
static float bloodcount = 0;
while(count--)
{
k = particlepalette[colorbase + (rand()&3)];
- particle(pt_rain, PARTICLE_UPRIGHT_FACING, k, k, tex_particle, true, true, 0.5, 8, lhrandom(8, 16), 0, t, 0, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], cl.time + 9999, dir[0], dir[1], dir[2], 0, 0);
+ particle(pt_rain, PARTICLE_BEAM, k, k, tex_particle, true, true, 0.5, 0.02, lhrandom(8, 16), 0, t, 0, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], cl.time + 9999, dir[0], dir[1], dir[2], 0, 0);
}
break;
case 1:
// if we skip out, leave it reset
ent->persistent.trail_time = 0.0f;
- contents = Mod_PointInLeaf(pos, cl.worldmodel)->contents;
+ contents = Mod_PointContents(pos, cl.worldmodel);
if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
return;
{
// assume it's blood (lame, but...)
if (cl_stainmaps.integer)
- R_Stain(v, 32, 32, 16, 16, p->alpha * p->scalex * (1.0f / 400.0f), 192, 48, 48, p->alpha * p->scalex * (1.0f / 400.0f));
+ R_Stain(v, 32, 32, 16, 16, p->alpha * p->scalex * (1.0f / 40.0f), 192, 48, 48, p->alpha * p->scalex * (1.0f / 40.0f));
p->die = -1;
freeparticles[j++] = p;
continue;
{
f = p->friction * frametime;
if (!content)
- content = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
+ content = Mod_PointContents(p->org, cl.worldmodel);
if (content != CONTENTS_EMPTY)
f *= 4;
f = 1.0f - f;
{
case pt_blood:
if (!content)
- content = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
+ content = Mod_PointContents(p->org, cl.worldmodel);
a = content;
if (a != CONTENTS_EMPTY)
{
break;
case pt_bubble:
if (!content)
- content = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
+ content = Mod_PointContents(p->org, cl.worldmodel);
if (content != CONTENTS_WATER && content != CONTENTS_SLIME)
{
p->die = -1;
p->vel[2] = /*lhrandom(-32, 32) +*/ p->vel2[2];
}
if (!content)
- content = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
+ content = Mod_PointContents(p->org, cl.worldmodel);
a = content;
if (a != CONTENTS_EMPTY && a != CONTENTS_SKY)
p->die = -1;
static particletexture_t particletexture[MAX_PARTICLETEXTURES];
static cvar_t r_drawparticles = {0, "r_drawparticles", "1"};
-static cvar_t r_particles_lighting = {0, "r_particles_lighting", "0"};
static qbyte shadebubble(float dx, float dy, vec3_t light)
{
void R_Particles_Init (void)
{
Cvar_RegisterVariable(&r_drawparticles);
- Cvar_RegisterVariable(&r_particles_lighting);
R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap);
}
-int partindexarray[6] = {0, 1, 2, 0, 2, 3};
+void R_DrawParticleCallback(const void *calldata1, int calldata2)
+{
+ int additive, texnum, orientation;
+ float org[3], up2[3], v[3], right[3], up[3], fog, ifog, fogvec[3], cr, cg, cb, ca;
+ particletexture_t *tex;
+ rmeshstate_t m;
+ const particle_t *p = calldata1;
+
+ VectorCopy(p->org, org);
+ orientation = (p->flags >> P_ORIENTATION_FIRSTBIT) & ((1 << P_ORIENTATION_BITS) - 1);
+ texnum = (p->flags >> P_TEXNUM_FIRSTBIT) & ((1 << P_TEXNUM_BITS) - 1);
+ //dynlight = p->flags & P_DYNLIGHT;
+ additive = p->flags & P_ADDITIVE;
+
+ memset(&m, 0, sizeof(m));
+ m.blendfunc1 = GL_SRC_ALPHA;
+ if (additive)
+ m.blendfunc2 = GL_ONE;
+ else
+ m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+ m.tex[0] = R_GetTexture(particlefonttexture);
+ R_Mesh_Matrix(&r_identitymatrix);
+ R_Mesh_State(&m);
+
+ tex = &particletexture[texnum];
+ cr = p->color[0] * (1.0f / 255.0f);
+ cg = p->color[1] * (1.0f / 255.0f);
+ cb = p->color[2] * (1.0f / 255.0f);
+ ca = p->alpha * (1.0f / 255.0f);
+ if (fogenabled)
+ {
+ VectorSubtract(org, r_origin, fogvec);
+ fog = exp(fogdensity/DotProduct(fogvec,fogvec));
+ ifog = 1 - fog;
+ cr = cr * ifog;
+ cg = cg * ifog;
+ cb = cb * ifog;
+ if (!additive)
+ {
+ cr += fogcolor[0] * fog;
+ cg += fogcolor[1] * fog;
+ cb += fogcolor[2] * fog;
+ }
+ }
+ cr *= r_colorscale;
+ cg *= r_colorscale;
+ cb *= r_colorscale;
+
+ varray_color[ 0] = varray_color[ 4] = varray_color[ 8] = varray_color[12] = cr;
+ varray_color[ 1] = varray_color[ 5] = varray_color[ 9] = varray_color[13] = cg;
+ varray_color[ 2] = varray_color[ 6] = varray_color[10] = varray_color[14] = cb;
+ varray_color[ 3] = varray_color[ 7] = varray_color[11] = varray_color[15] = ca;
+ varray_texcoord[0][0] = tex->s2;varray_texcoord[0][1] = tex->t1;
+ varray_texcoord[0][2] = tex->s1;varray_texcoord[0][3] = tex->t1;
+ varray_texcoord[0][4] = tex->s1;varray_texcoord[0][5] = tex->t2;
+ varray_texcoord[0][6] = tex->s2;varray_texcoord[0][7] = tex->t2;
+
+ if (orientation == PARTICLE_BEAM)
+ {
+ VectorMA(p->org, -p->scaley, p->vel, v);
+ VectorMA(p->org, p->scaley, p->vel, up2);
+ R_CalcBeamVerts(varray_vertex, v, up2, p->scalex);
+ }
+ else if (orientation == PARTICLE_BILLBOARD)
+ {
+ VectorScale(vright, p->scalex, right);
+ VectorScale(vup, p->scaley, up);
+ varray_vertex[ 0] = org[0] + right[0] - up[0];
+ varray_vertex[ 1] = org[1] + right[1] - up[1];
+ varray_vertex[ 2] = org[2] + right[2] - up[2];
+ varray_vertex[ 4] = org[0] - right[0] - up[0];
+ varray_vertex[ 5] = org[1] - right[1] - up[1];
+ varray_vertex[ 6] = org[2] - right[2] - up[2];
+ varray_vertex[ 8] = org[0] - right[0] + up[0];
+ varray_vertex[ 9] = org[1] - right[1] + up[1];
+ varray_vertex[10] = org[2] - right[2] + up[2];
+ varray_vertex[12] = org[0] + right[0] + up[0];
+ varray_vertex[13] = org[1] + right[1] + up[1];
+ varray_vertex[14] = org[2] + right[2] + up[2];
+ }
+ else if (orientation == PARTICLE_ORIENTED_DOUBLESIDED)
+ {
+ // double-sided
+ if (DotProduct(p->vel2, r_origin) > DotProduct(p->vel2, org))
+ {
+ VectorNegate(p->vel2, v);
+ VectorVectors(v, right, up);
+ }
+ else
+ VectorVectors(p->vel2, right, up);
+ VectorScale(right, p->scalex, right);
+ VectorScale(up, p->scaley, up);
+ varray_vertex[ 0] = org[0] + right[0] - up[0];
+ varray_vertex[ 1] = org[1] + right[1] - up[1];
+ varray_vertex[ 2] = org[2] + right[2] - up[2];
+ varray_vertex[ 4] = org[0] - right[0] - up[0];
+ varray_vertex[ 5] = org[1] - right[1] - up[1];
+ varray_vertex[ 6] = org[2] - right[2] - up[2];
+ varray_vertex[ 8] = org[0] - right[0] + up[0];
+ varray_vertex[ 9] = org[1] - right[1] + up[1];
+ varray_vertex[10] = org[2] - right[2] + up[2];
+ varray_vertex[12] = org[0] + right[0] + up[0];
+ varray_vertex[13] = org[1] + right[1] + up[1];
+ varray_vertex[14] = org[2] + right[2] + up[2];
+ }
+ else
+ Host_Error("R_DrawParticles: unknown particle orientation %i\n", orientation);
+ R_Mesh_Draw(4, 2, polygonelements);
+}
void R_DrawParticles (void)
{
- int i, lighting, dynlight, additive, texnum, orientation;
- float minparticledist, org[3], uprightangles[3], up2[3], right2[3], v[3], right[3], up[3], fog, ifog, fogvec[3], cr, cg, cb, ca;
- mleaf_t *leaf;
- particletexture_t *tex;
- rmeshbufferinfo_t m;
+ int i;
+ float minparticledist;
particle_t *p;
// LordHavoc: early out conditions
if ((!cl_numparticles) || (!r_drawparticles.integer))
return;
- lighting = r_particles_lighting.integer;
- if (!r_dynamic.integer)
- lighting = 0;
-
c_particles += cl_numparticles;
- uprightangles[0] = 0;
- uprightangles[1] = r_refdef.viewangles[1];
- uprightangles[2] = 0;
- AngleVectors (uprightangles, NULL, right2, up2);
-
minparticledist = DotProduct(r_origin, vpn) + 16.0f;
+ // LordHavoc: only render if not too close
for (i = 0, p = particles;i < cl_numparticles;i++, p++)
- {
- // LordHavoc: only render if not too close
- if (DotProduct(p->org, vpn) < minparticledist)
- continue;
-
- // LordHavoc: check if it's in a visible leaf
- leaf = Mod_PointInLeaf(p->org, cl.worldmodel);
- if (leaf->visframe != r_framecount)
- continue;
-
- VectorCopy(p->org, org);
- orientation = (p->flags >> P_ORIENTATION_FIRSTBIT) & ((1 << P_ORIENTATION_BITS) - 1);
- texnum = (p->flags >> P_TEXNUM_FIRSTBIT) & ((1 << P_TEXNUM_BITS) - 1);
- dynlight = p->flags & P_DYNLIGHT;
- additive = p->flags & P_ADDITIVE;
- if (orientation == PARTICLE_BILLBOARD)
- {
- VectorScale(vright, p->scalex, right);
- VectorScale(vup, p->scaley, up);
- }
- else if (orientation == PARTICLE_UPRIGHT_FACING)
- {
- VectorScale(right2, p->scalex, right);
- VectorScale(up2, p->scaley, up);
- }
- else if (orientation == PARTICLE_ORIENTED_DOUBLESIDED)
- {
- // double-sided
- if (DotProduct(p->vel2, r_origin) > DotProduct(p->vel2, org))
- {
- VectorNegate(p->vel2, v);
- VectorVectors(v, right, up);
- }
- else
- VectorVectors(p->vel2, right, up);
- VectorScale(right, p->scalex, right);
- VectorScale(up, p->scaley, up);
- }
- else
- Host_Error("R_DrawParticles: unknown particle orientation %i\n", orientation);
-
- tex = &particletexture[texnum];
-
- cr = p->color[0] * (1.0f / 255.0f);
- cg = p->color[1] * (1.0f / 255.0f);
- cb = p->color[2] * (1.0f / 255.0f);
- ca = p->alpha * (1.0f / 255.0f);
- if (lighting >= 1 && (dynlight || lighting >= 2))
- {
- R_CompleteLightPoint(v, org, true, leaf);
- cr *= v[0];
- cg *= v[1];
- cb *= v[2];
- }
-
- if (fogenabled)
- {
- VectorSubtract(org, r_origin, fogvec);
- fog = exp(fogdensity/DotProduct(fogvec,fogvec));
- ifog = 1 - fog;
- cr = cr * ifog;
- cg = cg * ifog;
- cb = cb * ifog;
- if (!additive)
- {
- cr += fogcolor[0] * fog;
- cg += fogcolor[1] * fog;
- cb += fogcolor[2] * fog;
- }
- }
-
- memset(&m, 0, sizeof(m));
- m.transparent = true;
- m.blendfunc1 = GL_SRC_ALPHA;
- if (additive)
- m.blendfunc2 = GL_ONE;
- else
- m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
- m.numtriangles = 2;
- m.numverts = 4;
- m.tex[0] = R_GetTexture(particlefonttexture);
- if (R_Mesh_Draw_GetBuffer(&m, false))
- {
- m.index[0] = 0;
- m.index[1] = 1;
- m.index[2] = 2;
- m.index[3] = 0;
- m.index[4] = 2;
- m.index[5] = 3;
- m.vertex[0] = org[0] - right[0] - up[0];
- m.vertex[1] = org[1] - right[1] - up[1];
- m.vertex[2] = org[2] - right[2] - up[2];
- m.vertex[4] = org[0] - right[0] + up[0];
- m.vertex[5] = org[1] - right[1] + up[1];
- m.vertex[6] = org[2] - right[2] + up[2];
- m.vertex[8] = org[0] + right[0] + up[0];
- m.vertex[9] = org[1] + right[1] + up[1];
- m.vertex[10] = org[2] + right[2] + up[2];
- m.vertex[12] = org[0] + right[0] - up[0];
- m.vertex[13] = org[1] + right[1] - up[1];
- m.vertex[14] = org[2] + right[2] - up[2];
- m.texcoords[0][0] = tex->s1;
- m.texcoords[0][1] = tex->t1;
- m.texcoords[0][2] = tex->s1;
- m.texcoords[0][3] = tex->t2;
- m.texcoords[0][4] = tex->s2;
- m.texcoords[0][5] = tex->t2;
- m.texcoords[0][6] = tex->s2;
- m.texcoords[0][7] = tex->t1;
- m.color[0] = m.color[4] = m.color[8] = m.color[12] = cr * m.colorscale;
- m.color[1] = m.color[5] = m.color[9] = m.color[13] = cg * m.colorscale;
- m.color[2] = m.color[6] = m.color[10] = m.color[14] = cb * m.colorscale;
- m.color[3] = m.color[7] = m.color[11] = m.color[15] = ca;
- R_Mesh_Render();
- }
- }
+ if (DotProduct(p->org, vpn) >= minparticledist)
+ R_MeshQueue_AddTransparent(p->org, R_DrawParticleCallback, p, 0);
}