X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=r_part.c;h=ba99439922ed195e33183534dfcaa6889b02d71d;hb=64c4623de94bb0d3f0efe02361f1e8368efb047d;hp=914e54ea029a5ea151e763526fa668bf259dcb4b;hpb=5c41d784306266a94c8caf92c6ea2680f98a5e01;p=xonotic%2Fdarkplaces.git diff --git a/r_part.c b/r_part.c index 914e54ea..ba994399 100644 --- a/r_part.c +++ b/r_part.c @@ -20,34 +20,54 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -#define MAX_PARTICLES 4096 // default max # of particles at one - // time -#define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter what's - // on the command line +#define MAX_PARTICLES 4096 // default max # of particles at one time +#define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter what's on the command line + +// LordHavoc: added dust, smoke, snow, bloodcloud, and many others +typedef enum { + pt_static, pt_grav, pt_blob, pt_blob2, pt_smoke, pt_snow, pt_bloodcloud, pt_fallfadespark, pt_bubble, pt_fade, pt_smokecloud +} ptype_t; + +typedef struct particle_s +{ + vec3_t org; + float color; + vec3_t vel; + float die; + ptype_t type; + // LordHavoc: added for improved particle effects + float scale; + short texnum; + float alpha; // 0-255 + float time2; // used for various things (snow fluttering, for example) + vec3_t vel2; // used for snow fluttering (base velocity, wind for instance) +} particle_t; int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61}; int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66}; -int ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3}; +int ramp3[8] = {0x6d, 0x6b, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; int particletexture; int smokeparticletexture[8]; -int flareparticletexture; int rainparticletexture; -int bloodcloudparticletexture; int bubbleparticletexture; -particle_t *active_particles, *free_particles; - particle_t *particles; int r_numparticles; vec3_t r_pright, r_pup, r_ppn; -cvar_t r_particles = {"r_particles", "1"}; -cvar_t r_dynamicparticles = {"r_dynamicparticles", "1"}; +int numparticles; +particle_t **freeparticles; // list used only in compacting particles array -void fractalnoise(char *noise, int size); -void fractalnoise_zeroedge(char *noise, int size); +// LordHavoc: reduced duplicate code, and allow particle allocation system independence +#define ALLOCPARTICLE \ + if (numparticles >= r_numparticles)\ + return;\ + p = &particles[numparticles++]; + +cvar_t r_particles = {"r_particles", "1"}; +cvar_t r_dynamicparticles = {"r_dynamicparticles", "0", TRUE}; void R_InitParticleTexture (void) { @@ -56,9 +76,6 @@ void R_InitParticleTexture (void) byte data[32][32][4], noise1[32][32], noise2[32][32]; vec3_t normal, light; - particletexture = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, particletexture); - for (x=0 ; x<32 ; x++) { for (y=0 ; y<32 ; y++) @@ -71,13 +88,7 @@ void R_InitParticleTexture (void) data[y][x][3] = (byte) d; } } - glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - + particletexture = GL_LoadTexture ("particletexture", 32, 32, &data[0][0][0], true, true, 4); for (i = 0;i < 8;i++) { @@ -103,83 +114,8 @@ void R_InitParticleTexture (void) data[y][x][3] = 0; } - /* - for (x=0 ; x<34 ; x+=2) - for (y=0 ; y<34 ; y+=2) - data[y][x][0] = data[y][x][1] = data[y][x][2] = (rand()%32)+192; - for (x=0 ; x<32 ; x+=2) - for (y=0 ; y<32 ; y+=2) - { - data[y ][x+1][0] = data[y ][x+1][1] = data[y ][x+1][2] = (int) (data[y ][x ][0] + data[y ][x+2][0]) >> 1; - data[y+1][x ][0] = data[y+1][x ][1] = data[y+1][x ][2] = (int) (data[y ][x ][0] + data[y+2][x ][0]) >> 1; - data[y+1][x+1][0] = data[y+1][x+1][1] = data[y+1][x+1][2] = (int) (data[y ][x ][0] + data[y ][x+2][0] + data[y+2][x ][0] + data[y+2][x+2][0]) >> 2; - } - for (x=0 ; x<32 ; x++) - { - for (y=0 ; y<32 ; y++) - { - //data[y][x][0] = data[y][x][1] = data[y][x][2] = (rand()%192)+32; - dx = x - 16; - dy = y - 16; - d = (255 - (dx*dx+dy*dy)); - if (d < 0) d = 0; - data[y][x][3] = (byte) d; - } - } - */ - smokeparticletexture[i] = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, smokeparticletexture[i]); - glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - fractalnoise(&noise1[0][0], 32); - fractalnoise(&noise2[0][0], 32); - for (y = 0;y < 32;y++) - for (x = 0;x < 32;x++) - { - data[y][x][0] = data[y][x][1] = data[y][x][2] = (noise1[y][x] >> 1) + 128; - dx = x - 16; - dy = y - 16; - d = (noise2[y][x] * (255 - (dx*dx+dy*dy))) * (1.0f / 255.0f); - if (d < 0) d = 0; - if (d > 255) d = 255; - data[y][x][3] = (byte) d; - } - - bloodcloudparticletexture = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, bloodcloudparticletexture); - glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - flareparticletexture = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, flareparticletexture); - - for (x=0 ; x<32 ; x++) - { - for (y=0 ; y<32 ; y++) - { - data[y][x][0] = data[y][x][1] = data[y][x][2] = 255; - dx = x - 16; - dy = y - 16; - d = 2048 / (dx*dx+dy*dy+1) - 32; - d = bound(0, d, 255); - data[y][x][3] = (byte) d; - } + smokeparticletexture[i] = GL_LoadTexture (va("smokeparticletexture%d", i), 32, 32, &data[0][0][0], true, true, 4); } - glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - rainparticletexture = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, rainparticletexture); for (x=0 ; x<32 ; x++) { @@ -202,15 +138,7 @@ void R_InitParticleTexture (void) data[y][x][3] = (byte) d; } } - glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - bubbleparticletexture = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, bubbleparticletexture); + rainparticletexture = GL_LoadTexture ("rainparticletexture", 32, 32, &data[0][0][0], true, true, 4); light[0] = 1;light[1] = 1;light[2] = 1; VectorNormalize(light); @@ -249,12 +177,20 @@ void R_InitParticleTexture (void) data[y][x][3] = 0; } } - glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + bubbleparticletexture = GL_LoadTexture ("bubbleparticletexture", 32, 32, &data[0][0][0], true, true, 4); +} - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +void r_part_start() +{ + particles = (particle_t *) malloc (r_numparticles * sizeof(particle_t)); + freeparticles = (void *) malloc (r_numparticles * sizeof(particle_t *)); + R_InitParticleTexture (); +} - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +void r_part_shutdown() +{ + free(particles); + free(freeparticles); } /* @@ -262,7 +198,7 @@ void R_InitParticleTexture (void) R_InitParticles =============== */ -void R_InitParticles (void) +void R_Particles_Init (void) { int i; @@ -279,12 +215,119 @@ void R_InitParticles (void) r_numparticles = MAX_PARTICLES; } - particles = (particle_t *) Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles"); - Cvar_RegisterVariable (&r_particles); Cvar_RegisterVariable (&r_dynamicparticles); - R_InitParticleTexture (); + + R_RegisterModule("R_Particles", r_part_start, r_part_shutdown); +} + +#define particle(ptype, pcolor, ptex, pscale, palpha, ptime, px, py, pz, pvx, pvy, pvz)\ +{\ + particle_t *p;\ + ALLOCPARTICLE\ + p->type = (ptype);\ + p->color = (pcolor);\ + p->texnum = (ptex);\ + p->scale = (pscale);\ + p->alpha = (palpha);\ + p->die = cl.time + (ptime);\ + p->org[0] = (px);\ + p->org[1] = (py);\ + p->org[2] = (pz);\ + p->vel[0] = (pvx);\ + p->vel[1] = (pvy);\ + p->vel[2] = (pvz);\ } +#define particle2(ptype, pcolor, ptex, pscale, palpha, ptime, pbase, poscale, pvscale)\ +{\ + particle_t *p;\ + ALLOCPARTICLE\ + p->type = (ptype);\ + p->color = (pcolor);\ + p->texnum = (ptex);\ + p->scale = (pscale);\ + p->alpha = (palpha);\ + p->die = cl.time + (ptime);\ + p->org[0] = lhrandom(-(poscale), (poscale)) + (pbase)[0];\ + p->org[1] = lhrandom(-(poscale), (poscale)) + (pbase)[1];\ + p->org[2] = lhrandom(-(poscale), (poscale)) + (pbase)[2];\ + p->vel[0] = lhrandom(-(pvscale), (pvscale));\ + p->vel[1] = lhrandom(-(pvscale), (pvscale));\ + p->vel[2] = lhrandom(-(pvscale), (pvscale));\ +} +#define particle3(ptype, pcolor, ptex, pscale, palpha, ptime, pbase, pscalex, pscaley, pscalez, pvscalex, pvscaley, pvscalez)\ +{\ + particle_t *p;\ + ALLOCPARTICLE\ + p->type = (ptype);\ + p->color = (pcolor);\ + p->texnum = (ptex);\ + p->scale = (pscale);\ + p->alpha = (palpha);\ + p->die = cl.time + (ptime);\ + p->org[0] = lhrandom(-(pscalex), (pscalex)) + (pbase)[0];\ + p->org[1] = lhrandom(-(pscaley), (pscaley)) + (pbase)[1];\ + p->org[2] = lhrandom(-(pscalez), (pscalez)) + (pbase)[2];\ + p->vel[0] = lhrandom(-(pvscalex), (pvscalex));\ + p->vel[1] = lhrandom(-(pvscaley), (pvscaley));\ + p->vel[2] = lhrandom(-(pvscalez), (pvscalez));\ +} +/* +void particle(int type, int color, int tex, float scale, int alpha, float time, float x, float y, float z, float vx, float vy, float vz) +{ + particle_t *p; + ALLOCPARTICLE + + p->type = type; + p->color = color; + p->texnum = tex; + p->scale = scale; + p->alpha = alpha; + p->die = cl.time + time; + p->org[0] = x; + p->org[1] = y; + p->org[2] = z; + p->vel[0] = vx; + p->vel[1] = vy; + p->vel[2] = vz; +} +void particle2(int type, int color, int tex, float scale, int alpha, float time, vec3_t base, float oscale, float vscale) +{ + particle_t *p; + ALLOCPARTICLE + + p->type = type; + p->color = color; + p->texnum = tex; + p->scale = scale; + p->alpha = alpha; + p->die = cl.time + time; + p->org[0] = lhrandom(-oscale, oscale) + base[0]; + p->org[1] = lhrandom(-oscale, oscale) + base[1]; + p->org[2] = lhrandom(-oscale, oscale) + base[2]; + p->vel[0] = lhrandom(-vscale, vscale); + p->vel[1] = lhrandom(-vscale, vscale); + p->vel[2] = lhrandom(-vscale, vscale); +} +void particle3(int type, int color, int tex, float scale, int alpha, float time, vec3_t base, float scalex, float scaley, float scalez, float vscalex, float vscaley, float vscalez) +{ + particle_t *p; + ALLOCPARTICLE + + p->type = type; + p->color = color; + p->texnum = tex; + p->scale = scale; + p->alpha = alpha; + p->die = cl.time + time; + p->org[0] = lhrandom(-scalex, scalex) + base[0]; + p->org[1] = lhrandom(-scaley, scaley) + base[1]; + p->org[2] = lhrandom(-scalez, scalez) + base[2]; + p->vel[0] = lhrandom(-vscalex, vscalex); + p->vel[1] = lhrandom(-vscaley, vscaley); + p->vel[2] = lhrandom(-vscalez, vscalez); +} +*/ /* =============== @@ -304,9 +347,8 @@ void R_EntityParticles (entity_t *ent) { int count; int i; - particle_t *p; float angle; - float sr, sp, sy, cr, cp, cy; + float sp, sy, cp, cy; vec3_t forward; float dist; if (!r_particles.value) return; // LordHavoc: particles are optional @@ -314,12 +356,9 @@ void R_EntityParticles (entity_t *ent) dist = 64; count = 50; -if (!avelocities[0][0]) -{ -for (i=0 ; inext; - p->next = active_particles; - active_particles = p; - - p->texnum = flareparticletexture; - p->scale = 2; - p->alpha = 255; - p->die = cl.time + 0.01; - p->color = 0x6f; - p->type = pt_explode; - - p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength; - p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength; - p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength; + particle(pt_static, 0x6f, particletexture, 2, 255, 0, ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength, ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength, ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength, 0, 0, 0); } } @@ -365,14 +385,15 @@ R_ClearParticles */ void R_ClearParticles (void) { - int i; - - free_particles = &particles[0]; - active_particles = NULL; +// int i; +// free_particles = &particles[0]; +// active_particles = NULL; - for (i=0 ;i= r_numparticles) { Con_Printf ("Not enough free particles\n"); break; } - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - p->texnum = particletexture; - p->scale = 2; - p->alpha = 255; - p->die = 99999; - p->color = (-c)&15; - p->type = pt_static; - VectorCopy (vec3_origin, p->vel); - VectorCopy (org, p->org); + particle(pt_static, (-c)&15, particletexture, 2, 255, 99999, org[0], org[1], org[2], 0, 0, 0); } fclose (f); @@ -462,63 +470,15 @@ R_ParticleExplosion */ void R_ParticleExplosion (vec3_t org, int smoke) { - int i, j; - particle_t *p; + int i; if (!r_particles.value) return; // LordHavoc: particles are optional - - for (i=0 ; i<1024 ; i++) - { - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->texnum = particletexture; - p->scale = lhrandom(1,3); - p->alpha = rand()&255; - p->die = cl.time + 5; - p->color = ramp1[0]; - p->ramp = lhrandom(0, 4); -// if (i & 1) -// p->type = pt_explode; -// else -// p->type = pt_explode2; - p->color = ramp1[rand()&7]; - p->type = pt_fallfadespark; - for (j=0 ; j<3 ; j++) - { - p->org[j] = org[j] + ((rand()&15)-8); - p->vel[j] = lhrandom(-192, 192); - } - p->vel[2] += 160; - } + particle(pt_smokecloud, (rand()&7) + 8, smokeparticletexture[rand()&7], 30, 96, 2, org[0], org[1], org[2], 0, 0, 0); - if (smoke) - { + i = Mod_PointInLeaf(org, cl.worldmodel)->contents; + if (i == CONTENTS_SLIME || i == CONTENTS_WATER) for (i=0 ; i<32 ; i++) - { - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - p->texnum = smokeparticletexture[rand()&7]; - p->scale = 12; - p->alpha = 80; - p->die = cl.time + 2; - p->type = pt_smoke; - p->color = (rand()&7) + 8; - for (j=0 ; j<3 ; j++) - { - p->org[j] = org[j] + ((rand()%96)-48); - p->vel[j] = (rand()&63)-32; - } - } - } + particle2(pt_bubble, (rand()&3) + 12, bubbleparticletexture, lhrandom(1, 2), 255, 2, org, 16, 16); } /* @@ -529,34 +489,11 @@ R_ParticleExplosion2 */ void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength) { - int i, j; - particle_t *p; - int colorMod = 0; + int i; if (!r_particles.value) return; // LordHavoc: particles are optional - for (i=0; i<512; i++) - { - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - p->texnum = smokeparticletexture[rand()&7]; - p->scale = 1.5; - p->alpha = 255; - p->die = cl.time + 0.3; - p->color = colorStart + (colorMod % colorLength); - colorMod++; - - p->type = pt_blob; - for (j=0 ; j<3 ; j++) - { - p->org[j] = org[j] + ((rand()&15)-8); - p->vel[j] = lhrandom(-192, 192); - } - } + for (i = 0;i < 512;i++) + particle2(pt_fade, colorStart + (i % colorLength), particletexture, 1.5, 255, 0.3, org, 8, 192); } /* @@ -567,47 +504,13 @@ R_BlobExplosion */ void R_BlobExplosion (vec3_t org) { - int i, j; - particle_t *p; + int i; if (!r_particles.value) return; // LordHavoc: particles are optional - for (i=0 ; i<1024 ; i++) - { - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - p->texnum = smokeparticletexture[rand()&7]; - p->scale = 2; - p->alpha = 255; - p->die = cl.time + 1 + (rand()&8)*0.05; - - if (i & 1) - { - p->type = pt_blob; - p->color = 66 + rand()%6; - for (j=0 ; j<3 ; j++) - { - p->org[j] = org[j] + ((rand()%32)-16); - p->vel[j] = lhrandom(-128, 128); - } - } - else - { - p->type = pt_blob2; - p->color = 150 + rand()%6; - for (j=0 ; j<3 ; j++) - { - p->org[j] = org[j] + ((rand()%32)-16); - p->vel[j] = lhrandom(-128, 128); - } - } - p->vel[0] *= 0.25; - p->vel[1] *= 0.25; - } + for (i=0 ; i<512 ; i++) + particle3(pt_blob, 66+(rand()%6), particletexture, 2, 255, lhrandom(1, 1.4), org, 16, 16, 16, 4, 4, 128); + for (i=0 ; i<512 ; i++) + particle3(pt_blob2, 150+(rand()%6), particletexture, 2, 255, lhrandom(1, 1.4), org, 16, 16, 16, 4, 4, 128); } /* @@ -618,8 +521,6 @@ R_RunParticleEffect */ void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count) { - int j; - particle_t *p; if (!r_particles.value) return; // LordHavoc: particles are optional if (count == 1024) @@ -627,124 +528,44 @@ void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count) R_ParticleExplosion(org, false); return; } - while (count) + color &= ~7; + if (count & 7) { - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - if (count & 7) - { - p->alpha = (count & 7) * 16 + (rand()&15); - count &= ~7; - } - else - { - p->alpha = 128; - count -= 8; - } - - p->texnum = particletexture; - p->scale = 6; - p->die = cl.time + 1; //lhrandom(0.1, 0.5); - p->color = (color&~7) + (rand()&7); - p->type = pt_fade; //static; //slowgrav; - for (j=0 ; j<3 ; j++) - { - p->org[j] = org[j] + ((rand()&15)-8); - p->vel[j] = dir[j]*15;// + (rand()%300)-150; - } + particle2(pt_fade, color + (rand()&7), particletexture, 6, (count & 7) * 16 + (rand()&15), 1, org, 8, 15); + count &= ~7; } + count >>= 3; + while (count--) + particle2(pt_fade, color + (rand()&7), particletexture, 6, 128, 1, org, 8, 15); } // LordHavoc: added this for spawning sparks/dust (which have strong gravity) /* =============== R_SparkShower - =============== */ -void R_SparkShower (vec3_t org, vec3_t dir, int count, int type) +void R_SparkShower (vec3_t org, vec3_t dir, int count) { - int i, j; - particle_t *p; if (!r_particles.value) return; // LordHavoc: particles are optional - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - if (type == 0) // sparks - { - p->texnum = smokeparticletexture[rand()&7]; - p->scale = 15; - p->alpha = 64; - p->color = (rand()&3)+12; - p->type = pt_bulletpuff; - p->die = cl.time + 1; - VectorCopy(org, p->org); - p->vel[0] = p->vel[1] = p->vel[2] = 0; - } - else // blood - { - p->texnum = smokeparticletexture[rand()&7]; - p->scale = 12; - p->alpha = 128; - p->color = (rand()&3)+68; - p->type = pt_bloodcloud; - p->die = cl.time + 0.5; - VectorCopy(org, p->org); - p->vel[0] = p->vel[1] = p->vel[2] = 0; - return; - } - for (i=0 ; inext; - p->next = active_particles; - active_particles = p; - - p->texnum = flareparticletexture; - p->scale = 2; - p->alpha = 255; - p->die = cl.time + 0.0625 * (rand()&15); - /* - if (type == 0) // sparks - { - */ - p->type = pt_dust; - p->ramp = (rand()&3); - p->color = ramp1[(int)p->ramp]; - for (j=0 ; j<3 ; j++) - { - p->org[j] = org[j] + ((rand()&7)-4); - p->vel[j] = dir[j] + (rand()%192)-96; - } - /* - } - else // blood - { - p->type = pt_fadespark2; - p->color = 67 + (rand()&3); - for (j=0 ; j<3 ; j++) - { - p->org[j] = org[j] + (rand()&7)-4; - p->vel[j] = dir[j] + (rand()&63)-32; - } - } - */ - } + // smoke puff + particle(pt_smokecloud, 12+(rand()&3), smokeparticletexture[rand()&7], 8, 64, 99, org[0], org[1], org[2], 0, 0, 0); + // sparks + while(count--) + particle2(pt_fallfadespark, ramp3[rand()%6], particletexture, 1, lhrandom(0, 255), 5, org, 4, 96); +} + +void R_BloodPuff (vec3_t org) +{ + if (!r_particles.value) return; // LordHavoc: particles are optional + + particle(pt_bloodcloud, 68+(rand()&3), smokeparticletexture[rand()&7], 12, 128, 99, org[0], org[1], org[2], 0, 0, 0); } void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count) { - int i, j; + int j; particle_t *p; vec3_t diff; vec3_t center; @@ -755,26 +576,21 @@ void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count) center[0] = (mins[0] + maxs[0]) * 0.5; center[1] = (mins[1] + maxs[1]) * 0.5; center[2] = (mins[2] + maxs[2]) * 0.5; - velscale[0] = velspeed * 2.0 / diff[0]; - velscale[1] = velspeed * 2.0 / diff[1]; - velscale[2] = velspeed * 2.0 / diff[2]; + // FIXME: change velspeed back to 2.0x after fixing mod + velscale[0] = velspeed * 0.5 / diff[0]; + velscale[1] = velspeed * 0.5 / diff[1]; + velscale[2] = velspeed * 0.5 / diff[2]; - for (i=0 ; inext; - p->next = active_particles; - active_particles = p; - - p->texnum = bloodcloudparticletexture; - p->scale = 12; + ALLOCPARTICLE + + p->texnum = smokeparticletexture[rand()&7]; + p->scale = lhrandom(6, 8); p->alpha = 96 + (rand()&63); - p->die = cl.time + 2; //0.015625 * (rand()%128); - p->type = pt_fadespark; + p->die = cl.time + 2; + p->type = pt_bloodcloud; p->color = (rand()&3)+68; -// p->color = 67 + (rand()&3); for (j=0 ; j<3 ; j++) { p->org[j] = diff[j] * (float) (rand()%1024) * (1.0 / 1024.0) + mins[j]; @@ -785,7 +601,7 @@ void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count) void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel) { - int i, j; + int j; particle_t *p; vec3_t diff; float t; @@ -796,16 +612,11 @@ void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb VectorSubtract(maxs, mins, diff); - for (i=0 ; inext; - p->next = active_particles; - active_particles = p; - - p->texnum = flareparticletexture; + ALLOCPARTICLE + + p->texnum = particletexture; p->scale = 6; p->alpha = 255; p->die = cl.time + 1 + (rand()&15)*0.0625; @@ -855,12 +666,7 @@ void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb for (i=0 ; inext; - p->next = active_particles; - active_particles = p; + ALLOCPARTICLE vel[0] = dir[0] + (rand()&31) - 16; vel[1] = dir[1] + (rand()&31) - 16; @@ -898,42 +704,36 @@ R_LavaSplash */ void R_LavaSplash (vec3_t org) { - int i, j, k; + int i, j; particle_t *p; float vel; vec3_t dir; if (!r_particles.value) return; // LordHavoc: particles are optional - for (i=-16 ; i<16 ; i+=2) - for (j=-16 ; j<16 ; j+=2) - for (k=0 ; k<1 ; k++) - { - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; + for (i=-128 ; i<128 ; i+=16) + for (j=-128 ; j<128 ; j+=16) + { + ALLOCPARTICLE - p->texnum = flareparticletexture; - p->scale = 10; - p->alpha = 128; - p->die = cl.time + 2 + (rand()&31) * 0.02; - p->color = 224 + (rand()&7); - p->type = pt_slowgrav; - - dir[0] = j*8 + (rand()&7); - dir[1] = i*8 + (rand()&7); - dir[2] = 256; - - p->org[0] = org[0] + dir[0]; - p->org[1] = org[1] + dir[1]; - p->org[2] = org[2] + (rand()&63); - - VectorNormalize (dir); - vel = 50 + (rand()&63); - VectorScale (dir, vel, p->vel); - } + p->texnum = particletexture; + p->scale = 10; + p->alpha = 128; + p->die = cl.time + 2 + (rand()&31) * 0.02; + p->color = 224 + (rand()&7); + p->type = pt_grav; + + dir[0] = j + (rand()&7); + dir[1] = i + (rand()&7); + dir[2] = 256; + + p->org[0] = org[0] + dir[0]; + p->org[1] = org[1] + dir[1]; + p->org[2] = org[2] + (rand()&63); + + VectorNormalize (dir); + vel = 50 + (rand()&63); + VectorScale (dir, vel, p->vel); + } } /* @@ -946,60 +746,20 @@ void R_TeleportSplash (vec3_t org) { int i, j, k; particle_t *p; -// vec3_t dir; if (!r_particles.value) return; // LordHavoc: particles are optional - /* - for (i=-16 ; i<16 ; i+=4) - for (j=-16 ; j<16 ; j+=4) - for (k=-24 ; k<32 ; k+=4) - { - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - p->contents = 0; - p->texnum = particletexture; - p->scale = 2; - p->alpha = 255; - p->die = cl.time + 0.2 + (rand()&7) * 0.02; - p->color = 7 + (rand()&7); - p->type = pt_slowgrav; - - dir[0] = j*8; - dir[1] = i*8; - dir[2] = k*8; - - p->org[0] = org[0] + i + (rand()&3); - p->org[1] = org[1] + j + (rand()&3); - p->org[2] = org[2] + k + (rand()&3); - - VectorNormalize (dir); - vel = 50 + (rand()&63); - VectorScale (dir, vel, p->vel); - } - */ - - for (i=-24 ; i<24 ; i+=8) - for (j=-24 ; j<24 ; j+=8) + for (i=-16 ; i<16 ; i+=8) + for (j=-16 ; j<16 ; j+=8) for (k=-24 ; k<32 ; k+=8) { - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; + ALLOCPARTICLE - p->texnum = flareparticletexture; - p->scale = 4; - p->alpha = lhrandom(32,256); + p->texnum = particletexture; + p->scale = 1; + p->alpha = lhrandom(32,128); p->die = cl.time + 5; - p->color = 254; //8 + (rand()&7); - p->type = pt_fadespark; + p->color = 254; + p->type = pt_fade; p->org[0] = org[0] + i + (rand()&7); p->org[1] = org[1] + j + (rand()&7); @@ -1043,12 +803,7 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) while (t < nt) { - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; + ALLOCPARTICLE p->vel[0] = p->vel[1] = p->vel[2] = 0; p->die = cl.time + 2; @@ -1076,7 +831,7 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) { dec = 0.02f; p->texnum = smokeparticletexture[rand()&7]; - p->scale = lhrandom(6, 10); + p->scale = lhrandom(8, 12); p->alpha = 64 + (rand()&31); p->color = (rand()&3)+12; p->type = pt_smoke; @@ -1102,13 +857,14 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) */ case 2: // blood + case 4: // slight blood dec = 0.025f; p->texnum = smokeparticletexture[rand()&7]; p->scale = lhrandom(6, 8); - p->alpha = 255; + p->alpha = type == 4 ? 192 : 255; p->color = (rand()&3)+68; p->type = pt_bloodcloud; - p->die = cl.time + 2; + p->die = cl.time + 9999; for (j=0 ; j<3 ; j++) { p->vel[j] = (rand()&15)-8; @@ -1118,45 +874,14 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) case 3: case 5: // tracer - dec = 0.01f; - p->texnum = flareparticletexture; - p->scale = 2; - p->alpha = 255; - p->die = cl.time + 0.2; //5; - p->type = pt_static; - if (type == 3) - p->color = 52 + ((tracercount&4)<<1); - else - p->color = 230 + ((tracercount&4)<<1); - - tracercount++; - - VectorCopy (start, p->org); - if (tracercount & 1) - { - p->vel[0] = 30*vec[1]; - p->vel[1] = 30*-vec[0]; - } - else - { - p->vel[0] = 30*-vec[1]; - p->vel[1] = 30*vec[0]; - } - break; - - case 4: // slight blood - dec = 0.025f; // sparse trail + dec = 0.02f; p->texnum = smokeparticletexture[rand()&7]; - p->scale = lhrandom(6, 8); - p->alpha = 192; - p->color = (rand()&3)+68; - p->type = pt_fadespark2; - p->die = cl.time + 2; - for (j=0 ; j<3 ; j++) - { - p->vel[j] = (rand()&15)-8; - p->org[j] = start[j] + ((rand()&3)-2); - } + p->scale = 4; + p->alpha = 64 + (rand()&31); + p->color = type == 3 ? 56 : 234; + p->type = pt_fade; + p->die = cl.time + 10000; + VectorCopy(start, p->org); break; case 6: // voor trail @@ -1165,7 +890,7 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) p->scale = lhrandom(3, 5); p->alpha = 255; p->color = 9*16 + 8 + (rand()&3); - p->type = pt_fadespark2; + p->type = pt_fade; p->die = cl.time + 2; for (j=0 ; j<3 ; j++) { @@ -1197,35 +922,15 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent) { vec3_t vec; - float len; - particle_t *p; + int len; if (!r_particles.value) return; // LordHavoc: particles are optional VectorSubtract (end, start, vec); - len = VectorNormalizeLength (vec); - while (len > 0) + len = (int) (VectorNormalizeLength (vec) * (1.0f / 3.0f)); + VectorScale(vec, 3, vec); + while (len--) { - len -= 3; - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - VectorCopy (vec3_origin, p->vel); - - p->texnum = flareparticletexture; - p->scale = 8; - p->alpha = 192; - p->color = color; - p->type = pt_smoke; - p->die = cl.time + 1; - VectorCopy(start, p->org); -// for (j=0 ; j<3 ; j++) -// p->org[j] = start[j] + ((rand()&15)-8); - + particle(pt_smoke, color, particletexture, 8, 192, 99, start[0], start[1], start[2], 0, 0, 0); VectorAdd (start, vec, start); } } @@ -1243,14 +948,15 @@ void R_CompleteLightPoint (vec3_t color, vec3_t p); void R_DrawParticles (void) { - particle_t *p, *kill; + particle_t *p; int i, r,g,b,a; - float grav, grav1, time1, time2, time3, dvel, frametime, scale, scale2; + float gravity, dvel, frametime, scale, scale2, minparticledist; byte *color24; - vec3_t up, right, uprightangles, forward2, up2, right2, v, tempcolor; + vec3_t up, right, uprightangles, forward2, up2, right2, tempcolor; + int activeparticles, maxparticle, j, k; // LordHavoc: early out condition - if (!active_particles) + if (!numparticles) return; VectorScale (vup, 1.5, up); @@ -1262,58 +968,32 @@ void R_DrawParticles (void) AngleVectors (uprightangles, forward2, right2, up2); frametime = cl.time - cl.oldtime; - time3 = frametime * 15; - time2 = frametime * 10; // 15; - time1 = frametime * 5; - grav = (grav1 = frametime * sv_gravity.value) * 0.05; + gravity = frametime * sv_gravity.value; dvel = 1+4*frametime; - for ( ;; ) - { - kill = active_particles; - if (kill && kill->die < cl.time) - { - active_particles = kill->next; - kill->next = free_particles; - free_particles = kill; - continue; - } - break; - } + minparticledist = DotProduct(r_refdef.vieworg, vpn) + 16.0f; - for (p=active_particles ; p ; p=p->next) + activeparticles = 0; + maxparticle = -1; + j = 0; + for (k = 0, p = particles;k < numparticles;k++, p++) { - for ( ;; ) + if (p->die < cl.time) { - kill = p->next; - if (kill && kill->die < cl.time) - { - p->next = kill->next; - kill->next = free_particles; - free_particles = kill; - continue; - } - break; + freeparticles[j++] = p; + continue; } - // LordHavoc: 'removed last in list' condition - if (!p) - break; + maxparticle = k; + activeparticles++; - VectorSubtract(p->org, r_refdef.vieworg, v); - if (DotProduct(v, v) >= 256.0f) + // LordHavoc: only render if not too close + if (DotProduct(p->org, vpn) >= minparticledist) { - scale = p->scale * -0.5;scale2 = p->scale * 0.5; color24 = (byte *) &d_8to24table[(int)p->color]; r = color24[0]; g = color24[1]; b = color24[2]; a = p->alpha; - if (lighthalf) - { - r >>= 1; - g >>= 1; - b >>= 1; - } if (r_dynamicparticles.value) { R_CompleteLightPoint(tempcolor, p->org); @@ -1322,6 +1002,7 @@ void R_DrawParticles (void) b = (b * (int) tempcolor[2]) >> 7; } transpolybegin(p->texnum, 0, p->texnum, TPOLYTYPE_ALPHA); + scale = p->scale * -0.5;scale2 = p->scale * 0.5; if (p->texnum == rainparticletexture) // rain streak { transpolyvert(p->org[0] + up2[0]*scale + right2[0]*scale , p->org[1] + up2[1]*scale + right2[1]*scale , p->org[2] + up2[2]*scale + right2[2]*scale , 0,1,r,g,b,a); @@ -1347,73 +1028,24 @@ void R_DrawParticles (void) { case pt_static: break; - case pt_fire: - p->ramp += time1; - if (p->ramp >= 6) - p->die = -1; - else - p->color = ramp3[(int)p->ramp]; - p->vel[2] += grav; - break; - - case pt_explode: - p->ramp += time2; - if (p->ramp >=8) - p->die = -1; - else - p->color = ramp1[(int)p->ramp]; -// p->vel[2] -= grav1; // LordHavoc: apply full gravity to explosion sparks - for (i=0 ; i<3 ; i++) - p->vel[i] *= dvel; -// p->vel[2] -= grav; - break; - - case pt_explode2: - p->ramp += time3; - if (p->ramp >= 8) - p->die = -1; - else - p->color = ramp2[(int)p->ramp]; -// p->vel[2] -= grav1; // LordHavoc: apply full gravity to explosion sparks - for (i=0 ; i<3 ; i++) -// p->vel[i] -= p->vel[i]*frametime; - p->vel[i] *= dvel; -//// p->vel[2] -= grav; - break; case pt_blob: for (i=0 ; i<3 ; i++) - p->vel[i] += p->vel[i]*dvel; - p->vel[2] -= grav; + p->vel[i] *= dvel; break; case pt_blob2: for (i=0 ; i<2 ; i++) - p->vel[i] -= p->vel[i]*dvel; - p->vel[2] -= grav; + p->vel[i] *= dvel; break; case pt_grav: - p->vel[2] -= grav1; - break; - case pt_slowgrav: - p->vel[2] -= grav; - break; -// LordHavoc: gunshot spark showers - case pt_dust: - p->ramp += time1; - p->scale -= frametime * 4; - if (p->ramp >= 8 || p->scale <= 0) - p->die = -1; - else - p->color = ramp3[(int)p->ramp]; - p->vel[2] -= grav1; + p->vel[2] -= gravity; break; // LordHavoc: for smoke trails case pt_smoke: - p->scale += frametime * 4; - p->alpha -= frametime * 48; -// p->vel[2] += grav; + p->scale += frametime * 6; + p->alpha -= frametime * 128; if (p->alpha < 1) p->die = -1; break; @@ -1426,41 +1058,20 @@ void R_DrawParticles (void) p->vel[2] = (rand()&63)-32 + p->vel2[2]; } break; - case pt_bulletpuff: - p->scale -= frametime * 64; - p->alpha -= frametime * 1024; - p->vel[2] -= grav; - if (p->alpha < 1 || p->scale < 1) - p->die = -1; - break; case pt_bloodcloud: + if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY) + { + p->die = -1; + break; + } p->scale += frametime * 4; p->alpha -= frametime * 64; - p->vel[2] -= grav; if (p->alpha < 1 || p->scale < 1) p->die = -1; break; - case pt_fadespark: - p->alpha -= frametime * 256; - p->vel[2] -= grav; - if (p->alpha < 1) - p->die = -1; - break; - case pt_fadespark2: - p->alpha -= frametime * 512; - p->vel[2] -= grav; - if (p->alpha < 1) - p->die = -1; - break; case pt_fallfadespark: p->alpha -= frametime * 256; - p->vel[2] -= grav1; - if (p->alpha < 1) - p->die = -1; - break; - case pt_fallfadespark2: - p->alpha -= frametime * 512; - p->vel[2] -= grav1; + p->vel[2] -= gravity; if (p->alpha < 1) p->die = -1; break; @@ -1470,22 +1081,40 @@ void R_DrawParticles (void) p->die = -1; break; case pt_bubble: - if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY) + a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + if (a != CONTENTS_WATER && a != CONTENTS_SLIME) p->die = -1; - p->vel[2] += grav1 * 2; - if (p->vel[2] >= 200) - p->vel[2] = lhrandom(130, 200); + p->vel[2] += gravity * 0.25; + p->vel[0] *= (1 - (frametime * 0.0625)); + p->vel[1] *= (1 - (frametime * 0.0625)); + p->vel[2] *= (1 - (frametime * 0.0625)); if (cl.time > p->time2) { p->time2 = cl.time + lhrandom(0, 0.5); - p->vel[0] = lhrandom(-32,32); - p->vel[1] = lhrandom(-32,32); + p->vel[0] += lhrandom(-32,32); + p->vel[1] += lhrandom(-32,32); + p->vel[2] += lhrandom(-32,32); } p->alpha -= frametime * 64; if (p->alpha < 1) p->die = -1; break; + case pt_smokecloud: + p->scale += frametime * 60; + p->alpha -= frametime * 96; + if (p->alpha < 1) + p->die = -1; + break; } } + // fill in gaps to compact the array + i = 0; + while (maxparticle >= activeparticles) + { + *freeparticles[i++] = particles[maxparticle--]; + while (maxparticle >= activeparticles && particles[maxparticle].die < cl.time) + maxparticle--; + } + numparticles = activeparticles; }