X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=r_part.c;h=bfd01a8e5c65bcde719cd265d588281b542e858c;hp=5c822d9b8f82d59f27c5a28bdc957f99e7851ece;hb=98a17785f73d59a58e84b47eaebbcf6d628d5b7a;hpb=8dcce44300385b12c46d494c06aadcfa35a8bc14 diff --git a/r_part.c b/r_part.c index 5c822d9b..bfd01a8e 100644 --- a/r_part.c +++ b/r_part.c @@ -20,230 +20,181 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -#define MAX_PARTICLES 2048 // 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_rain, pt_bloodcloud, pt_fallfadespark, pt_bubble, pt_fade, pt_smokecloud, pt_splash +} ptype_t; + +typedef struct particle_s +{ + vec3_t org; + float color; + vec3_t vel; + float die; + ptype_t type; + float scale; + short texnum; + float alpha; // 0-255 + float time2; // used for various things (snow fluttering, for example) + vec3_t oldorg; + 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; -int flareparticletexture; +int smokeparticletexture[8]; 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; -//extern cvar_t r_particles/*, r_smoke*/, r_smokealpha; -//cvar_t r_smokecolor = {"r_smokecolor", "0"}; +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++]; -void R_InitParticleTexture (void) -{ - int x,y,d; - float dx, dy, dz, f, dot; - byte data[64][64][4], noise1[64][64], noise2[64][64]; - vec3_t normal, light; - - particletexture = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, particletexture); +cvar_t r_particles = {"r_particles", "1"}; +cvar_t r_dynamicparticles = {"r_dynamicparticles", "0", TRUE}; - for (x=0 ; x<64 ; x++) +byte shadebubble(float dx, float dy, vec3_t light) +{ + float dz, f, dot; + vec3_t normal; + if ((dx*dx+dy*dy) < 1) // it does hit the sphere { - for (y=0 ; y<64 ; y++) - { - data[y][x][0] = data[y][x][1] = data[y][x][2] = 255; - dx = x - 16; - dy = y - 16; - d = (255 - (dx*dx+dy*dy)); - if (d < 0) d = 0; - data[y][x][3] = (byte) d; - } + dz = 1 - (dx*dx+dy*dy); + f = 0; + // back side + normal[0] = dx;normal[1] = dy;normal[2] = dz; + VectorNormalize(normal); + dot = DotProduct(normal, light); + if (dot > 0.5) // interior reflection + f += ((dot * 2) - 1); + else if (dot < -0.5) // exterior reflection + f += ((dot * -2) - 1); + // front side + normal[0] = dx;normal[1] = dy;normal[2] = -dz; + VectorNormalize(normal); + dot = DotProduct(normal, light); + if (dot > 0.5) // interior reflection + f += ((dot * 2) - 1); + else if (dot < -0.5) // exterior reflection + f += ((dot * -2) - 1); + f *= 128; + f += 16; // just to give it a haze so you can see the outline + f = bound(0, f, 255); + return (byte) f; } - glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 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); - + else + return 0; +} - fractalnoise(&noise1[0][0], 64); - fractalnoise(&noise2[0][0], 64); - for (y = 0;y < 64;y++) - for (x = 0;x < 64;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; - } +void R_InitParticleTexture (void) +{ + int x,y,d,i,m; + float dx, dy; + byte data[32][32][4], noise1[32][32], noise2[32][32]; + vec3_t light; - /* - 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()%64)+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<64 ; x++) + for (y = 0;y < 32;y++) { - for (y=0 ; y<64 ; y++) + dy = y - 16; + for (x = 0;x < 32;x++) { - //data[y][x][0] = data[y][x][1] = data[y][x][2] = (rand()%192)+64; + data[y][x][0] = data[y][x][1] = data[y][x][2] = 255; dx = x - 16; - dy = y - 16; d = (255 - (dx*dx+dy*dy)); if (d < 0) d = 0; data[y][x][3] = (byte) d; } } - */ - smokeparticletexture = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, smokeparticletexture); - glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 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], 64); - fractalnoise(&noise2[0][0], 64); - for (y = 0;y < 64;y++) - for (x = 0;x < 64;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, 64, 64, 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); + particletexture = GL_LoadTexture ("particletexture", 32, 32, &data[0][0][0], true, true, 4); - for (x=0 ; x<64 ; x++) + for (i = 0;i < 8;i++) { - for (y=0 ; y<64 ; y++) + do { - 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; + fractalnoise(&noise1[0][0], 32, 1); + fractalnoise(&noise2[0][0], 32, 8); + m = 0; + for (y = 0;y < 32;y++) + { + dy = y - 16; + 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; + d = ((noise2[y][x] * 384) >> 8) - 128; + if (d > 0) + { + if (d > 255) + d = 255; + d = (d * (255 - (int) (dx*dx+dy*dy))) >> 7; + if (d < 0) d = 0; + if (d > 255) d = 255; + data[y][x][3] = (byte) d; + if (m < d) + m = d; + } + else + data[y][x][3] = 0; + } + } } - } - glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + while (m < 192); - 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); + smokeparticletexture[i] = GL_LoadTexture (va("smokeparticletexture%d", i), 32, 32, &data[0][0][0], true, true, 4); + } - for (x=0 ; x<64 ; x++) + light[0] = 1;light[1] = 1;light[2] = 1; + VectorNormalize(light); + for (x=0 ; x<32 ; x++) { - for (y=0 ; y<64 ; y++) + for (y=0 ; y<32 ; y++) { data[y][x][0] = data[y][x][1] = data[y][x][2] = 255; - if (y < 24) // stretch the upper half to make a raindrop - { - dx = (x - 16)*2; - dy = (y - 24)*2/3; - d = (255 - (dx*dx+dy*dy))/2; - } - else - { - dx = (x - 16)*2; - dy = (y - 24)*2; - d = (255 - (dx*dx+dy*dy))/2; - } - if (d < 0) d = 0; - data[y][x][3] = (byte) d; + data[y][x][3] = shadebubble((x - 16) * (1.0 / 8.0), y < 24 ? (y - 24) * (1.0 / 24.0) : (y - 24) * (1.0 / 8.0), light); } } - glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 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); - for (x=0 ; x<64 ; x++) + for (x=0 ; x<32 ; x++) { - for (y=0 ; y<64 ; y++) + for (y=0 ; y<32 ; y++) { data[y][x][0] = data[y][x][1] = data[y][x][2] = 255; - dx = x * (1.0 / 16.0) - 1.0; - dy = y * (1.0 / 16.0) - 1.0; - if (dx*dx+dy*dy < 1) // it does hit the sphere - { - dz = 1 - (dx*dx+dy*dy); - f = 0; - // back side - normal[0] = dx;normal[1] = dy;normal[2] = dz; - VectorNormalize(normal); - dot = DotProduct(normal, light); - if (dot > 0.5) // interior reflection - f += ((dot * 2) - 1); - else if (dot < -0.5) // exterior reflection - f += ((dot * -2) - 1); - // front side - normal[0] = dx;normal[1] = dy;normal[2] = -dz; - VectorNormalize(normal); - dot = DotProduct(normal, light); - if (dot > 0.5) // interior reflection - f += ((dot * 2) - 1); - else if (dot < -0.5) // exterior reflection - f += ((dot * -2) - 1); - f *= 255; - f = bound(0, f, 255); - data[y][x][3] = (byte) d; - } - else - data[y][x][3] = 0; + data[y][x][3] = shadebubble((x - 16) * (1.0 / 16.0), (y - 16) * (1.0 / 16.0), light); } } - glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 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); } /* @@ -251,7 +202,7 @@ void R_InitParticleTexture (void) R_InitParticles =============== */ -void R_InitParticles (void) +void R_Particles_Init (void) { int i; @@ -268,11 +219,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); -// Cvar_RegisterVariable (&r_smokecolor); - 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); } +*/ /* =============== @@ -292,22 +351,18 @@ 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 + if (!r_particles.value) return; // LordHavoc: particles are optional 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); } } @@ -353,14 +389,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); @@ -450,65 +474,23 @@ R_ParticleExplosion */ void R_ParticleExplosion (vec3_t org, int smoke) { - int i, j; - particle_t *p; -// if (!r_particles.value) return; // LordHavoc: particles are optional - - for (i=0 ; i<1024 ; i++) + int i; + if (!r_particles.value) return; // LordHavoc: particles are optional + + particle(pt_smokecloud, (rand()&7) + 8, smokeparticletexture[rand()&7], 30, 160, 2, org[0], org[1], org[2], 0, 0, 0); + + i = Mod_PointInLeaf(org, cl.worldmodel)->contents; + if (i == CONTENTS_SLIME || i == CONTENTS_WATER) { - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - p->texnum = flareparticletexture; - p->scale = 4+(rand()&7); - p->alpha = rand()&255; - p->die = cl.time + 5; - p->color = ramp1[0]; - p->ramp = rand()&3; - /* - 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()&63)-32); - p->vel[j] = (rand()&511)-256; - } - p->vel[j] += 200; + for (i=0 ; i<128 ; i++) + particle2(pt_bubble, (rand()&3) + 12, bubbleparticletexture, lhrandom(1, 2), 255, 2, org, 16, 96); } - - if (smoke) + else { - 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; - p->scale = 24; - 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; - } - } + for (i = 0;i < 256;i++) + particle(pt_fallfadespark, ramp3[rand()%6], particletexture, 1.5, lhrandom(0, 255), 5, lhrandom(-16, 16) + org[0], lhrandom(-16, 16) + org[1], lhrandom(-16, 16) + org[2], lhrandom(-192, 192), lhrandom(-192, 192), lhrandom(-192, 192) + 192); } + } /* @@ -519,34 +501,11 @@ R_ParticleExplosion2 */ void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength) { - int i, j; - particle_t *p; - int colorMod = 0; -// 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 = flareparticletexture; - p->scale = 8; - p->alpha = 255; - p->die = cl.time + 0.3; - p->color = colorStart + (colorMod % colorLength); - colorMod++; + int i; + if (!r_particles.value) return; // LordHavoc: particles are optional - p->type = pt_blob; - for (j=0 ; j<3 ; j++) - { - p->org[j] = org[j] + ((rand()%32)-16); - p->vel[j] = (rand()%512)-256; - } - } + for (i = 0;i < 512;i++) + particle2(pt_fade, colorStart + (i % colorLength), particletexture, 1.5, 255, 0.3, org, 8, 192); } /* @@ -557,45 +516,13 @@ R_BlobExplosion */ void R_BlobExplosion (vec3_t org) { - int i, j; - particle_t *p; -// if (!r_particles.value) return; // LordHavoc: particles are optional + 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 = flareparticletexture; - p->scale = 8; - 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] = (rand()%512)-256; - } - } - 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] = (rand()%512)-256; - } - } - } + 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); } /* @@ -606,179 +533,79 @@ R_RunParticleEffect */ void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count) { - int i, j; - particle_t *p; -// if (!r_particles.value) return; // LordHavoc: particles are optional + if (!r_particles.value) return; // LordHavoc: particles are optional - for (i=0 ; inext; - p->next = active_particles; - active_particles = p; - - if (count == 1024) - { // rocket explosion - p->texnum = flareparticletexture; - p->scale = 8; - p->alpha = 255; - p->die = cl.time + 5; - p->color = ramp1[0]; - p->ramp = rand()&3; - if (i & 1) - { - p->type = pt_explode; - for (j=0 ; j<3 ; j++) - { - p->org[j] = org[j] + ((rand()%32)-16); - p->vel[j] = (rand()%512)-256; - } - } - else - { - p->type = pt_explode2; - for (j=0 ; j<3 ; j++) - { - p->org[j] = org[j] + ((rand()%32)-16); - p->vel[j] = (rand()%512)-256; - } - } - } - else - { - p->texnum = flareparticletexture; - p->scale = 8; - p->alpha = 255; - p->die = cl.time + 0.1*(rand()%5); - p->color = (color&~7) + (rand()&7); - p->type = pt_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; - } - } + R_ParticleExplosion(org, false); + return; } + color &= ~7; + if (count & 7) + { + 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 (!r_particles.value) return; // LordHavoc: particles are optional + + // 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); + particle(pt_fallfadespark, ramp3[rand()%6], particletexture, 1, lhrandom(0, 255), 5, lhrandom(-4, 4) + org[0], lhrandom(-4, 4) + org[1], lhrandom(-4, 4) + org[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64) + 64); +} - 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; - p->scale = 20; - 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 = bloodcloudparticletexture; - p->scale = 24; - 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 = 5; - 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; - } - } - */ - } +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); + particle(pt_bloodcloud, 68+(rand()&3), smokeparticletexture[rand()&7], 10, 128, 99, org[0] + lhrandom(-4, 4), org[1] + lhrandom(-4, 4), org[2] + lhrandom(-4, 4), 0, 0, 0); + particle(pt_bloodcloud, 68+(rand()&3), smokeparticletexture[rand()&7], 8, 128, 99, org[0] + lhrandom(-4, 4), org[1] + lhrandom(-4, 4), org[2] + lhrandom(-4, 4), 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; vec3_t velscale; -// if (!r_particles.value) return; // LordHavoc: particles are optional + if (!r_particles.value) return; // LordHavoc: particles are optional VectorSubtract(maxs, mins, diff); 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 = 24; + ALLOCPARTICLE + + p->texnum = smokeparticletexture[rand()&7]; + p->scale = lhrandom(4, 6); 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]; @@ -789,28 +616,23 @@ 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; -// if (!r_particles.value) return; // LordHavoc: particles are optional + if (!r_particles.value) return; // LordHavoc: particles are optional if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;} if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;} if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;} VectorSubtract(maxs, mins, diff); - for (i=0 ; inext; - p->next = active_particles; - active_particles = p; - - p->texnum = flareparticletexture; - p->scale = 12; + ALLOCPARTICLE + + p->texnum = particletexture; + p->scale = 6; p->alpha = 255; p->die = cl.time + 1 + (rand()&15)*0.0625; if (gravity) @@ -837,7 +659,7 @@ void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb vec3_t org; vec3_t vel; float t, z; -// if (!r_particles.value) return; // LordHavoc: particles are optional + if (!r_particles.value) return; // LordHavoc: particles are optional if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;} if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;} if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;} @@ -859,12 +681,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; @@ -873,22 +690,24 @@ void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb org[1] = diff[1] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[1]; org[2] = z; - p->scale = 6; p->alpha = 255; p->die = t; if (type == 1) { + p->scale = 2; p->texnum = particletexture; p->type = pt_snow; } else // 0 { + p->scale = 3; p->texnum = rainparticletexture; - p->type = pt_static; + p->type = pt_rain; } p->color = colorbase + (rand()&3); VectorCopy(org, p->org); VectorCopy(vel, p->vel); + VectorCopy(vel, p->vel2); } } @@ -901,42 +720,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 + 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 = 24; - p->alpha = 255; - 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); + } } /* @@ -949,59 +762,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->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); - } - */ + if (!r_particles.value) return; // LordHavoc: particles are optional - 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 = 8; - p->alpha = (1 + rand()&7) * 32; + 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); @@ -1016,11 +790,10 @@ void R_TeleportSplash (vec3_t org) void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) { vec3_t vec; - float len, dec, t, nt, speed; + float len, dec = 0, t, nt, speed; int j, contents, bubbles; particle_t *p; - static int tracercount; -// if (!r_particles.value) return; // LordHavoc: particles are optional + if (!r_particles.value) return; // LordHavoc: particles are optional t = cl.oldtime; nt = cl.time; @@ -1045,12 +818,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; @@ -1061,14 +829,11 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) case 1: // grenade trail if (bubbles) { - dec = 0.01f; + dec = 0.005f; p->texnum = bubbleparticletexture; - p->scale = 6+(rand()&3); + p->scale = lhrandom(1,2); p->alpha = 255; -// if (r_smokecolor.value) -// p->color = r_smokecolor.value; -// else - p->color = (rand()&3)+12; + p->color = (rand()&3)+12; p->type = pt_bubble; p->die = cl.time + 2; for (j=0 ; j<3 ; j++) @@ -1079,16 +844,13 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) } else { - dec = 0.03f; - p->texnum = smokeparticletexture; - p->scale = 12+(rand()&7); + dec = 0.02f; + p->texnum = smokeparticletexture[rand()&7]; + p->scale = lhrandom(8, 12); p->alpha = 64 + (rand()&31); -// if (r_smokecolor.value) -// p->color = r_smokecolor.value; -// else - p->color = (rand()&3)+12; + p->color = (rand()&3)+12; p->type = pt_smoke; - p->die = cl.time + 2; + p->die = cl.time + 10000; VectorCopy(start, p->org); } break; @@ -1097,7 +859,7 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) case 1: // smoke smoke dec = 0.016f; p->texnum = smokeparticletexture; - p->scale = 12+rand()&7; + p->scale = lhrandom(6,9); p->alpha = 64; if (r_smokecolor.value) p->color = r_smokecolor.value; @@ -1110,13 +872,14 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) */ case 2: // blood - dec = 0.03f; - p->texnum = bloodcloudparticletexture; - p->scale = 20+(rand()&7); - p->alpha = 255; + case 4: // slight blood + dec = 0.025f; + p->texnum = smokeparticletexture[rand()&7]; + p->scale = lhrandom(4, 6); + 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; @@ -1126,54 +889,23 @@ 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; + dec = 0.02f; + p->texnum = smokeparticletexture[rand()&7]; p->scale = 4; - 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.03f; // sparse trail - p->texnum = bloodcloudparticletexture; - p->scale = 20+(rand()&7); - p->alpha = 255; - 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->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 dec = 0.05f; // sparse trail - p->texnum = flareparticletexture; - p->scale = 20+(rand()&7); + p->texnum = smokeparticletexture[rand()&7]; + 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++) { @@ -1184,12 +916,12 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) case 7: // Nehahra smoke tracer dec = 0.14f; - p->texnum = smokeparticletexture; - p->scale = 12+(rand()&7); + p->texnum = smokeparticletexture[rand()&7]; + p->scale = lhrandom(8, 12); p->alpha = 64; p->color = (rand()&3)+12; p->type = pt_smoke; - p->die = cl.time + 1; + p->die = cl.time + 10000; for (j=0 ; j<3 ; j++) p->org[j] = start[j] + ((rand()&3)-2); break; @@ -1205,80 +937,43 @@ 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; - static int tracercount; -// if (!r_particles.value) return; // LordHavoc: particles are optional + 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 = 16; - 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); } } -//extern qboolean isG200, isATI, isRagePro; -extern qboolean lighthalf; - /* =============== R_DrawParticles =============== */ extern cvar_t sv_gravity; +void R_CompleteLightPoint (vec3_t color, vec3_t p); + +void TraceLine (vec3_t start, vec3_t end, vec3_t impact); void R_DrawParticles (void) { - particle_t *p, *kill; - int i, /*texnum, */r,g,b,a; - float grav, grav1, time1, time2, time3, dvel, frametime, scale, scale2; + particle_t *p; + int i, r,g,b,a; + float gravity, dvel, frametime, scale, scale2, minparticledist; byte *color24; - vec3_t up, right, uprightangles, forward2, up2, right2, v; + vec3_t up, right, uprightangles, forward2, up2, right2, tempcolor, v; + int activeparticles, maxparticle, j, k; // LordHavoc: early out condition - if (!active_particles) + if (!numparticles) return; - /* - texnum = particletexture; - glBindTexture(GL_TEXTURE_2D, texnum); - glEnable (GL_BLEND); - // LordHavoc: Matrox G200 cards can't handle per pixel alpha at all... - // and ATI Rage Pro can't modulate a per pixel alpha texture - if (isG200 || isRagePro) - glEnable(GL_ALPHA_TEST); - else - glDisable(GL_ALPHA_TEST); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthMask(0); // disable zbuffer updates - glShadeModel(GL_FLAT); - glBegin (GL_TRIANGLES); - */ - VectorScale (vup, 1.5, up); VectorScale (vright, 1.5, right); @@ -1288,118 +983,59 @@ 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.25;scale2 = p->scale * 0.75; - /* - if (p->texnum != texnum) - { - texnum = p->texnum; - glEnd(); - glBindTexture(GL_TEXTURE_2D, texnum); - glBegin(GL_TRIANGLES); - } - if (lighthalf) - { - color24 = (byte *)&d_8to24table[(int)p->color]; - if (p->texnum == smokeparticletexture) - glColor4ub((byte) (color24[0] >> 1), (byte) (color24[1] >> 1), (byte) (color24[2] >> 1), (byte) (p->alpha*r_smokealpha.value)); - else - glColor4ub((byte) (color24[0] >> 1), (byte) (color24[1] >> 1), (byte) (color24[2] >> 1), (byte) p->alpha); - } - else - { - color24 = (byte *) &d_8to24table[(int)p->color]; - if (p->texnum == smokeparticletexture) - glColor4ub(color24[0], color24[1], color24[2], (byte) (p->alpha*r_smokealpha.value)); - else - glColor4ub(color24[0], color24[1], color24[2], (byte) p->alpha); - } - if (p->texnum == rainparticletexture) // rain streak - { - glTexCoord2f (0,0); - glVertex3f (p->org[0] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale ); - glTexCoord2f (1,0); - glVertex3f (p->org[0] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale ); - glTexCoord2f (0,1); - glVertex3f (p->org[0] + right2[0]*scale2, p->org[1] + right2[1]*scale2, p->org[2] + right2[2]*scale2); - } - else - { - glTexCoord2f (0,0); - // LordHavoc: centered particle sprites - glVertex3f (p->org[0] + up[0]*scale + right[0]*scale , p->org[1] + up[1]*scale + right[1]*scale , p->org[2] + up[2]*scale + right[2]*scale ); - glTexCoord2f (1,0); - glVertex3f (p->org[0] + up[0]*scale2 + right[0]*scale , p->org[1] + up[1]*scale2 + right[1]*scale , p->org[2] + up[2]*scale2 + right[2]*scale ); - glTexCoord2f (0,1); - glVertex3f (p->org[0] + up[0]*scale + right[0]*scale2, p->org[1] + up[1]*scale + right[1]*scale2, p->org[2] + up[2]*scale + right[2]*scale2); - } - */ color24 = (byte *) &d_8to24table[(int)p->color]; r = color24[0]; g = color24[1]; b = color24[2]; a = p->alpha; - if (lighthalf) + if (r_dynamicparticles.value) { - r >>= 1; - g >>= 1; - b >>= 1; + R_CompleteLightPoint(tempcolor, p->org); + r = (r * (int) tempcolor[0]) >> 7; + g = (g * (int) tempcolor[1]) >> 7; + 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] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale , 0,0,r,g,b,a); - transpolyvert(p->org[0] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale , 1,0,r,g,b,a); - transpolyvert(p->org[0] + right2[0]*scale2, p->org[1] + right2[1]*scale2, p->org[2] + right2[2]*scale2, 0,1,r,g,b,a); + 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); + transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale , p->org[1] + up2[1]*scale2 + right2[1]*scale , p->org[2] + up2[2]*scale2 + right2[2]*scale , 0,0,r,g,b,a); + transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale2, p->org[1] + up2[1]*scale2 + right2[1]*scale2, p->org[2] + up2[2]*scale2 + right2[2]*scale2, 1,0,r,g,b,a); + transpolyvert(p->org[0] + up2[0]*scale + right2[0]*scale2, p->org[1] + up2[1]*scale + right2[1]*scale2, p->org[2] + up2[2]*scale + right2[2]*scale2, 1,1,r,g,b,a); } else { - transpolyvert(p->org[0] + up[0]*scale + right[0]*scale , p->org[1] + up[1]*scale + right[1]*scale , p->org[2] + up[2]*scale + right[2]*scale , 0,0,r,g,b,a); - transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale , p->org[1] + up[1]*scale2 + right[1]*scale , p->org[2] + up[2]*scale2 + right[2]*scale , 1,0,r,g,b,a); - transpolyvert(p->org[0] + up[0]*scale + right[0]*scale2, p->org[1] + up[1]*scale + right[1]*scale2, p->org[2] + up[2]*scale + right[2]*scale2, 0,1,r,g,b,a); + transpolyvert(p->org[0] + up[0]*scale + right[0]*scale , p->org[1] + up[1]*scale + right[1]*scale , p->org[2] + up[2]*scale + right[2]*scale , 0,1,r,g,b,a); + transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale , p->org[1] + up[1]*scale2 + right[1]*scale , p->org[2] + up[2]*scale2 + right[2]*scale , 0,0,r,g,b,a); + transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale2, p->org[1] + up[1]*scale2 + right[1]*scale2, p->org[2] + up[2]*scale2 + right[2]*scale2, 1,0,r,g,b,a); + transpolyvert(p->org[0] + up[0]*scale + right[0]*scale2, p->org[1] + up[1]*scale + right[1]*scale2, p->org[2] + up[2]*scale + right[2]*scale2, 1,1,r,g,b,a); } transpolyend(); } + VectorCopy(p->org, p->oldorg); p->org[0] += p->vel[0]*frametime; p->org[1] += p->vel[1]*frametime; p->org[2] += p->vel[2]*frametime; @@ -1408,143 +1044,146 @@ 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[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 * 16; - p->alpha -= frametime * 64; - p->vel[2] += grav; + p->scale += frametime * 6; + p->alpha -= frametime * 128; if (p->alpha < 1) p->die = -1; break; case pt_snow: if (cl.time > p->time2) { - p->time2 = cl.time + 0.4; - p->vel[0] = (rand()&63)-32; - p->vel[1] = (rand()&63)-32; + p->time2 = cl.time + (rand() & 3) * 0.1; + p->vel[0] = (rand()&63)-32 + p->vel2[0]; + p->vel[1] = (rand()&63)-32 + p->vel2[1]; + 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: - p->scale -= frametime * 24; - p->alpha -= frametime * 128; - p->vel[2] -= grav; +// if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY) +// { +// p->die = -1; +// break; +// } + p->scale += frametime * 16; + p->alpha -= frametime * 512; if (p->alpha < 1 || p->scale < 1) p->die = -1; break; - case pt_fadespark: + case pt_fallfadespark: p->alpha -= frametime * 256; - p->vel[2] -= grav; + p->vel[2] -= gravity; if (p->alpha < 1) p->die = -1; break; - case pt_fadespark2: + case pt_fade: 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; + case pt_bubble: + a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + if (a != CONTENTS_WATER && a != CONTENTS_SLIME) + { + p->texnum = smokeparticletexture[rand()&7]; + p->type = pt_splash; + p->alpha = 96; + p->scale = 5; + p->vel[0] = p->vel[1] = p->vel[2] = 0; + p->die = cl.time + 1000; +// p->die = -1; + } + 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[2] += lhrandom(-32,32); + } + p->alpha -= frametime * 64; if (p->alpha < 1) p->die = -1; break; - case pt_fallfadespark2: - p->alpha -= frametime * 512; - p->vel[2] -= grav1; + case pt_smokecloud: + p->scale += frametime * 60; + p->alpha -= frametime * 96; if (p->alpha < 1) p->die = -1; break; - case pt_bubble: - p->vel[2] += grav1; - if (p->vel[2] >= 100) - p->vel[2] = 68+rand()&31; - if (cl.time > p->time2) - { - p->time2 = cl.time + (rand()&7)*0.0625; - p->vel[0] = (rand()&63)-32; - p->vel[1] = (rand()&63)-32; - } - p->alpha -= frametime * 32; + case pt_splash: + p->scale += frametime * 24; + p->alpha -= frametime * 256; if (p->alpha < 1) p->die = -1; break; + case pt_rain: + a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + if (a != CONTENTS_EMPTY && a != CONTENTS_SKY) + { + if (a == CONTENTS_SOLID && Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents == CONTENTS_SOLID) + break; // still in solid + p->die = cl.time + 1000; + switch (a) + { + case CONTENTS_LAVA: + case CONTENTS_SLIME: + p->texnum = smokeparticletexture[rand()&7]; + p->type = pt_smokecloud; + p->alpha = 64; + p->vel[2] = 96; + break; + case CONTENTS_WATER: + p->texnum = smokeparticletexture[rand()&7]; + p->type = pt_splash; + p->alpha = 96; + p->scale = 5; + p->vel[0] = p->vel[1] = p->vel[2] = 0; +// p->texnum = bubbleparticletexture; +// p->type = pt_bubble; +// p->vel[2] *= 0.1; + break; + default: // CONTENTS_SOLID and any others + TraceLine(p->oldorg, p->org, v); + VectorCopy(v, p->org); + p->texnum = smokeparticletexture[rand()&7]; + p->type = pt_splash; + p->alpha = 96; + p->scale = 5; + p->vel[0] = p->vel[1] = p->vel[2] = 0; + p->die = cl.time + 1000; + break; + } + } + break; } } - - /* - glEnd (); - glShadeModel(GL_SMOOTH); - glDepthMask(1); // enable zbuffer updates - glDisable (GL_BLEND); - */ + // 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; }