]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_particles.c
removed \n from all Host_Error, Sys_Error, PRVM_ERROR, PF_ERROR calls, since Host_Err...
[xonotic/darkplaces.git] / cl_particles.c
index d93069f8d3df9c75a0aca1389ad904e90c9d61a7..b772d9ffe8f21abc2475cef2c0c39d77f9ed70a4 100644 (file)
@@ -25,9 +25,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define NUMVERTEXNORMALS       162
 siextern float r_avertexnormals[NUMVERTEXNORMALS][3];
 #define m_bytenormals r_avertexnormals
-#define VectorNormalizeFast VectorNormalize
 #define CL_PointQ1Contents(v) (Mod_PointInLeaf(v,cl.worldmodel)->contents)
-typedef unsigned char qbyte;
+typedef unsigned char unsigned char;
 #define cl_stainmaps.integer 0
 void R_Stain (vec3_t origin, float radius, int cr1, int cg1, int cb1, int ca1, int cr2, int cg2, int cb2, int ca2)
 {
@@ -46,16 +45,16 @@ void R_CalcBeam_Vertex3f (float *vert, vec3_t org1, vec3_t org2, float width)
        vec3_t right1, right2, diff, normal;
 
        VectorSubtract (org2, org1, normal);
-       VectorNormalizeFast (normal);
+       VectorNormalize (normal);
 
        // calculate 'right' vector for start
        VectorSubtract (r_vieworigin, org1, diff);
-       VectorNormalizeFast (diff);
+       VectorNormalize (diff);
        CrossProduct (normal, diff, right1);
 
        // calculate 'right' vector for end
        VectorSubtract (r_vieworigin, org2, diff);
-       VectorNormalizeFast (diff);
+       VectorNormalize (diff);
        CrossProduct (normal, diff, right2);
 
        vert[ 0] = org1[0] + width * right1[0];
@@ -71,7 +70,7 @@ void R_CalcBeam_Vertex3f (float *vert, vec3_t org1, vec3_t org2, float width)
        vert[10] = org2[1] + width * right2[1];
        vert[11] = org2[2] + width * right2[2];
 }
-void fractalnoise(qbyte *noise, int size, int startgrid)
+void fractalnoise(unsigned char *noise, int size, int startgrid)
 {
        int x, y, g, g2, amplitude, min, max, size1 = size - 1, sizepower, gridpower;
        int *noisebuf;
@@ -79,11 +78,17 @@ void fractalnoise(qbyte *noise, int size, int startgrid)
 
        for (sizepower = 0;(1 << sizepower) < size;sizepower++);
        if (size != (1 << sizepower))
-               Sys_Error("fractalnoise: size must be power of 2\n");
+       {
+               Con_Printf("fractalnoise: size must be power of 2\n");
+               return;
+       }
 
        for (gridpower = 0;(1 << gridpower) < startgrid;gridpower++);
        if (startgrid != (1 << gridpower))
-               Sys_Error("fractalnoise: grid must be power of 2\n");
+       {
+               Con_Printf("fractalnoise: grid must be power of 2\n");
+               return;
+       }
 
        startgrid = bound(0, startgrid, size);
 
@@ -129,7 +134,7 @@ void fractalnoise(qbyte *noise, int size, int startgrid)
        // normalize noise and copy to output
        for (y = 0;y < size;y++)
                for (x = 0;x < size;x++)
-                       *noise++ = (qbyte) (((n(x,y) - min) * 256) / max);
+                       *noise++ = (unsigned char) (((n(x,y) - min) * 256) / max);
        free(noisebuf);
 #undef n
 }
@@ -145,14 +150,14 @@ void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up)
        right[0] -= d * forward[0];
        right[1] -= d * forward[1];
        right[2] -= d * forward[2];
-       VectorNormalizeFast(right);
+       VectorNormalize(right);
        CrossProduct(right, forward, up);
 }
 #if QW
 #include "pmove.h"
 extern qboolean PM_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, pmtrace_t *trace);
 #endif
-float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int hitbmodels, void **hitent, int hitsupercontentsmask)
+trace_t CL_TraceBox (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hitbmodels, int *hitent, int hitsupercontentsmask, qboolean hitplayers)
 {
 #if QW
        pmtrace_t trace;
@@ -167,9 +172,7 @@ float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int
 #else
        RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace);
 #endif
-       VectorCopy(trace.endpos, impact);
-       VectorCopy(trace.plane.normal, normal);
-       return trace.fraction;
+       return trace;
 }
 #else
 #include "cl_collision.h"
@@ -200,30 +203,31 @@ typedef struct particletype_s
 {
        pblend_t blendmode;
        porientation_t orientation;
+       qboolean lighting;
 }
 particletype_t;
 
 typedef enum
 {
-       pt_alphastatic, pt_static, pt_spark, pt_beam, pt_rain, pt_raindecal, pt_snow, pt_bubble, pt_blood, pt_grow, pt_decal, pt_entityparticle, pt_total
+       pt_alphastatic, pt_static, pt_spark, pt_beam, pt_rain, pt_raindecal, pt_snow, pt_bubble, pt_blood, pt_smoke, pt_decal, pt_entityparticle, pt_total
 }
 ptype_t;
 
 // must match ptype_t values
 particletype_t particletype[pt_total] =
 {
-       {PBLEND_ALPHA, PARTICLE_BILLBOARD}, //pt_alphastatic
-       {PBLEND_ADD, PARTICLE_BILLBOARD}, //pt_static
-       {PBLEND_ADD, PARTICLE_SPARK}, //pt_spark
-       {PBLEND_ADD, PARTICLE_BEAM}, //pt_beam
-       {PBLEND_ADD, PARTICLE_SPARK}, //pt_rain
-       {PBLEND_ADD, PARTICLE_ORIENTED_DOUBLESIDED}, //pt_raindecal
-       {PBLEND_ADD, PARTICLE_BILLBOARD}, //pt_snow
-       {PBLEND_ADD, PARTICLE_BILLBOARD}, //pt_bubble
-       {PBLEND_MOD, PARTICLE_BILLBOARD}, //pt_blood
-       {PBLEND_ADD, PARTICLE_BILLBOARD}, //pt_grow
-       {PBLEND_MOD, PARTICLE_ORIENTED_DOUBLESIDED}, //pt_decal
-       {PBLEND_ALPHA, PARTICLE_BILLBOARD}, //pt_entityparticle
+       {PBLEND_ALPHA, PARTICLE_BILLBOARD, false}, //pt_alphastatic
+       {PBLEND_ADD, PARTICLE_BILLBOARD, false}, //pt_static
+       {PBLEND_ADD, PARTICLE_SPARK, false}, //pt_spark
+       {PBLEND_ADD, PARTICLE_BEAM, false}, //pt_beam
+       {PBLEND_ADD, PARTICLE_SPARK, false}, //pt_rain
+       {PBLEND_ADD, PARTICLE_ORIENTED_DOUBLESIDED, false}, //pt_raindecal
+       {PBLEND_ADD, PARTICLE_BILLBOARD, false}, //pt_snow
+       {PBLEND_ADD, PARTICLE_BILLBOARD, false}, //pt_bubble
+       {PBLEND_MOD, PARTICLE_BILLBOARD, false}, //pt_blood
+       {PBLEND_ADD, PARTICLE_BILLBOARD, false}, //pt_smoke
+       {PBLEND_MOD, PARTICLE_ORIENTED_DOUBLESIDED, false}, //pt_decal
+       {PBLEND_ALPHA, PARTICLE_BILLBOARD, false}, //pt_entityparticle
 };
 
 typedef struct particle_s
@@ -239,13 +243,11 @@ typedef struct particle_s
        float           bounce; // how much bounce-back from a surface the particle hits (0 = no physics, 1 = stop and slide, 2 = keep bouncing forever, 1.5 is typical)
        float           gravity; // how much gravity affects this particle (1.0 = normal gravity, 0.0 = none)
        float           friction; // how much air friction affects this object (objects with a low mass/size ratio tend to get more air friction)
-       qbyte           color[4];
-#ifndef WORKINGLQUAKE
-       entity_render_t *owner; // decal stuck to this entity
+       unsigned char           color[4];
+       unsigned short owner; // decal stuck to this entity
        model_t         *ownermodel; // model the decal is stuck to (used to make sure the entity is still alive)
        vec3_t          relativeorigin; // decal at this location in entity's coordinate space
        vec3_t          relativedirection; // decal oriented this way relative to entity's coordinate space
-#endif
 }
 particle_t;
 
@@ -324,10 +326,6 @@ cvar_t cl_decals = {CVAR_SAVE, "cl_decals", "0"};
 cvar_t cl_decals_time = {CVAR_SAVE, "cl_decals_time", "0"};
 cvar_t cl_decals_fadetime = {CVAR_SAVE, "cl_decals_fadetime", "20"};
 
-#ifndef WORKINGLQUAKE
-static mempool_t *cl_part_mempool;
-#endif
-
 void CL_Particles_Clear(void)
 {
        cl_numparticles = 0;
@@ -383,8 +381,7 @@ void CL_Particles_Init (void)
 #ifdef WORKINGLQUAKE
        particles = (particle_t *) Hunk_AllocName(cl_maxparticles * sizeof(particle_t), "particles");
 #else
-       cl_part_mempool = Mem_AllocPool("CL_Part", 0, NULL);
-       particles = (particle_t *) Mem_Alloc(cl_part_mempool, cl_maxparticles * sizeof(particle_t));
+       particles = (particle_t *) Mem_Alloc(cl_mempool, cl_maxparticles * sizeof(particle_t));
 #endif
        CL_Particles_Clear();
 }
@@ -393,8 +390,6 @@ void CL_Particles_Shutdown (void)
 {
 #ifdef WORKINGLQUAKE
        // No clue what to do here...
-#else
-       Mem_FreePool (&cl_part_mempool);
 #endif
 }
 
@@ -459,7 +454,7 @@ particle_t *particle(particletype_t *ptype, int pcolor1, int pcolor2, int ptex,
        return part;
 }
 
-void CL_SpawnDecalParticleForSurface(void *hitent, const vec3_t org, const vec3_t normal, int color1, int color2, int texnum, float size, float alpha)
+void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t normal, int color1, int color2, int texnum, float size, float alpha)
 {
        particle_t *p;
        if (!cl_decals.integer)
@@ -470,9 +465,9 @@ void CL_SpawnDecalParticleForSurface(void *hitent, const vec3_t org, const vec3_
                p->time2 = cl.time;
 #ifndef WORKINGLQUAKE
                p->owner = hitent;
-               p->ownermodel = p->owner->model;
-               Matrix4x4_Transform(&p->owner->inversematrix, org, p->relativeorigin);
-               Matrix4x4_Transform3x3(&p->owner->inversematrix, normal, p->relativedirection);
+               p->ownermodel = cl_entities[p->owner].render.model;
+               Matrix4x4_Transform(&cl_entities[p->owner].render.inversematrix, org, p->relativeorigin);
+               Matrix4x4_Transform3x3(&cl_entities[p->owner].render.inversematrix, normal, p->relativedirection);
                VectorAdd(p->relativeorigin, p->relativedirection, p->relativeorigin);
 #endif
        }
@@ -482,24 +477,21 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size,
 {
        int i;
        float bestfrac, bestorg[3], bestnormal[3];
-       float frac, v[3], normal[3], org2[3];
-#ifdef WORKINGLQUAKE
-       void *besthitent = NULL, *hitent;
-#else
-       entity_render_t *besthitent = NULL, *hitent;
-#endif
+       float org2[3];
+       int besthitent = 0, hitent;
+       trace_t trace;
        bestfrac = 10;
        for (i = 0;i < 32;i++)
        {
                VectorRandom(org2);
                VectorMA(org, maxdist, org2, org2);
-               frac = CL_TraceLine(org, org2, v, normal, true, &hitent, SUPERCONTENTS_SOLID);
-               if (bestfrac > frac)
+               trace = CL_TraceBox(org, vec3_origin, vec3_origin, org2, true, &hitent, SUPERCONTENTS_SOLID, false);
+               if (bestfrac > trace.fraction)
                {
-                       bestfrac = frac;
+                       bestfrac = trace.fraction;
                        besthitent = hitent;
-                       VectorCopy(v, bestorg);
-                       VectorCopy(normal, bestnormal);
+                       VectorCopy(trace.endpos, bestorg);
+                       VectorCopy(trace.plane.normal, bestnormal);
                }
        }
        if (bestfrac < 1)
@@ -566,7 +558,7 @@ void CL_ReadPointFile_f (void)
 #if WORKINGLQUAKE
        pointfile = COM_LoadTempFile (name);
 #else
-       pointfile = FS_LoadFile(name, tempmempool, true);
+       pointfile = (char *)FS_LoadFile(name, tempmempool, true, NULL);
 #endif
        if (!pointfile)
        {
@@ -575,6 +567,7 @@ void CL_ReadPointFile_f (void)
        }
 
        Con_Printf("Reading %s...\n", name);
+       VectorClear(leakorg);
        c = 0;
        s = 0;
        pointfilepos = pointfile;
@@ -665,6 +658,7 @@ CL_ParticleExplosion
 void CL_ParticleExplosion (vec3_t org)
 {
        int i;
+       trace_t trace;
        //vec3_t v;
        //vec3_t v2;
        if (cl_stainmaps.integer)
@@ -698,13 +692,14 @@ void CL_ParticleExplosion (vec3_t org)
                                        v[0] = org[0] + lhrandom(-48, 48);
                                        v[1] = org[1] + lhrandom(-48, 48);
                                        v[2] = org[2] + lhrandom(-48, 48);
-                                       if (CL_TraceLine(org, v, v2, NULL, true, NULL, SUPERCONTENTS_SOLID) >= 0.1)
+                                       trace = CL_TraceBox(org, vec3_origin, vec3_origin, v, true, NULL, SUPERCONTENTS_SOLID, false);
+                                       if (trace.fraction >= 0.1)
                                                break;
                                }
-                               VectorSubtract(v2, org, v2);
+                               VectorSubtract(trace.endpos, org, v2);
 #endif
                                VectorScale(v2, 2.0f, v2);
-                               particle(particletype + pt_static, 0xFFFFFF, 0xFFFFFF, tex_smoke[rand()&7], 12, 32, 64, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0);
+                               particle(particletype + pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 12, 32, 64, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0);
                        }
                }
 
@@ -806,8 +801,9 @@ void CL_SparkShower (vec3_t org, vec3_t dir, int count, vec_t gravityscale)
 
 void CL_Smoke (vec3_t org, vec3_t dir, int count)
 {
-       vec3_t org2, org3;
+       vec3_t org2;
        int k;
+       trace_t trace;
 
        if (!cl_particles.integer) return;
 
@@ -820,8 +816,8 @@ void CL_Smoke (vec3_t org, vec3_t dir, int count)
                        org2[0] = org[0] + 0.125f * lhrandom(-count, count);
                        org2[1] = org[1] + 0.125f * lhrandom(-count, count);
                        org2[2] = org[2] + 0.125f * lhrandom(-count, count);
-                       CL_TraceLine(org, org2, org3, NULL, true, NULL, SUPERCONTENTS_SOLID);
-                       particle(particletype + pt_grow, 0x101010, 0x202020, tex_smoke[rand()&7], 3, (1.0f / cl_particles_quality.value) * 255, (1.0f / cl_particles_quality.value) * 1024, 0, 0, org3[0], org3[1], org3[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 0);
+                       trace = CL_TraceBox(org, vec3_origin, vec3_origin, org2, true, NULL, SUPERCONTENTS_SOLID, false);
+                       particle(particletype + pt_smoke, 0x101010, 0x202020, tex_smoke[rand()&7], 3, (1.0f / cl_particles_quality.value) * 255, (1.0f / cl_particles_quality.value) * 1024, 0, 0, trace.endpos[0], trace.endpos[1], trace.endpos[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 0);
                }
        }
 }
@@ -844,7 +840,8 @@ static float bloodcount = 0;
 void CL_BloodPuff (vec3_t org, vec3_t vel, int count)
 {
        float s;
-       vec3_t org2, org3;
+       vec3_t org2;
+       trace_t trace;
        // bloodcount is used to accumulate counts too small to cause a blood particle
        if (!cl_particles.integer) return;
        if (!cl_particles_blood.integer) return;
@@ -859,8 +856,8 @@ void CL_BloodPuff (vec3_t org, vec3_t vel, int count)
                org2[0] = org[0] + 0.125f * lhrandom(-bloodcount, bloodcount);
                org2[1] = org[1] + 0.125f * lhrandom(-bloodcount, bloodcount);
                org2[2] = org[2] + 0.125f * lhrandom(-bloodcount, bloodcount);
-               CL_TraceLine(org, org2, org3, NULL, true, NULL, SUPERCONTENTS_SOLID);
-               particle(particletype + pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, cl_particles_blood_alpha.value * 768 / cl_particles_quality.value, cl_particles_blood_alpha.value * 384 / cl_particles_quality.value, 0, -1, org3[0], org3[1], org3[2], vel[0] + lhrandom(-s, s), vel[1] + lhrandom(-s, s), vel[2] + lhrandom(-s, s), 1);
+               trace = CL_TraceBox(org, vec3_origin, vec3_origin, org2, true, NULL, SUPERCONTENTS_SOLID, false);
+               particle(particletype + pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, cl_particles_blood_alpha.value * 768 / cl_particles_quality.value, cl_particles_blood_alpha.value * 384 / cl_particles_quality.value, 0, -1, trace.endpos[0], trace.endpos[1], trace.endpos[2], vel[0] + lhrandom(-s, s), vel[1] + lhrandom(-s, s), vel[2] + lhrandom(-s, s), 1);
                bloodcount -= 16 / cl_particles_quality.value;
        }
 }
@@ -915,6 +912,7 @@ void CL_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int color
 {
        int k;
        float t, z, minz, maxz;
+       particle_t *p;
        if (!cl_particles.integer) return;
        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;}
@@ -950,13 +948,15 @@ void CL_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int color
                {
                        k = particlepalette[colorbase + (rand()&3)];
                        if (gamemode == GAME_GOODVSBAD2)
-                               particle(particletype + pt_snow, k, k, tex_particle, 20, lhrandom(64, 128) / cl_particles_quality.value, 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0);
+                               p = particle(particletype + pt_snow, k, k, tex_particle, 20, lhrandom(64, 128) / cl_particles_quality.value, 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0);
                        else
-                               particle(particletype + pt_snow, k, k, tex_particle, 1, lhrandom(64, 128) / cl_particles_quality.value, 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0);
+                               p = particle(particletype + pt_snow, k, k, tex_particle, 1, lhrandom(64, 128) / cl_particles_quality.value, 0, 0, -1, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz), dir[0], dir[1], dir[2], 0);
+                       if (p)
+                               VectorCopy(p->vel, p->relativedirection);
                }
                break;
        default:
-               Host_Error("CL_ParticleRain: unknown type %i (0 = rain, 1 = snow)\n", type);
+               Con_Printf ("CL_ParticleRain: unknown type %i (0 = rain, 1 = snow)\n", type);
        }
 }
 
@@ -983,7 +983,7 @@ void CL_Stardust (vec3_t mins, vec3_t maxs, int count)
                o[1] = lhrandom(mins[1], maxs[1]);
                o[2] = lhrandom(mins[2], maxs[2]);
                VectorSubtract(o, center, v);
-               VectorNormalizeFast(v);
+               VectorNormalize(v);
                VectorScale(v, 100, v);
                v[2] += sv_gravity.value * 0.15f;
                particle(particletype + pt_static, 0x903010, 0xFFD030, tex_particle, 1.5, lhrandom(64, 128) / cl_particles_quality.value, 128 / cl_particles_quality.value, 1, 0, o[0], o[1], o[2], v[0], v[1], v[2], 0.2);
@@ -1147,7 +1147,7 @@ void CL_RocketTrail (vec3_t start, vec3_t end, int type, int color, entity_t *en
                                dec = qd*3;
                                if (smoke)
                                {
-                                       particle(particletype + pt_grow, 0x303030, 0x606060, tex_smoke[rand()&7], 3, qd*cl_particles_smoke_alpha.value*125, qd*cl_particles_smoke_alphafade.value*125, 0, 0, pos[0], pos[1], pos[2], lhrandom(-5, 5), lhrandom(-5, 5), lhrandom(-5, 5), 0);
+                                       particle(particletype + pt_smoke, 0x303030, 0x606060, tex_smoke[rand()&7], 3, qd*cl_particles_smoke_alpha.value*125, qd*cl_particles_smoke_alphafade.value*125, 0, 0, pos[0], pos[1], pos[2], lhrandom(-5, 5), lhrandom(-5, 5), lhrandom(-5, 5), 0);
                                        particle(particletype + pt_static, 0x801010, 0xFFA020, tex_smoke[rand()&7], 3, qd*cl_particles_smoke_alpha.value*288, qd*cl_particles_smoke_alphafade.value*1400, 0, 0, pos[0], pos[1], pos[2], lhrandom(-20, 20), lhrandom(-20, 20), lhrandom(-20, 20), 0);
                                }
                                if (bubbles)
@@ -1158,7 +1158,7 @@ void CL_RocketTrail (vec3_t start, vec3_t end, int type, int color, entity_t *en
                                // FIXME: make it gradually stop smoking
                                dec = qd*3;
                                if (smoke)
-                                       particle(particletype + pt_grow, 0x303030, 0x606060, tex_smoke[rand()&7], 3, qd*cl_particles_smoke_alpha.value*100, qd*cl_particles_smoke_alphafade.value*100, 0, 0, pos[0], pos[1], pos[2], lhrandom(-5, 5), lhrandom(-5, 5), lhrandom(-5, 5), 0);
+                                       particle(particletype + pt_smoke, 0x303030, 0x606060, tex_smoke[rand()&7], 3, qd*cl_particles_smoke_alpha.value*100, qd*cl_particles_smoke_alphafade.value*100, 0, 0, pos[0], pos[1], pos[2], lhrandom(-5, 5), lhrandom(-5, 5), lhrandom(-5, 5), 0);
                                break;
 
 
@@ -1215,6 +1215,8 @@ void CL_RocketTrail (vec3_t start, vec3_t end, int type, int color, entity_t *en
                                        particle(particletype + pt_alphastatic, color, color, tex_particle, 5, qd*128, qd*320, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0);
                                break;
 #endif
+                       default:
+                               Sys_Error("CL_RocketTrail: unknown trail type %i", type);
                }
 
                // advance to next time and position
@@ -1244,7 +1246,7 @@ void CL_Tei_Smoke(const vec3_t org, const vec3_t dir, int count)
        // smoke puff
        if (cl_particles_smoke.integer)
                for (f = 0;f < count;f += 4.0f / cl_particles_quality.value)
-                       particle(particletype + pt_grow, 0x202020, 0x404040, tex_smoke[rand()&7], 5, 255 / cl_particles_quality.value, 512 / cl_particles_quality.value, 0, 0, org[0] + 0.125f * lhrandom(-count, count), org[1] + 0.125f * lhrandom (-count, count), org[2] + 0.125f * lhrandom(-count, count), dir[0] + lhrandom(-count, count) * 0.5f, dir[1] + lhrandom(-count, count) * 0.5f, dir[2] + lhrandom(-count, count) * 0.5f, 0);
+                       particle(particletype + pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 5, 255 / cl_particles_quality.value, 512 / cl_particles_quality.value, 0, 0, org[0] + 0.125f * lhrandom(-count, count), org[1] + 0.125f * lhrandom (-count, count), org[2] + 0.125f * lhrandom(-count, count), dir[0] + lhrandom(-count, count) * 0.5f, dir[1] + lhrandom(-count, count) * 0.5f, dir[2] + lhrandom(-count, count) * 0.5f, 0);
 }
 
 void CL_Tei_PlasmaHit(const vec3_t org, const vec3_t dir, int count)
@@ -1259,7 +1261,7 @@ void CL_Tei_PlasmaHit(const vec3_t org, const vec3_t dir, int count)
        // smoke puff
        if (cl_particles_smoke.integer)
                for (f = 0;f < count;f += 4.0f / cl_particles_quality.value)
-                       particle(particletype + pt_grow, 0x202020, 0x404040, tex_smoke[rand()&7], 5, 255 / cl_particles_quality.value, 512 / cl_particles_quality.value, 0, 0, org[0] + 0.125f * lhrandom(-count, count), org[1] + 0.125f * lhrandom (-count, count), org[2] + 0.125f * lhrandom(-count, count), dir[0] + lhrandom(-count, count), dir[1] + lhrandom(-count, count), dir[2] + lhrandom(-count, count), 0);
+                       particle(particletype + pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 5, 255 / cl_particles_quality.value, 512 / cl_particles_quality.value, 0, 0, org[0] + 0.125f * lhrandom(-count, count), org[1] + 0.125f * lhrandom (-count, count), org[2] + 0.125f * lhrandom(-count, count), dir[0] + lhrandom(-count, count), dir[1] + lhrandom(-count, count), dir[2] + lhrandom(-count, count), 0);
 
        // sparks
        if (cl_particles_sparks.integer)
@@ -1276,12 +1278,9 @@ void CL_MoveParticles (void)
 {
        particle_t *p;
        int i, maxparticle, j, a, content;
-       float gravity, dvel, bloodwaterfade, frametime, f, dist, normal[3], v[3], org[3], oldorg[3];
-#ifdef WORKINGLQUAKE
-       void *hitent;
-#else
-       entity_render_t *hitent;
-#endif
+       float gravity, dvel, bloodwaterfade, frametime, f, dist, org[3], oldorg[3];
+       int hitent;
+       trace_t trace;
 
        // LordHavoc: early out condition
        if (!cl_numparticles)
@@ -1326,17 +1325,17 @@ void CL_MoveParticles (void)
                                if (p->type == particletype + pt_rain)
                                {
                                        // raindrop - splash on solid/water/slime/lava
-                                       if (CL_TraceLine(oldorg, p->org, v, normal, true, &hitent, SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK) < 1)
+                                       trace = CL_TraceBox(oldorg, vec3_origin, vec3_origin, p->org, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK, false);
+                                       if (trace.fraction < 1)
                                        {
-                                               VectorCopy(v, p->org);
-                                               // splash
-                                               p->type = particletype + pt_raindecal;
                                                // convert from a raindrop particle to a rainsplash decal
+                                               VectorCopy(trace.endpos, p->org);
+                                               VectorCopy(trace.plane.normal, p->vel);
+                                               VectorAdd(p->org, p->vel, p->org);
+                                               p->type = particletype + pt_raindecal;
                                                p->texnum = tex_rainsplash[0];
                                                p->time2 = cl.time;
                                                p->alphafade = p->alpha / 0.4;
-                                               VectorCopy(normal, p->vel);
-                                               VectorAdd(p->org, normal, p->org);
                                                p->bounce = 0;
                                                p->friction = 0;
                                                p->gravity = 0;
@@ -1346,12 +1345,16 @@ void CL_MoveParticles (void)
                                else if (p->type == particletype + pt_blood)
                                {
                                        // blood - splash on solid
-                                       if (CL_TraceLine(oldorg, p->org, v, normal, true, &hitent, SUPERCONTENTS_SOLID) < 1)
+                                       trace = CL_TraceBox(oldorg, vec3_origin, vec3_origin, p->org, true, &hitent, SUPERCONTENTS_SOLID, false);
+                                       if (trace.fraction < 1)
                                        {
-                                               VectorCopy(v, p->org);
+                                               // convert from a blood particle to a blood decal
+                                               VectorCopy(trace.endpos, p->org);
+                                               VectorCopy(trace.plane.normal, p->vel);
+                                               VectorAdd(p->org, p->vel, p->org);
 #ifndef WORKINGLQUAKE
                                                if (cl_stainmaps.integer)
-                                                       R_Stain(v, 32, 32, 16, 16, p->alpha * p->size * (1.0f / 40.0f), 192, 48, 48, p->alpha * p->size * (1.0f / 40.0f));
+                                                       R_Stain(p->org, 32, 32, 16, 16, p->alpha * p->size * (1.0f / 40.0f), 192, 48, 48, p->alpha * p->size * (1.0f / 40.0f));
 #endif
                                                if (!cl_decals.integer)
                                                {
@@ -1360,19 +1363,15 @@ void CL_MoveParticles (void)
                                                }
 
                                                p->type = particletype + pt_decal;
-                                               // convert from a blood particle to a blood decal
                                                p->texnum = tex_blooddecal[rand()&7];
 #ifndef WORKINGLQUAKE
                                                p->owner = hitent;
-                                               p->ownermodel = hitent->model;
-                                               Matrix4x4_Transform(&hitent->inversematrix, v, p->relativeorigin);
-                                               Matrix4x4_Transform3x3(&hitent->inversematrix, normal, p->relativedirection);
-                                               VectorAdd(p->relativeorigin, p->relativedirection, p->relativeorigin);
+                                               p->ownermodel = cl_entities[hitent].render.model;
+                                               Matrix4x4_Transform(&cl_entities[hitent].render.inversematrix, p->org, p->relativeorigin);
+                                               Matrix4x4_Transform3x3(&cl_entities[hitent].render.inversematrix, p->vel, p->relativedirection);
 #endif
                                                p->time2 = cl.time;
                                                p->alphafade = 0;
-                                               VectorCopy(normal, p->vel);
-                                               VectorAdd(p->org, normal, p->org);
                                                p->bounce = 0;
                                                p->friction = 0;
                                                p->gravity = 0;
@@ -1381,9 +1380,10 @@ void CL_MoveParticles (void)
                                }
                                else
                                {
-                                       if (CL_TraceLine(oldorg, p->org, v, normal, true, &hitent, SUPERCONTENTS_SOLID) < 1)
+                                       trace = CL_TraceBox(oldorg, vec3_origin, vec3_origin, p->org, true, NULL, SUPERCONTENTS_SOLID, false);
+                                       if (trace.fraction < 1)
                                        {
-                                               VectorCopy(v, p->org);
+                                               VectorCopy(trace.endpos, p->org);
                                                if (p->bounce < 0)
                                                {
                                                        p->type = NULL;
@@ -1391,8 +1391,8 @@ void CL_MoveParticles (void)
                                                }
                                                else
                                                {
-                                                       dist = DotProduct(p->vel, normal) * -p->bounce;
-                                                       VectorMA(p->vel, dist, normal, p->vel);
+                                                       dist = DotProduct(p->vel, trace.plane.normal) * -p->bounce;
+                                                       VectorMA(p->vel, dist, trace.plane.normal, p->vel);
                                                        if (DotProduct(p->vel, p->vel) < 0.03)
                                                                VectorClear(p->vel);
                                                }
@@ -1475,9 +1475,9 @@ void CL_MoveParticles (void)
                                {
                                        // snow flutter
                                        p->time2 = cl.time + (rand() & 3) * 0.1;
-                                       p->vel[0] += lhrandom(-32, 32);
-                                       p->vel[1] += lhrandom(-32, 32);
-                                       p->vel[2] += lhrandom(-32, 32);
+                                       p->vel[0] = p->relativedirection[0] + lhrandom(-32, 32);
+                                       p->vel[1] = p->relativedirection[1] + lhrandom(-32, 32);
+                                       //p->vel[2] = p->relativedirection[2] + lhrandom(-32, 32);
                                }
 #ifdef WORKINGLQUAKE
                                a = CL_PointQ1Contents(p->org);
@@ -1488,17 +1488,17 @@ void CL_MoveParticles (void)
 #endif
                                        p->type = NULL;
                                break;
-                       case pt_grow:
-                               p->size += frametime * 15;
+                       case pt_smoke:
+                               //p->size += frametime * 15;
                                break;
                        case pt_decal:
                                // FIXME: this has fairly wacky handling of alpha
-                               p->alphafade = cl.time > (p->time2 + cl_decals_time.value) ? (p->alpha / cl_decals_fadetime.value) : 0;
+                               p->alphafade = cl.time > (p->time2 + cl_decals_time.value) ? (255 / cl_decals_fadetime.value) : 0;
 #ifndef WORKINGLQUAKE
-                               if (p->owner->model == p->ownermodel)
+                               if (cl_entities[p->owner].render.model == p->ownermodel)
                                {
-                                       Matrix4x4_Transform(&p->owner->matrix, p->relativeorigin, p->org);
-                                       Matrix4x4_Transform3x3(&p->owner->matrix, p->relativedirection, p->vel);
+                                       Matrix4x4_Transform(&cl_entities[p->owner].render.matrix, p->relativeorigin, p->org);
+                                       Matrix4x4_Transform3x3(&cl_entities[p->owner].render.matrix, p->relativedirection, p->vel);
                                }
                                else
                                        p->type = NULL;
@@ -1522,7 +1522,7 @@ void CL_MoveParticles (void)
 
 #define MAX_PARTICLETEXTURES 64
 // particletexture_t is a rectangle in the particlefonttexture
-typedef struct
+typedef struct particletexture_s
 {
        rtexture_t *texture;
        float s1, t1, s2, t2;
@@ -1542,7 +1542,7 @@ static cvar_t r_drawparticles = {0, "r_drawparticles", "1"};
 #define PARTICLETEXTURESIZE 64
 #define PARTICLEFONTSIZE (PARTICLETEXTURESIZE*8)
 
-static qbyte shadebubble(float dx, float dy, vec3_t light)
+static unsigned char shadebubble(float dx, float dy, vec3_t light)
 {
        float dz, f, dot;
        vec3_t normal;
@@ -1569,13 +1569,13 @@ static qbyte shadebubble(float dx, float dy, vec3_t light)
                f *= 128;
                f += 16; // just to give it a haze so you can see the outline
                f = bound(0, f, 255);
-               return (qbyte) f;
+               return (unsigned char) f;
        }
        else
                return 0;
 }
 
-static void setuptex(int texnum, qbyte *data, qbyte *particletexturedata)
+static void setuptex(int texnum, unsigned char *data, unsigned char *particletexturedata)
 {
        int basex, basey, y;
        basex = ((texnum >> 0) & 7) * PARTICLETEXTURESIZE;
@@ -1588,11 +1588,11 @@ static void setuptex(int texnum, qbyte *data, qbyte *particletexturedata)
                memcpy(particletexturedata + ((basey + y) * PARTICLEFONTSIZE + basex) * 4, data + y * PARTICLETEXTURESIZE * 4, PARTICLETEXTURESIZE * 4);
 }
 
-void particletextureblotch(qbyte *data, float radius, float red, float green, float blue, float alpha)
+void particletextureblotch(unsigned char *data, float radius, float red, float green, float blue, float alpha)
 {
        int x, y;
        float cx, cy, dx, dy, f, iradius;
-       qbyte *d;
+       unsigned char *d;
        cx = (lhrandom(radius + 1, PARTICLETEXTURESIZE - 2 - radius) + lhrandom(radius + 1, PARTICLETEXTURESIZE - 2 - radius)) * 0.5f;
        cy = (lhrandom(radius + 1, PARTICLETEXTURESIZE - 2 - radius) + lhrandom(radius + 1, PARTICLETEXTURESIZE - 2 - radius)) * 0.5f;
        iradius = 1.0f / radius;
@@ -1615,7 +1615,7 @@ void particletextureblotch(qbyte *data, float radius, float red, float green, fl
        }
 }
 
-void particletextureclamp(qbyte *data, int minr, int ming, int minb, int maxr, int maxg, int maxb)
+void particletextureclamp(unsigned char *data, int minr, int ming, int minb, int maxr, int maxg, int maxb)
 {
        int i;
        for (i = 0;i < PARTICLETEXTURESIZE*PARTICLETEXTURESIZE;i++, data += 4)
@@ -1626,7 +1626,7 @@ void particletextureclamp(qbyte *data, int minr, int ming, int minb, int maxr, i
        }
 }
 
-void particletextureinvert(qbyte *data)
+void particletextureinvert(unsigned char *data)
 {
        int i;
        for (i = 0;i < PARTICLETEXTURESIZE*PARTICLETEXTURESIZE;i++, data += 4)
@@ -1638,10 +1638,10 @@ void particletextureinvert(qbyte *data)
 }
 
 // Those loops are in a separate function to work around an optimization bug in Mac OS X's GCC
-static void R_InitBloodTextures (qbyte *particletexturedata)
+static void R_InitBloodTextures (unsigned char *particletexturedata)
 {
        int i, j, k, m;
-       qbyte data[PARTICLETEXTURESIZE][PARTICLETEXTURESIZE][4];
+       unsigned char data[PARTICLETEXTURESIZE][PARTICLETEXTURESIZE][4];
 
        // blood particles
        for (i = 0;i < 8;i++)
@@ -1673,9 +1673,9 @@ static void R_InitParticleTexture (void)
 {
        int x, y, d, i, k, m;
        float dx, dy, radius, f, f2;
-       qbyte data[PARTICLETEXTURESIZE][PARTICLETEXTURESIZE][4], noise3[64][64], data2[64][16][4];
+       unsigned char data[PARTICLETEXTURESIZE][PARTICLETEXTURESIZE][4], noise3[64][64], data2[64][16][4];
        vec3_t light;
-       qbyte *particletexturedata;
+       unsigned char *particletexturedata;
 
        // a note: decals need to modulate (multiply) the background color to
        // properly darken it (stain), and they need to be able to alpha fade,
@@ -1686,7 +1686,7 @@ static void R_InitParticleTexture (void)
        // and white on black background) so we can alpha fade it to black, then
        // we invert it again during the blendfunc to make it work...
 
-       particletexturedata = Mem_Alloc(tempmempool, PARTICLEFONTSIZE*PARTICLEFONTSIZE*4);
+       particletexturedata = (unsigned char *)Mem_Alloc(tempmempool, PARTICLEFONTSIZE*PARTICLEFONTSIZE*4);
        memset(particletexturedata, 255, PARTICLEFONTSIZE*PARTICLEFONTSIZE*4);
 
        // smoke
@@ -1695,7 +1695,7 @@ static void R_InitParticleTexture (void)
                memset(&data[0][0][0], 255, sizeof(data));
                do
                {
-                       qbyte noise1[PARTICLETEXTURESIZE*2][PARTICLETEXTURESIZE*2], noise2[PARTICLETEXTURESIZE*2][PARTICLETEXTURESIZE*2];
+                       unsigned char noise1[PARTICLETEXTURESIZE*2][PARTICLETEXTURESIZE*2], noise2[PARTICLETEXTURESIZE*2][PARTICLETEXTURESIZE*2];
 
                        fractalnoise(&noise1[0][0], PARTICLETEXTURESIZE*2, PARTICLETEXTURESIZE/8);
                        fractalnoise(&noise2[0][0], PARTICLETEXTURESIZE*2, PARTICLETEXTURESIZE/4);
@@ -1711,7 +1711,7 @@ static void R_InitParticleTexture (void)
                                                d = d * (1-(dx*dx+dy*dy));
                                        d = (d * noise1[y][x]) >> 7;
                                        d = bound(0, d, 255);
-                                       data[y][x][3] = (qbyte) d;
+                                       data[y][x][3] = (unsigned char) d;
                                        if (m < d)
                                                m = d;
                                }
@@ -1750,7 +1750,7 @@ static void R_InitParticleTexture (void)
                        dx = (x - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1);
                        d = 256 * (1 - (dx*dx+dy*dy));
                        d = bound(0, d, 255);
-                       data[y][x][3] = (qbyte) d;
+                       data[y][x][3] = (unsigned char) d;
                }
        }
        setuptex(tex_particle, &data[0][0][0], particletexturedata);
@@ -1835,7 +1835,7 @@ static void R_InitParticleTexture (void)
                {
                        dx = (x - 0.5f*16) / (16*0.5f-2);
                        d = (1 - sqrt(fabs(dx))) * noise3[y][x];
-                       data2[y][x][0] = data2[y][x][1] = data2[y][x][2] = (qbyte) bound(0, d, 255);
+                       data2[y][x][0] = data2[y][x][1] = data2[y][x][2] = (unsigned char) bound(0, d, 255);
                        data2[y][x][3] = 255;
                }
        }
@@ -1898,11 +1898,11 @@ void R_DrawParticle(particle_t *p)
 #else
 void R_DrawParticleCallback(const void *calldata1, int calldata2)
 {
-       const particle_t *p = calldata1;
+       const particle_t *p = (particle_t *)calldata1;
        rmeshstate_t m;
 #endif
        pblend_t blendmode;
-       float org[3], up2[3], v[3], right[3], up[3], fog, ifog, fogvec[3], cr, cg, cb, ca, size;
+       float org[3], up2[3], v[3], right[3], up[3], fog, ifog, cr, cg, cb, ca, size;
        particletexture_t *tex;
 
        VectorCopy(p->org, org);
@@ -1924,15 +1924,22 @@ void R_DrawParticleCallback(const void *calldata1, int calldata2)
                ca = 1;
        }
 #ifndef WORKINGLQUAKE
+       if (p->type->lighting)
+       {
+               float ambient[3], diffuse[3], diffusenormal[3];
+               R_CompleteLightPoint(ambient, diffuse, diffusenormal, org, true);
+               cr *= (ambient[0] + 0.5 * diffuse[0]);
+               cg *= (ambient[1] + 0.5 * diffuse[1]);
+               cb *= (ambient[2] + 0.5 * diffuse[2]);
+       }
        if (fogenabled)
        {
-               VectorSubtract(org, r_vieworigin, fogvec);
-               fog = exp(fogdensity/DotProduct(fogvec,fogvec));
+               fog = VERTEXFOGTABLE(VectorDistance(org, r_vieworigin));
                ifog = 1 - fog;
                cr = cr * ifog;
                cg = cg * ifog;
                cb = cb * ifog;
-               if (blendmode == PBLEND_ADD)
+               if (blendmode == PBLEND_ALPHA)
                {
                        cr += fogcolor[0] * fog;
                        cg += fogcolor[1] * fog;
@@ -2011,7 +2018,7 @@ void R_DrawParticleCallback(const void *calldata1, int calldata2)
        {
                R_CalcBeam_Vertex3f(particle_vertex3f, p->org, p->vel, size);
                VectorSubtract(p->vel, p->org, up);
-               VectorNormalizeFast(up);
+               VectorNormalize(up);
                v[0] = DotProduct(p->org, up) * (1.0f / 64.0f);
                v[1] = DotProduct(p->vel, up) * (1.0f / 64.0f);
                particle_texcoord2f[0] = 1;particle_texcoord2f[1] = v[0];
@@ -2020,7 +2027,10 @@ void R_DrawParticleCallback(const void *calldata1, int calldata2)
                particle_texcoord2f[6] = 1;particle_texcoord2f[7] = v[1];
        }
        else
-               Host_Error("R_DrawParticles: unknown particle orientation %i\n", p->type->orientation);
+       {
+               Con_Printf("R_DrawParticles: unknown particle orientation %i\n", p->type->orientation);
+               return;
+       }
 
 #if WORKINGLQUAKE
        if (blendmode == PBLEND_ALPHA)
@@ -2037,7 +2047,7 @@ void R_DrawParticleCallback(const void *calldata1, int calldata2)
        glTexCoord2f(particle_texcoord2f[6], particle_texcoord2f[7]);glVertex3f(particle_vertex3f[ 9], particle_vertex3f[10], particle_vertex3f[11]);
        glEnd();
 #else
-       R_Mesh_Draw(4, 2, polygonelements);
+       R_Mesh_Draw(0, 4, 2, polygonelements);
 #endif
 }
 
@@ -2075,7 +2085,7 @@ void R_DrawParticles (void)
        {
                if (p->type)
                {
-                       c_particles++;
+                       renderstats.particles++;
                        if (DotProduct(p->org, r_viewforward) >= minparticledist || p->type->orientation == PARTICLE_BEAM)
                        {
                                if (p->type == particletype + pt_decal)