Code: Select all
ptime = cl.time - p->spawntime;
neworg[0] = p->org[0] + (p->vel[0] + (p->dvel[0] * ptime)) * ptime;
neworg[1] = p->org[1] + (p->vel[1] + (p->dvel[1] * ptime)) * ptime;
neworg[2] = p->org[2] + (p->vel[2] + (p->dvel[2] * ptime) + (ptime * grav * p->grav)) * ptime;
There are a few new things here.
p->spawntime is just the value of cl.time when the particle is spawned.
p->dvel is normally 0 but can have values depending on the emitter (explosions, generally) - pull these from the old type handling (which can otherwise be mostly removed).
grav is sv_gravity.value * 0.05
p->grav is 1 for particles that go up (rocket/grenade trails), -1 for particles that go down (most types) or 0 for particles that are unaffected by gravity.
Full drawing code (GL 3.x+ needed):
Code: Select all
extern cvar_t sv_gravity;
typedef struct partinst_s
{
float org[3];
union
{
unsigned color;
byte rgba[4];
};
} partinst_t;
typedef struct partvert_s
{
float st[2];
} partvert_t;
#define MAX_PART_INST 16384
partinst_t partinsts[MAX_PART_INST];
partvert_t partverts[4] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};
void R_DrawParticles (void)
{
particle_t *p, *kill;
float grav = sv_gravity.value * 0.05;
float ptime;
int numinst = 0;
// kill any particles at the head of the list
for (;;)
{
kill = active_particles;
if (kill && kill->die < cl.time)
{
active_particles = kill->next;
kill->next = free_particles;
free_particles = kill;
continue;
}
break;
}
if (!active_particles) return;
GL_BindProgram (gl_particleprog);
glUniform3fv (u_partrorigin, 1, r_origin);
glUniform3fv (u_partvpn, 1, vpn);
glUniform3fv (u_partvright, 1, vright);
glUniform3fv (u_partvup, 1, vup);
glEnable (GL_BLEND);
glDepthMask (GL_FALSE);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, sizeof (partinst_t), partinsts[0].org);
glVertexAttribPointer (1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof (partinst_t), partinsts[0].rgba);
glVertexAttribPointer (2, 2, GL_FLOAT, GL_FALSE, sizeof (partvert_t), partverts->st);
glVertexAttribDivisor (0, 1);
glVertexAttribDivisor (1, 1);
for (numinst = 0, p = active_particles; p; p = p->next, numinst++)
{
// kill any particles in the middle of the list
for (;;)
{
kill = p->next;
if (kill && kill->die < cl.time)
{
p->next = kill->next;
kill->next = free_particles;
free_particles = kill;
continue;
}
break;
}
if (numinst == MAX_PART_INST)
{
glDrawArraysInstanced (GL_TRIANGLE_STRIP, 0, 4, numinst);
c_draw_calls++;
numinst = 0;
}
ptime = cl.time - p->spawntime;
partinsts[numinst].org[0] = p->org[0] + (p->vel[0] + (p->dvel[0] * ptime)) * ptime;
partinsts[numinst].org[1] = p->org[1] + (p->vel[1] + (p->dvel[1] * ptime)) * ptime;
partinsts[numinst].org[2] = p->org[2] + (p->vel[2] + (p->dvel[2] * ptime) + (ptime * grav * p->grav)) * ptime;
partinsts[numinst].color = d_8to24table[(int) p->color];
if (p->baseramp)
{
float ramptime = p->ramp + ptime * p->ramptime;
int ramp = (int) ramptime;
if (ramp > 10 || p->baseramp[ramp] == 0xff)
p->die = -1;
else p->color = p->baseramp[ramp];
}
}
if (numinst)
{
glDrawArraysInstanced (GL_TRIANGLE_STRIP, 0, 4, numinst);
c_draw_calls++;
}
glVertexAttribDivisor (0, 0);
glVertexAttribDivisor (1, 0);
glDepthMask (GL_TRUE);
glDisable (GL_BLEND);
}
Code: Select all
uniform vec3 r_origin;
uniform vec3 vpn;
uniform vec3 vright;
uniform vec3 vup;
layout(location = 0) in vec4 position;
layout(location = 1) in vec4 color;
layout(location = 2) in vec4 texcoord;
void main ()
{
float scale = (1.0 + dot (position.xyz - r_origin, vpn) * 0.004) * 0.666;
gl_Position = gl_ModelViewProjectionMatrix * vec4 (position.xyz + (vright * scale * texcoord.t) + (vup * scale * texcoord.s), 1.0);
gl_FrontColor = color;
gl_TexCoord[0] = texcoord;
}
void main ()
{
vec4 color = gl_Color;
color.a = (1.0 - dot (gl_TexCoord[0].st, gl_TexCoord[0].st)) * 1.5;
gl_FragColor = color * gl_Color.a;
}