]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_part.c
minor speedup to VectorNormalize #define's
[xonotic/darkplaces.git] / r_part.c
index 540494a8c83ab5d74dcc4ee5105fea3af260be66..b443d834375d2279a5434f2d45fd3a576197acd5 100644 (file)
--- a/r_part.c
+++ b/r_part.c
@@ -20,7 +20,7 @@ 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
+#define MAX_PARTICLES                  32768   // default max # of particles at one
                                                                                //  time
 #define ABSOLUTE_MIN_PARTICLES 512             // no fewer than this no matter what's
                                                                                //  on the command line
@@ -30,7 +30,7 @@ int           ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
 int            ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
 
 int            particletexture;
-int            smokeparticletexture;
+int            smokeparticletexture[8];
 int            flareparticletexture;
 int            rainparticletexture;
 int            bloodcloudparticletexture;
@@ -43,20 +43,30 @@ int                 r_numparticles;
 
 vec3_t                 r_pright, r_pup, r_ppn;
 
-cvar_t r_particles = {"r_particles", "1", true};
+// LordHavoc: reduced duplicate code, and allow particle allocation system independence
+#define ALLOCPARTICLE \
+       if (!free_particles)\
+               return;\
+       p = free_particles;\
+       free_particles = p->next;\
+       p->next = active_particles;\
+       active_particles = p;
+
+cvar_t r_particles = {"r_particles", "1"};
+cvar_t r_dynamicparticles = {"r_dynamicparticles", "0", TRUE};
 
 void fractalnoise(char *noise, int size);
 void fractalnoise_zeroedge(char *noise, int size);
 
 void R_InitParticleTexture (void)
 {
-       int             x,y,d;
+       int             x,y,d,i;
        float   dx, dy, dz, f, dot;
        byte    data[32][32][4], noise1[32][32], noise2[32][32];
        vec3_t  normal, light;
 
        particletexture = texture_extension_number++;
-    glBindTexture(GL_TEXTURE_2D, particletexture);
+       glBindTexture(GL_TEXTURE_2D, particletexture);
 
        for (x=0 ; x<32 ; x++)
        {
@@ -78,50 +88,61 @@ void R_InitParticleTexture (void)
        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;
-               }
-
-       /*
-       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 (i = 0;i < 8;i++)
        {
-               for (y=0 ; y<32 ; y++)
+               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] * 4 - 512;
+                               if (d > 0)
+                               {
+                                       if (d > 255)
+                                               d = 255;
+                                       d = (d * (255 - (int) (dx*dx+dy*dy))) >> 8;
+                                       if (d < 0) d = 0;
+                                       if (d > 255) d = 255;
+                                       data[y][x][3] = (byte) d;
+                               }
+                               else
+                                       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++)
                {
-                       //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;
+                       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);
        }
-       */
-       smokeparticletexture = texture_extension_number++;
-       glBindTexture(GL_TEXTURE_2D, smokeparticletexture);
-       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);
@@ -145,7 +166,7 @@ void R_InitParticleTexture (void)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
        flareparticletexture = texture_extension_number++;
-    glBindTexture(GL_TEXTURE_2D, flareparticletexture);
+       glBindTexture(GL_TEXTURE_2D, flareparticletexture);
 
        for (x=0 ; x<32 ; x++)
        {
@@ -167,7 +188,7 @@ void R_InitParticleTexture (void)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
        rainparticletexture = texture_extension_number++;
-    glBindTexture(GL_TEXTURE_2D, rainparticletexture);
+       glBindTexture(GL_TEXTURE_2D, rainparticletexture);
 
        for (x=0 ; x<32 ; x++)
        {
@@ -198,7 +219,7 @@ void R_InitParticleTexture (void)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
        bubbleparticletexture = texture_extension_number++;
-    glBindTexture(GL_TEXTURE_2D, bubbleparticletexture);
+       glBindTexture(GL_TEXTURE_2D, bubbleparticletexture);
 
        light[0] = 1;light[1] = 1;light[2] = 1;
        VectorNormalize(light);
@@ -270,6 +291,7 @@ void R_InitParticles (void)
        particles = (particle_t *) Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
 
        Cvar_RegisterVariable (&r_particles);
+       Cvar_RegisterVariable (&r_dynamicparticles);
        R_InitParticleTexture ();
 }
 
@@ -324,17 +346,13 @@ avelocities[0][i] = (rand()&255) * 0.01;
                forward[1] = cp*sy;
                forward[2] = -sp;
 
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
+//             p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = p->vel[0] = p->vel[1] = p->vel[2] = 0;
                p->texnum = flareparticletexture;
                p->scale = 2;
                p->alpha = 255;
-               p->die = cl.time + 0.01;
+               p->die = cl.time;
                p->color = 0x6f;
                p->type = pt_explode;
                
@@ -395,10 +413,7 @@ void R_ReadPointFile_f (void)
                        Con_Printf ("Not enough free particles\n");
                        break;
                }
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
                
                p->texnum = particletexture;
                p->scale = 2;
@@ -406,7 +421,7 @@ void R_ReadPointFile_f (void)
                p->die = 99999;
                p->color = (-c)&15;
                p->type = pt_static;
-               VectorCopy (vec3_origin, p->vel);
+//             p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = p->vel[0] = p->vel[1] = p->vel[2] = 0;
                VectorCopy (org, p->org);
        }
 
@@ -414,6 +429,37 @@ void R_ReadPointFile_f (void)
        Con_Printf ("%i points read\n", c);
 }
 
+/*
+===============
+R_BlastParticles
+
+LordHavoc: blasts away particles in the area, used for explosions to disturb the smoke trail and such
+===============
+*/
+/*
+void R_BlastParticles(vec3_t org, vec_t radius, vec_t power)
+{
+       vec3_t v;
+       particle_t *p;
+       vec_t radius2 = radius * radius, speed, dist, scale = 2.5 * power / radius;
+       p = active_particles;
+       if (!p)
+               return;
+       while (p)
+       {
+               VectorSubtract(p->org, org, v);
+               dist = DotProduct(v,v);
+               if (dist < radius2)
+               {
+                       speed = (radius - sqrt(dist)) * scale;
+                       VectorNormalize(v);
+                       VectorMA(p->pushvel, speed, v, p->pushvel);
+               }
+               p = p->next;
+       }
+}
+*/
+
 /*
 ===============
 R_ParseParticleEffect
@@ -452,62 +498,78 @@ 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++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
-               p->texnum = flareparticletexture;
-               p->scale = lhrandom(2,5);
+//             p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+               p->texnum = particletexture;
+               p->scale = lhrandom(1,3);
                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->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()&63)-32);
-                       p->vel[j] = (rand()&511)-256;
+                       p->org[j] = org[j] + lhrandom(-8,8);
+                       p->vel[j] = lhrandom(-192, 192);
                }
-               p->vel[j] += 200;
+               p->vel[2] += 160;
        }
+       */
 
-       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;
-                       p->scale = 12;
-                       p->alpha = 80;
+                       ALLOCPARTICLE
+
+//                     p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+                       p->texnum = bubbleparticletexture;
+                       p->scale = lhrandom(1,2);
+                       p->alpha = 255;
+                       p->color = (rand()&3)+12;
+                       p->type = pt_bubble;
                        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;
+                               p->org[j] = org[j] + lhrandom(-16,16);
+                               p->vel[j] = lhrandom(-16,16);
                        }
                }
        }
+       else // if (smoke)
+       {
+//             for (i=0 ; i<32 ; i++)
+//             {
+                       ALLOCPARTICLE
+
+//                     p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+                       p->texnum = smokeparticletexture[rand()&7];
+//                     p->scale = 12;
+                       p->scale = 30;
+                       p->alpha = 96;
+                       p->die = cl.time + 2;
+                       p->type = pt_smokecloud;
+                       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;
+                               p->org[j] = org[j];
+                               p->vel[j] = 0;
+                       }
+               }
+//     }
 }
 
 /*
@@ -525,15 +587,11 @@ void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
 
        for (i=0; i<512; i++)
        {
-               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->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+               p->texnum = particletexture;
+               p->scale = 1.5;
                p->alpha = 255;
                p->die = cl.time + 0.3;
                p->color = colorStart + (colorMod % colorLength);
@@ -542,8 +600,8 @@ void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
                p->type = pt_blob;
                for (j=0 ; j<3 ; j++)
                {
-                       p->org[j] = org[j] + ((rand()%32)-16);
-                       p->vel[j] = (rand()%512)-256;
+                       p->org[j] = org[j] + ((rand()&15)-8);
+                       p->vel[j] = lhrandom(-192, 192);
                }
        }
 }
@@ -562,15 +620,11 @@ void R_BlobExplosion (vec3_t org)
        
        for (i=0 ; i<1024 ; i++)
        {
-               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->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+               p->texnum = particletexture;
+               p->scale = 2;
                p->alpha = 255;
                p->die = cl.time + 1 + (rand()&8)*0.05;
 
@@ -581,7 +635,7 @@ void R_BlobExplosion (vec3_t org)
                        for (j=0 ; j<3 ; j++)
                        {
                                p->org[j] = org[j] + ((rand()%32)-16);
-                               p->vel[j] = (rand()%512)-256;
+                               p->vel[j] = lhrandom(-128, 128);
                        }
                }
                else
@@ -591,9 +645,11 @@ void R_BlobExplosion (vec3_t org)
                        for (j=0 ; j<3 ; j++)
                        {
                                p->org[j] = org[j] + ((rand()%32)-16);
-                               p->vel[j] = (rand()%512)-256;
+                               p->vel[j] = lhrandom(-128, 128);
                        }
                }
+               p->vel[0] *= 0.25;
+               p->vel[1] *= 0.25;
        }
 }
 
@@ -605,59 +661,39 @@ R_RunParticleEffect
 */
 void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
 {
-       int                     i, j;
+       int                     j;
        particle_t      *p;
        if (!r_particles.value) return; // LordHavoc: particles are optional
        
-       for (i=0 ; i<count ; i++)
+       if (count == 1024)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
-
-               if (count == 1024)
-               {       // rocket explosion
-                       p->texnum = flareparticletexture;
-                       p->scale = 4;
-                       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;
-                               }
-                       }
+               R_ParticleExplosion(org, false);
+               return;
+       }
+       while (count)
+       {
+               ALLOCPARTICLE
+               if (count & 7)
+               {
+                       p->alpha = (count & 7) * 16 + (rand()&15);
+                       count &= ~7;
                }
                else
                {
-                       p->texnum = flareparticletexture;
-                       p->scale = 4;
-                       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;
-                       }
+                       p->alpha = 128;
+                       count -= 8;
+               }
+
+//             p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+               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;
                }
        }
 }
@@ -675,17 +711,13 @@ void R_SparkShower (vec3_t org, vec3_t dir, int count, int type)
        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;
+       ALLOCPARTICLE
+//     p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
        if (type == 0) // sparks
        {
-               p->texnum = smokeparticletexture;
+               p->texnum = smokeparticletexture[rand()&7];
                p->scale = 10;
-               p->alpha = 64;
+               p->alpha = 48;
                p->color = (rand()&3)+12;
                p->type = pt_bulletpuff;
                p->die = cl.time + 1;
@@ -694,7 +726,7 @@ void R_SparkShower (vec3_t org, vec3_t dir, int count, int type)
        }
        else // blood
        {
-               p->texnum = bloodcloudparticletexture;
+               p->texnum = smokeparticletexture[rand()&7];
                p->scale = 12;
                p->alpha = 128;
                p->color = (rand()&3)+68;
@@ -706,16 +738,12 @@ void R_SparkShower (vec3_t org, vec3_t dir, int count, int type)
        }
        for (i=0 ; i<count ; i++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
+//             p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                p->texnum = flareparticletexture;
                p->scale = 2;
-               p->alpha = 255;
+               p->alpha = 192;
                p->die = cl.time + 0.0625 * (rand()&15);
                /*
                if (type == 0) // sparks
@@ -764,13 +792,9 @@ void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count)
        
        for (i=0 ; i<count ; i++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
+//             p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                p->texnum = bloodcloudparticletexture;
                p->scale = 12;
                p->alpha = 96 + (rand()&63);
@@ -801,13 +825,9 @@ void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb
        
        for (i=0 ; i<count ; i++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
+//             p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                p->texnum = flareparticletexture;
                p->scale = 6;
                p->alpha = 255;
@@ -858,12 +878,7 @@ void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb
        
        for (i=0 ; i<count ; i++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
                vel[0] = dir[0] + (rand()&31) - 16;
                vel[1] = dir[1] + (rand()&31) - 16;
@@ -872,6 +887,7 @@ 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->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                p->scale = 1.5;
                p->alpha = 255;
                p->die = t;
@@ -911,13 +927,9 @@ void R_LavaSplash (vec3_t org)
                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;
+                               ALLOCPARTICLE
                
+//                             p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                                p->texnum = flareparticletexture;
                                p->scale = 10;
                                p->alpha = 128;
@@ -957,13 +969,10 @@ void R_TeleportSplash (vec3_t org)
                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;
+                               ALLOCPARTICLE
                
+//                             p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+                               p->contents = 0;
                                p->texnum = particletexture;
                                p->scale = 2;
                                p->alpha = 255;
@@ -989,16 +998,12 @@ void R_TeleportSplash (vec3_t org)
                for (j=-24 ; j<24 ; 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->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                                p->texnum = flareparticletexture;
                                p->scale = 4;
-                               p->alpha = (1 + rand()&7) * 32;
+                               p->alpha = lhrandom(32,256);
                                p->die = cl.time + 5;
                                p->color = 254; //8 + (rand()&7);
                                p->type = pt_fadespark;
@@ -1016,7 +1021,7 @@ 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;
@@ -1045,13 +1050,9 @@ 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->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                p->vel[0] = p->vel[1] = p->vel[2] = 0;
                p->die = cl.time + 2;
 
@@ -1077,8 +1078,8 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
                                else
                                {
                                        dec = 0.02f;
-                                       p->texnum = smokeparticletexture;
-                                       p->scale = lhrandom(4, 7);
+                                       p->texnum = smokeparticletexture[rand()&7];
+                                       p->scale = lhrandom(8, 12);
                                        p->alpha = 64 + (rand()&31);
                                        p->color = (rand()&3)+12;
                                        p->type = pt_smoke;
@@ -1104,13 +1105,13 @@ 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 = lhrandom(8, 12);
+                               dec = 0.025f;
+                               p->texnum = smokeparticletexture[rand()&7];
+                               p->scale = lhrandom(6, 8);
                                p->alpha = 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;
@@ -1147,13 +1148,13 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
                                break;
 
                        case 4: // slight blood
-                               dec = 0.03f; // sparse trail
-                               p->texnum = bloodcloudparticletexture;
-                               p->scale = lhrandom(8,12);
-                               p->alpha = 255;
+                               dec = 0.025f; // sparse trail
+                               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;
+                               p->die = cl.time + 9999;
                                for (j=0 ; j<3 ; j++)
                                {
                                        p->vel[j] = (rand()&15)-8;
@@ -1163,8 +1164,8 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
 
                        case 6: // voor trail
                                dec = 0.05f; // sparse trail
-                               p->texnum = flareparticletexture;
-                               p->scale = lhrandom(4, 8);
+                               p->texnum = smokeparticletexture[rand()&7];
+                               p->scale = lhrandom(3, 5);
                                p->alpha = 255;
                                p->color = 9*16 + 8 + (rand()&3);
                                p->type = pt_fadespark2;
@@ -1178,8 +1179,8 @@ 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 = lhrandom(6, 10);
+                               p->texnum = smokeparticletexture[rand()&7];
+                               p->scale = lhrandom(8, 12);
                                p->alpha = 64;
                                p->color = (rand()&3)+12;
                                p->type = pt_smoke;
@@ -1201,7 +1202,6 @@ 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
 
        VectorSubtract (end, start, vec);
@@ -1210,14 +1210,10 @@ void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent)
        {
                len -= 3;
 
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
                
-               VectorCopy (vec3_origin, p->vel);
+//             p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+               p->vel[0] = p->vel[1] = p->vel[2] = 0;
 
                p->texnum = flareparticletexture;
                p->scale = 8;
@@ -1242,14 +1238,15 @@ R_DrawParticles
 ===============
 */
 extern cvar_t  sv_gravity;
+void R_CompleteLightPoint (vec3_t color, vec3_t p);
 
 void R_DrawParticles (void)
 {
        particle_t              *p, *kill;
        int                             i, r,g,b,a;
-       float                   grav, grav1, time1, time2, time3, dvel, frametime, scale, scale2;
+       float                   grav, grav1, time1, time2, time3, dvel, frametime, scale, scale2/*, f1, f2*/, minparticledist;
        byte                    *color24;
-       vec3_t                  up, right, uprightangles, forward2, up2, right2, v;
+       vec3_t                  up, right, uprightangles, forward2, up2, right2, tempcolor;
 
        // LordHavoc: early out condition
        if (!active_particles)
@@ -1270,6 +1267,9 @@ void R_DrawParticles (void)
        grav = (grav1 = frametime * sv_gravity.value) * 0.05;
        dvel = 1+4*frametime;
 
+       minparticledist = DotProduct(r_refdef.vieworg, vpn) + 16.0f;
+
+       // remove dead particles at beginning of list
        for ( ;; ) 
        {
                kill = active_particles;
@@ -1285,6 +1285,7 @@ void R_DrawParticles (void)
 
        for (p=active_particles ; p ; p=p->next)
        {
+               // remove dead particles following this one
                for ( ;; )
                {
                        kill = p->next;
@@ -1297,14 +1298,10 @@ void R_DrawParticles (void)
                        }
                        break;
                }
-               // LordHavoc: 'removed last in list' condition
-               if (!p)
-                       break;
 
-               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];
@@ -1316,7 +1313,15 @@ void R_DrawParticles (void)
                                g >>= 1;
                                b >>= 1;
                        }
+                       if (r_dynamicparticles.value)
+                       {
+                               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] + 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);
@@ -1334,15 +1339,40 @@ void R_DrawParticles (void)
                        transpolyend();
                }
 
-               p->org[0] += p->vel[0]*frametime;
-               p->org[1] += p->vel[1]*frametime;
-               p->org[2] += p->vel[2]*frametime;
+               /*
+               if (p->pushvel[0] || p->pushvel[1] || p->pushvel[2])
+               {
+                       p->org[0] += (p->vel[0]+p->pushvel[0])*frametime;
+                       p->org[1] += (p->vel[1]+p->pushvel[1])*frametime;
+                       p->org[2] += (p->vel[2]+p->pushvel[2])*frametime;
+                       f1 = sqrt(DotProduct(p->pushvel,p->pushvel));
+                       f2 = f1 - frametime * 32;
+                       if (f2 <= 0)
+                               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+                       else
+                       {
+                               f2 /= f1;
+                               p->pushvel[0] *= f2;
+                               p->pushvel[1] *= f2;
+                               p->pushvel[2] *= f2;
+                       }
+               }
+               else
+               {
+                       if (p->type != pt_smokecloud)
+                       {
+               */
+                               p->org[0] += p->vel[0]*frametime;
+                               p->org[1] += p->vel[1]*frametime;
+                               p->org[2] += p->vel[2]*frametime;
+               /*
+                       }
+               }
+               */
                
                switch (p->type)
                {
                case pt_static:
-                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
-                               p->die = -1;
                        break;
                case pt_fire:
                        p->ramp += time1;
@@ -1351,8 +1381,6 @@ void R_DrawParticles (void)
                        else
                                p->color = ramp3[(int)p->ramp];
                        p->vel[2] += grav;
-                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
-                               p->die = -1;
                        break;
 
                case pt_explode:
@@ -1369,47 +1397,41 @@ void R_DrawParticles (void)
 
                case pt_explode2:
                        p->ramp += time3;
-                       if (p->ramp >= 8 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
+                       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;
+//                             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;
-                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
-                               p->die = -1;
                        break;
 
                case pt_blob2:
                        for (i=0 ; i<2 ; i++)
                                p->vel[i] -= p->vel[i]*dvel;
                        p->vel[2] -= grav;
-                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
-                               p->die = -1;
                        break;
 
                case pt_grav:
                        p->vel[2] -= grav1;
-                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
-                               p->die = -1;
                        break;
                case pt_slowgrav:
                        p->vel[2] -= grav;
-                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
-                               p->die = -1;
                        break;
 // LordHavoc: gunshot spark showers
                case pt_dust:
                        p->ramp += time1;
                        p->scale -= frametime * 4;
-                       if (p->ramp >= 8 || p->scale <= 0 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
+                       p->alpha -= frametime * 48;
+                       if (p->ramp >= 8 || p->scale < 1 || p->alpha < 1)
                                p->die = -1;
                        else
                                p->color = ramp3[(int)p->ramp];
@@ -1417,8 +1439,8 @@ void R_DrawParticles (void)
                        break;
 // LordHavoc: for smoke trails
                case pt_smoke:
-                       p->scale += frametime * 4;
-                       p->alpha -= frametime * 48;
+                       p->scale += frametime * 6;
+                       p->alpha -= frametime * 128;
 //                     p->vel[2] += grav;
                        if (p->alpha < 1)
                                p->die = -1;
@@ -1430,8 +1452,6 @@ void R_DrawParticles (void)
                                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];
-                               if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY)
-                                       p->die = -1;
                        }
                        break;
                case pt_bulletpuff:
@@ -1442,8 +1462,13 @@ void R_DrawParticles (void)
                                p->die = -1;
                        break;
                case pt_bloodcloud:
-                       p->scale -= frametime * 24;
-                       p->alpha -= frametime * 128;
+                       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;
@@ -1451,39 +1476,52 @@ void R_DrawParticles (void)
                case pt_fadespark:
                        p->alpha -= frametime * 256;
                        p->vel[2] -= grav;
-                       if (p->alpha < 1 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
+                       if (p->alpha < 1)
                                p->die = -1;
                        break;
                case pt_fadespark2:
                        p->alpha -= frametime * 512;
                        p->vel[2] -= grav;
-                       if (p->alpha < 1 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
+                       if (p->alpha < 1)
                                p->die = -1;
                        break;
                case pt_fallfadespark:
                        p->alpha -= frametime * 256;
                        p->vel[2] -= grav1;
-                       if (p->alpha < 1 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
+                       if (p->alpha < 1)
                                p->die = -1;
                        break;
                case pt_fallfadespark2:
                        p->alpha -= frametime * 512;
                        p->vel[2] -= grav1;
-                       if (p->alpha < 1 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
+               case pt_fade:
+                       p->alpha -= frametime * 512;
+                       if (p->alpha < 1)
                                p->die = -1;
                        break;
                case pt_bubble:
+                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY)
+                               p->die = -1;
                        p->vel[2] += grav1 * 2;
                        if (p->vel[2] >= 200)
-                               p->vel[2] = 136+rand()&63;
+                               p->vel[2] = lhrandom(130, 200);
                        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->time2 = cl.time + lhrandom(0, 0.5);
+                               p->vel[0] = lhrandom(-32,32);
+                               p->vel[1] = lhrandom(-32,32);
                        }
                        p->alpha -= frametime * 64;
-                       if (p->alpha < 1 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY)
+                       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;
                }