// renderparticles.cpp
#include "cube.h"
const int MAXPARTICLES = 10500;
const int NUMPARTCUTOFF = 20;
struct particle { vec o, d; int fade, type; int millis; particle *next; };
particle particles[MAXPARTICLES], *parlist = NULL, *parempty = NULL;
bool parinit = false;
VARP(maxparticles, 100, 2000, MAXPARTICLES-500);
void newparticle(vec &o, vec &d, int fade, int type)
{
if(!parinit)
{
loopi(MAXPARTICLES)
{
particles[i].next = parempty;
parempty = &particles[i];
};
parinit = true;
};
if(parempty)
{
particle *p = parempty;
parempty = p->next;
p->o = o;
p->d = d;
p->fade = fade;
p->type = type;
p->millis = lastmillis;
p->next = parlist;
parlist = p;
};
};
VAR(demotracking, 0, 0, 1);
VARP(particlesize, 20, 100, 500);
vec right, up;
void setorient(vec &r, vec &u) { right = r; up = u; };
void render_particles(int time)
{
if(demoplayback && demotracking)
{
vec nom = { 0, 0, 0 };
newparticle(player1->o, nom, 100000000, 8);
};
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA);
glDisable(GL_FOG);
struct parttype { float r, g, b; int gr, tex; float sz; } parttypes[] =
{
{ 0.7f, 0.6f, 0.3f, 2, 3, 0.06f }, // yellow: sparks
{ 0.5f, 0.5f, 0.5f, 20, 7, 0.15f }, // grey: small smoke
{ 0.2f, 0.2f, 1.0f, 20, 3, 0.08f }, // blue: edit mode entities
{ 1.0f, 0.1f, 0.1f, 1, 7, 0.06f }, // red: blood spats
{ 1.0f, 0.8f, 0.8f, 20, 6, 1.2f }, // yellow: fireball1
{ 0.5f, 0.5f, 0.5f, 20, 7, 0.6f }, // grey: big smoke
{ 1.0f, 1.0f, 1.0f, 20, 8, 1.2f }, // blue: fireball2
{ 1.0f, 1.0f, 1.0f, 20, 9, 1.2f }, // green: fireball3
{ 1.0f, 0.1f, 0.1f, 0, 7, 0.2f }, // red: demotrack
};
int numrender = 0;
for(particle *p, **pp = &parlist; p = *pp;)
{
parttype *pt = &parttypes[p->type];
glBindTexture(GL_TEXTURE_2D, pt->tex);
glBegin(GL_QUADS);
glColor3d(pt->r, pt->g, pt->b);
float sz = pt->sz*particlesize/100.0f;
// perf varray?
glTexCoord2f(0.0, 1.0); glVertex3d(p->o.x+(-right.x+up.x)*sz, p->o.z+(-right.y+up.y)*sz, p->o.y+(-right.z+up.z)*sz);
glTexCoord2f(1.0, 1.0); glVertex3d(p->o.x+( right.x+up.x)*sz, p->o.z+( right.y+up.y)*sz, p->o.y+( right.z+up.z)*sz);
glTexCoord2f(1.0, 0.0); glVertex3d(p->o.x+( right.x-up.x)*sz, p->o.z+( right.y-up.y)*sz, p->o.y+( right.z-up.z)*sz);
glTexCoord2f(0.0, 0.0); glVertex3d(p->o.x+(-right.x-up.x)*sz, p->o.z+(-right.y-up.y)*sz, p->o.y+(-right.z-up.z)*sz);
glEnd();
xtraverts += 4;
if(numrender++>maxparticles || (p->fade -= time)<0)
{
*pp = p->next;
p->next = parempty;
parempty = p;
}
else
{
if(pt->gr) p->o.z -= ((lastmillis-p->millis)/3.0f)*curtime/(pt->gr*10000);
vec a = p->d;
vmul(a,time);
vdiv(a,20000.0f);
vadd(p->o, a);
pp = &p->next;
};
};
glEnable(GL_FOG);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
};
void particle_splash(int type, int num, int fade, vec &p)
{
loopi(num)
{
const int radius = type==5 ? 50 : 150;
int x, y, z;
do
{
x = rnd(radius*2)-radius;
y = rnd(radius*2)-radius;
z = rnd(radius*2)-radius;
}
while(x*x+y*y+z*z>radius*radius);
vec d = { (float)x, (float)y, (float)z };
newparticle(p, d, rnd(fade*3), type);
};
};
void particle_trail(int type, int fade, vec &s, vec &e)
{
vdist(d, v, s, e);
vdiv(v, d*2+0.1f);
vec p = s;
loopi((int)d*2)
{
vadd(p, v);
vec d = { float(rnd(11)-5), float(rnd(11)-5), float(rnd(11)-5) };
newparticle(p, d, rnd(fade)+fade, type);
};
};