]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_particles.c
cmd: Re-re-re-re-implement the command parser. Allocate text only as needed.
[xonotic/darkplaces.git] / cl_particles.c
index 508fd15cea56687ebe76cbac04d4f4d227fb1f92..b08172e863232731999a3a698d7f94557711c573 100644 (file)
@@ -44,6 +44,7 @@ particletype_t particletype[pt_total] =
 
 #define PARTICLEEFFECT_UNDERWATER 1
 #define PARTICLEEFFECT_NOTUNDERWATER 2
+#define PARTICLEEFFECT_FORCENEAREST 4
 #define PARTICLEEFFECT_DEFINED 2147483648U
 
 typedef struct particleeffectinfo_s
@@ -113,7 +114,7 @@ typedef struct particleeffectinfo_s
        float lightradiusfade;
        float lighttime;
        float lightcolor[3];
-       qboolean lightshadow;
+       qbool lightshadow;
        int lightcubemapnum;
        float lightcorona[2];
        unsigned int staincolor[2]; // note: 0x808080 = neutral (particle's own color), these are modding factors for the particle's original color!
@@ -263,7 +264,7 @@ particleeffectinfo_t baselineparticleeffectinfo =
        0.0f, //float lightradiusfade;
        16777216.0f, //float lighttime;
        {1.0f, 1.0f, 1.0f}, //float lightcolor[3];
-       true, //qboolean lightshadow;
+       true, //qbool lightshadow;
        0, //int lightcubemapnum;
        {1.0f, 0.25f}, //float lightcorona[2];
        {(unsigned int)-1, (unsigned int)-1}, //unsigned int staincolor[2]; // note: 0x808080 = neutral (particle's own color), these are modding factors for the particle's original color!
@@ -299,14 +300,12 @@ cvar_t cl_particles_visculling = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_viscull
 cvar_t cl_particles_collisions = {CVAR_CLIENT | CVAR_SAVE, "cl_particles_collisions", "1", "allow costly collision detection on particles (sparks that bounce, particles not going through walls, blood hitting surfaces, etc)"};
 cvar_t cl_particles_forcetraileffects = {CVAR_CLIENT, "cl_particles_forcetraileffects", "0", "force trails to be displayed even if a non-trail draw primitive was used (debug/compat feature)"};
 cvar_t cl_decals = {CVAR_CLIENT | CVAR_SAVE, "cl_decals", "1", "enables decals (bullet holes, blood, etc)"};
-cvar_t cl_decals_visculling = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_visculling", "1", "perform a very cheap check if each decal is visible before drawing"};
 cvar_t cl_decals_time = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_time", "20", "how long before decals start to fade away"};
 cvar_t cl_decals_fadetime = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_fadetime", "1", "how long decals take to fade away"};
-cvar_t cl_decals_newsystem = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_newsystem", "1", "enables new advanced decal system"};
 cvar_t cl_decals_newsystem_intensitymultiplier = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_newsystem_intensitymultiplier", "2", "boosts intensity of decals (because the distance fade can make them hard to see otherwise)"};
 cvar_t cl_decals_newsystem_immediatebloodstain = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_newsystem_immediatebloodstain", "2", "0: no on-spawn blood stains; 1: on-spawn blood stains for pt_blood; 2: always use on-spawn blood stains"};
 cvar_t cl_decals_newsystem_bloodsmears = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_newsystem_bloodsmears", "1", "enable use of particle velocity as decal projection direction rather than surface normal"};
-cvar_t cl_decals_models = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_models", "0", "enables decals on animated models (if newsystem is also 1)"};
+cvar_t cl_decals_models = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_models", "0", "enables decals on animated models"};
 cvar_t cl_decals_bias = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_bias", "0.125", "distance to bias decals from surface to prevent depth fighting"};
 cvar_t cl_decals_max = {CVAR_CLIENT | CVAR_SAVE, "cl_decals_max", "4096", "maximum number of decals allowed to exist in the world at once"};
 
@@ -467,6 +466,7 @@ static void CL_Particles_ParseEffectInfo(const char *textstart, const char *text
                else if (!strcmp(argv[0], "staintex")) {readints(info->staintex, 2);}
                else if (!strcmp(argv[0], "stainless")) {info->staintex[0] = -2; info->staincolor[0] = (unsigned int)-1; info->staincolor[1] = (unsigned int)-1; info->stainalpha[0] = 1; info->stainalpha[1] = 1; info->stainsize[0] = 2; info->stainsize[1] = 2; }
                else if (!strcmp(argv[0], "rotate")) {readfloats(info->rotate, 4);}
+               else if (!strcmp(argv[0], "forcenearest")) {checkparms(1);info->flags |= PARTICLEEFFECT_FORCENEAREST;}
                else
                        Con_Printf("%s:%i: skipping unknown command %s\n", filename, linenumber, argv[0]);
 #undef checkparms
@@ -584,8 +584,8 @@ CL_InitParticles
 void CL_ReadPointFile_f(cmd_state_t *cmd);
 void CL_Particles_Init (void)
 {
-       Cmd_AddCommand(&cmd_client, "pointfile", CL_ReadPointFile_f, "display point file produced by qbsp when a leak was detected in the map (a line leading through the leak hole, to an entity inside the level)");
-       Cmd_AddCommand(&cmd_client, "cl_particles_reloadeffects", CL_Particles_LoadEffectInfo_f, "reloads effectinfo.txt and maps/levelname_effectinfo.txt (where levelname is the current map) if parameter is given, loads from custom file (no levelname_effectinfo are loaded in this case)");
+       Cmd_AddCommand(CMD_CLIENT, "pointfile", CL_ReadPointFile_f, "display point file produced by qbsp when a leak was detected in the map (a line leading through the leak hole, to an entity inside the level)");
+       Cmd_AddCommand(CMD_CLIENT, "cl_particles_reloadeffects", CL_Particles_LoadEffectInfo_f, "reloads effectinfo.txt and maps/levelname_effectinfo.txt (where levelname is the current map) if parameter is given, loads from custom file (no levelname_effectinfo are loaded in this case)");
 
        Cvar_RegisterVariable (&cl_particles);
        Cvar_RegisterVariable (&cl_particles_quality);
@@ -612,10 +612,8 @@ void CL_Particles_Init (void)
        Cvar_RegisterVariable (&cl_particles_collisions);
        Cvar_RegisterVariable (&cl_particles_forcetraileffects);
        Cvar_RegisterVariable (&cl_decals);
-       Cvar_RegisterVariable (&cl_decals_visculling);
        Cvar_RegisterVariable (&cl_decals_time);
        Cvar_RegisterVariable (&cl_decals_fadetime);
-       Cvar_RegisterVariable (&cl_decals_newsystem);
        Cvar_RegisterVariable (&cl_decals_newsystem_intensitymultiplier);
        Cvar_RegisterVariable (&cl_decals_newsystem_immediatebloodstain);
        Cvar_RegisterVariable (&cl_decals_newsystem_bloodsmears);
@@ -652,7 +650,7 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size,
 // stainsize: size of the stain as factor for palpha
 // angle: base rotation of the particle geometry around its center normal
 // spin: rotation speed of the particle geometry around its center normal
-particle_t *CL_NewParticle(const vec3_t sortorigin, unsigned short ptypeindex, int pcolor1, int pcolor2, int ptex, float psize, float psizeincrease, float palpha, float palphafade, float pgravity, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz, float pairfriction, float pliquidfriction, float originjitter, float velocityjitter, qboolean pqualityreduction, float lifetime, float stretch, pblend_t blendmode, porientation_t orientation, int staincolor1, int staincolor2, int staintex, float stainalpha, float stainsize, float angle, float spin, float tint[4])
+particle_t *CL_NewParticle(const vec3_t sortorigin, unsigned short ptypeindex, int pcolor1, int pcolor2, int ptex, float psize, float psizeincrease, float palpha, float palphafade, float pgravity, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz, float pairfriction, float pliquidfriction, float originjitter, float velocityjitter, qbool pqualityreduction, float lifetime, float stretch, pblend_t blendmode, porientation_t orientation, int staincolor1, int staincolor2, int staintex, float stainalpha, float stainsize, float angle, float spin, float tint[4])
 {
        int l1, l2, r, g, b;
        particle_t *part;
@@ -810,7 +808,7 @@ static void CL_ImmediateBloodStain(particle_t *part)
        int staintex;
 
        // blood creates a splash at spawn, not just at impact, this makes monsters bloody where they are shot
-       if (part->staintexnum >= 0 && cl_decals_newsystem.integer && cl_decals.integer)
+       if (part->staintexnum >= 0 && cl_decals.integer)
        {
                VectorCopy(part->vel, v);
                VectorNormalize(v);
@@ -819,7 +817,7 @@ static void CL_ImmediateBloodStain(particle_t *part)
        }
 
        // blood creates a splash at spawn, not just at impact, this makes monsters bloody where they are shot
-       if (part->typeindex == pt_blood && cl_decals_newsystem.integer && cl_decals.integer)
+       if (part->typeindex == pt_blood && cl_decals.integer)
        {
                VectorCopy(part->vel, v);
                VectorNormalize(v);
@@ -831,7 +829,6 @@ static void CL_ImmediateBloodStain(particle_t *part)
 void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t normal, int color1, int color2, int texnum, float size, float alpha)
 {
        int l1, l2;
-       decal_t *decal;
        entity_render_t *ent = &cl.entities[hitent].render;
        unsigned char color[3];
        if (!cl_decals.integer)
@@ -845,57 +842,10 @@ void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t
        color[1] = ((((color1 >>  8) & 0xFF) * l1 + ((color2 >>  8) & 0xFF) * l2) >> 8) & 0xFF;
        color[2] = ((((color1 >>  0) & 0xFF) * l1 + ((color2 >>  0) & 0xFF) * l2) >> 8) & 0xFF;
 
-       if (cl_decals_newsystem.integer)
-       {
-               if (vid.sRGB3D)
-                       R_DecalSystem_SplatEntities(org, normal, Image_LinearFloatFromsRGB(color[0]), Image_LinearFloatFromsRGB(color[1]), Image_LinearFloatFromsRGB(color[2]), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size);
-               else
-                       R_DecalSystem_SplatEntities(org, normal, color[0]*(1.0f/255.0f), color[1]*(1.0f/255.0f), color[2]*(1.0f/255.0f), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size);
-               return;
-       }
-
-       for (;cl.free_decal < cl.max_decals && cl.decals[cl.free_decal].typeindex;cl.free_decal++);
-       if (cl.free_decal >= cl.max_decals)
-               return;
-       decal = &cl.decals[cl.free_decal++];
-       if (cl.num_decals < cl.free_decal)
-               cl.num_decals = cl.free_decal;
-       memset(decal, 0, sizeof(*decal));
-       decal->decalsequence = cl.decalsequence++;
-       decal->typeindex = pt_decal;
-       decal->texnum = texnum;
-       VectorMA(org, cl_decals_bias.value, normal, decal->org);
-       VectorCopy(normal, decal->normal);
-       decal->size = size;
-       decal->alpha = alpha;
-       decal->time2 = cl.time;
-       decal->color[0] = color[0];
-       decal->color[1] = color[1];
-       decal->color[2] = color[2];
        if (vid.sRGB3D)
-       {
-               decal->color[0] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[0]) * 256.0f);
-               decal->color[1] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[1]) * 256.0f);
-               decal->color[2] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[2]) * 256.0f);
-       }
-       decal->owner = hitent;
-       decal->clusterindex = -1000; // no vis culling unless we're sure
-       if (hitent)
-       {
-               // these relative things are only used to regenerate p->org and p->vel if decal->owner is not world (0)
-               decal->ownermodel = cl.entities[decal->owner].render.model;
-               Matrix4x4_Transform(&cl.entities[decal->owner].render.inversematrix, org, decal->relativeorigin);
-               Matrix4x4_Transform3x3(&cl.entities[decal->owner].render.inversematrix, normal, decal->relativenormal);
-       }
+               R_DecalSystem_SplatEntities(org, normal, Image_LinearFloatFromsRGB(color[0]), Image_LinearFloatFromsRGB(color[1]), Image_LinearFloatFromsRGB(color[2]), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size);
        else
-       {
-               if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.PointInLeaf)
-               {
-                       mleaf_t *leaf = r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, decal->org);
-                       if(leaf)
-                               decal->clusterindex = leaf->clusterindex;
-               }
-       }
+               R_DecalSystem_SplatEntities(org, normal, color[0]*(1.0f/255.0f), color[1]*(1.0f/255.0f), color[2]*(1.0f/255.0f), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size);
 }
 
 void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, float alpha, int texnum, int color1, int color2)
@@ -927,10 +877,21 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size,
                CL_SpawnDecalParticleForSurface(besthitent, bestorg, bestnormal, color1, color2, texnum, size, alpha);
 }
 
+// generates a cubemap name with prefix flags based on info flags (for now only `!`)
+static char *LightCubemapNumToName(char *vabuf, size_t vasize, int lightcubemapnum, int flags)
+{
+       if (lightcubemapnum <= 0)
+               return NULL;
+       // `!` is prepended if the cubemap must be nearest-filtered
+       if (flags & PARTICLEEFFECT_FORCENEAREST)
+               return va(vabuf, vasize, "!cubemaps/%i", lightcubemapnum);
+       return va(vabuf, vasize, "cubemaps/%i", lightcubemapnum);
+}
+
 static void CL_Sparks(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float sparkcount);
 static void CL_Smoke(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float smokecount);
-static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, float tintmins[4], float tintmaxs[4], float fade, qboolean wanttrail);
-static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, qboolean wanttrail)
+static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qbool spawndlight, qbool spawnparticles, float tintmins[4], float tintmaxs[4], float fade, qbool wanttrail);
+static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qbool spawndlight, qbool spawnparticles, qbool wanttrail)
 {
        vec3_t center;
        matrix4x4_t lightmatrix;
@@ -1001,7 +962,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
                // bullet hole
                R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64);
                CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
-               CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, NULL, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (effectnameindex == EFFECT_TE_SUPERSPIKE)
        {
@@ -1042,7 +1003,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
                // bullet hole
                R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64);
                CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
-               CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, NULL, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (effectnameindex == EFFECT_TE_BLOOD)
        {
@@ -1053,7 +1014,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
                else
                {
                        static double bloodaccumulator = 0;
-                       qboolean immediatebloodstain = (cl_decals_newsystem_immediatebloodstain.integer >= 1);
+                       qbool immediatebloodstain = (cl_decals_newsystem_immediatebloodstain.integer >= 1);
                        //CL_NewParticle(center, pt_alphastatic, 0x4f0000,0x7f0000, tex_particle, 2.5, 0, 256, 256, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), 0, 0, 0, 1, 4, 0, 0, true, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, NULL);
                        bloodaccumulator += count * 0.333 * cl_particles_quality.value;
                        for (;bloodaccumulator > 0;bloodaccumulator--)
@@ -1074,7 +1035,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
                // plasma scorch mark
                R_Stain(center, 40, 40, 40, 40, 64, 88, 88, 88, 64);
                CL_SpawnDecalParticleForPoint(center, 6, 6, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
-               CL_AllocLightFlash(NULL, &lightmatrix, 200, 1, 1, 1, 1000, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 200, 1, 1, 1, 1000, 0.2, NULL, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (effectnameindex == EFFECT_TE_GUNSHOT)
        {
@@ -1109,17 +1070,17 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
                // bullet hole
                R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64);
                CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
-               CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, NULL, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (effectnameindex == EFFECT_TE_EXPLOSION)
        {
                CL_ParticleExplosion(center);
-               CL_AllocLightFlash(NULL, &lightmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (effectnameindex == EFFECT_TE_EXPLOSIONQUAD)
        {
                CL_ParticleExplosion(center);
-               CL_AllocLightFlash(NULL, &lightmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (effectnameindex == EFFECT_TE_TAREXPLOSION)
        {
@@ -1136,10 +1097,10 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
                }
                else
                        CL_ParticleExplosion(center);
-               CL_AllocLightFlash(NULL, &lightmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (effectnameindex == EFFECT_TE_SMALLFLASH)
-               CL_AllocLightFlash(NULL, &lightmatrix, 200, 2, 2, 2, 1000, 0.2, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 200, 2, 2, 2, 1000, 0.2, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        else if (effectnameindex == EFFECT_TE_FLAMEJET)
        {
                count *= cl_particles_quality.value;
@@ -1194,7 +1155,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
                }
                if (!cl_particles_quake.integer)
                        CL_NewParticle(center, pt_static, 0xffffff, 0xffffff, tex_particle, 30, 0, 256, 512, 0, 0, center[0], center[1], center[2], 0, 0, 0, 0, 0, 0, 0, false, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
-               CL_AllocLightFlash(NULL, &lightmatrix, 200, 2.0f, 2.0f, 2.0f, 400, 99.0f, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 200, 2.0f, 2.0f, 2.0f, 400, 99.0f, NULL, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (effectnameindex == EFFECT_TE_TEI_G3)
                CL_NewParticle(center, pt_beam, 0xFFFFFF, 0xFFFFFF, tex_beam, 8, 0, 256, 256, 0, 0, originmins[0], originmins[1], originmins[2], originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, 0, false, 0, 1, PBLEND_ADD, PARTICLE_HBEAM, -1, -1, -1, 1, 1, 0, 0, NULL);
@@ -1210,7 +1171,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
        else if (effectnameindex == EFFECT_TE_TEI_BIGEXPLOSION)
        {
                CL_ParticleExplosion(center);
-               CL_AllocLightFlash(NULL, &lightmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, -1, true, 1, 0.25, 0.5, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, NULL, -1, true, 1, 0.25, 0.5, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (effectnameindex == EFFECT_TE_TEI_PLASMAHIT)
        {
@@ -1223,7 +1184,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
                if (cl_particles_sparks.integer)
                        for (f = 0;f < count;f += 1.0f / cl_particles_quality.value)
                                CL_NewParticle(center, pt_spark, 0x2030FF, 0x80C0FF, tex_particle, 2.0f, 0, lhrandom(64, 255), 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 0, 465, true, 0, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL);
-               CL_AllocLightFlash(NULL, &lightmatrix, 500, 0.6f, 1.2f, 2.0f, 2000, 9999, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 500, 0.6f, 1.2f, 2.0f, 2000, 9999, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (effectnameindex == EFFECT_EF_FLAME)
        {
@@ -1232,7 +1193,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
                count *= 300 * cl_particles_quality.value;
                while (count-- > 0)
                        CL_NewParticle(center, pt_smoke, 0x6f0f00, 0xe3974f, tex_particle, 4, 0, lhrandom(64, 128), 384, -1, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 16, 128, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
-               CL_AllocLightFlash(NULL, &lightmatrix, 200, 2.0f, 1.5f, 0.5f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 200, 2.0f, 1.5f, 0.5f, 0, 0, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (effectnameindex == EFFECT_EF_STARDUST)
        {
@@ -1241,7 +1202,7 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
                count *= 200 * cl_particles_quality.value;
                while (count-- > 0)
                        CL_NewParticle(center, pt_static, 0x903010, 0xFFD030, tex_particle, 4, 0, lhrandom(64, 128), 128, 1, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0.2, 0.8, 16, 128, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL);
-               CL_AllocLightFlash(NULL, &lightmatrix, 200, 1.0f, 0.7f, 0.3f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+               CL_AllocLightFlash(NULL, &lightmatrix, 200, 1.0f, 0.7f, 0.3f, 0, 0, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        }
        else if (!strncmp(particleeffectname[effectnameindex], "TR_", 3))
        {
@@ -1458,9 +1419,9 @@ static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const v
 
 // this is also called on point effects with spawndlight = true and
 // spawnparticles = true
-static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, float tintmins[4], float tintmaxs[4], float fade, qboolean wanttrail)
+static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qbool spawndlight, qbool spawnparticles, float tintmins[4], float tintmaxs[4], float fade, qbool wanttrail)
 {
-       qboolean found = false;
+       qbool found = false;
        char vabuf[1024];
        if (effectnameindex < 1 || effectnameindex >= MAX_PARTICLEEFFECTNAME || !particleeffectname[effectnameindex][0])
        {
@@ -1484,8 +1445,8 @@ static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, con
                vec3_t up;
                vec_t traillen;
                vec_t trailstep;
-               qboolean underwater;
-               qboolean immediatebloodstain;
+               qbool underwater;
+               qbool immediatebloodstain;
                particle_t *part;
                float avgtint[4], tint[4], tintlerp;
                // note this runs multiple effects with the same name, each one spawns only one kind of particle, so some effects need more than one
@@ -1507,9 +1468,9 @@ static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, con
                {
                        if ((info->effectnameindex == effectnameindex) && (info->flags & PARTICLEEFFECT_DEFINED))
                        {
-                               qboolean definedastrail = info->trailspacing > 0;
+                               qbool definedastrail = info->trailspacing > 0;
 
-                               qboolean drawastrail = wanttrail;
+                               qbool drawastrail = wanttrail;
                                if (cl_particles_forcetraileffects.integer)
                                        drawastrail = drawastrail || definedastrail;
 
@@ -1531,7 +1492,7 @@ static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, con
                                        {
                                                // light flash (explosion, etc)
                                                // called when effect starts
-                                               CL_AllocLightFlash(NULL, &tempmatrix, info->lightradiusstart, info->lightcolor[0]*avgtint[0]*avgtint[3], info->lightcolor[1]*avgtint[1]*avgtint[3], info->lightcolor[2]*avgtint[2]*avgtint[3], info->lightradiusfade, info->lighttime, info->lightcubemapnum, -1, info->lightshadow, info->lightcorona[0], info->lightcorona[1], 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+                                               CL_AllocLightFlash(NULL, &tempmatrix, info->lightradiusstart, info->lightcolor[0]*avgtint[0]*avgtint[3], info->lightcolor[1]*avgtint[1]*avgtint[3], info->lightcolor[2]*avgtint[2]*avgtint[3], info->lightradiusfade, info->lighttime, LightCubemapNumToName(vabuf, sizeof(vabuf), info->lightcubemapnum, info->flags), -1, info->lightshadow, info->lightcorona[0], info->lightcorona[1], 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
                                        }
                                        else if (r_refdef.scene.numlights < MAX_DLIGHTS)
                                        {
@@ -1541,7 +1502,7 @@ static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, con
                                                rvec[0] = info->lightcolor[0]*avgtint[0]*avgtint[3];
                                                rvec[1] = info->lightcolor[1]*avgtint[1]*avgtint[3];
                                                rvec[2] = info->lightcolor[2]*avgtint[2]*avgtint[3];
-                                               R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, rvec, -1, info->lightcubemapnum > 0 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", info->lightcubemapnum) : NULL, info->lightshadow, info->lightcorona[0], info->lightcorona[1], 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+                                               R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, rvec, -1, LightCubemapNumToName(vabuf, sizeof(vabuf), info->lightcubemapnum, info->flags), info->lightshadow, info->lightcorona[0], info->lightcorona[1], 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
                                                r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++;
                                        }
                                }
@@ -1679,12 +1640,12 @@ static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, con
                CL_ParticleEffect_Fallback(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles, wanttrail);
 }
 
-void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, float tintmins[4], float tintmaxs[4], float fade)
+void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qbool spawndlight, qbool spawnparticles, float tintmins[4], float tintmaxs[4], float fade)
 {
        CL_NewParticlesFromEffectinfo(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles, tintmins, tintmaxs, fade, true);
 }
 
-void CL_ParticleBox(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, float tintmins[4], float tintmaxs[4], float fade)
+void CL_ParticleBox(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qbool spawndlight, qbool spawnparticles, float tintmins[4], float tintmaxs[4], float fade)
 {
        CL_NewParticlesFromEffectinfo(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles, tintmins, tintmaxs, fade, false);
 }
@@ -1878,7 +1839,7 @@ void CL_ParticleExplosion (const vec3_t org)
                                                VectorMA(org, 128, v2, v);
                                                trace = CL_TraceLine(org, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value, true, false, NULL, false, false);
                                        }
-                                       while (k < 16 && trace.fraction < 0.1f);
+                                       while (k++ < 16 && trace.fraction < 0.1f);
                                        VectorSubtract(trace.endpos, org, v2);
                                        VectorScale(v2, 2.0f, v2);
                                        CL_NewParticle(org, pt_spark, 0x903010, 0xFFD030, tex_particle, 1.0f, 0, lhrandom(0, 255), 512, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL);
@@ -2486,157 +2447,6 @@ void R_Particles_Init (void)
        R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap, NULL, NULL);
 }
 
-static void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
-{
-       int surfacelistindex;
-       const decal_t *d;
-       float *v3f, *t2f, *c4f;
-       particletexture_t *tex;
-       vec_t right[3], up[3], size, ca;
-       float alphascale = (1.0f / 65536.0f) * cl_particles_alpha.value;
-
-       RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
-
-       r_refdef.stats[r_stat_drawndecals] += numsurfaces;
-//     R_Mesh_ResetTextureState();
-       GL_DepthMask(false);
-       GL_DepthRange(0, 1);
-       GL_PolygonOffset(0, 0);
-       GL_DepthTest(true);
-       GL_CullFace(GL_NONE);
-
-       // generate all the vertices at once
-       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
-       {
-               d = cl.decals + surfacelist[surfacelistindex];
-
-               // calculate color
-               c4f = particle_color4f + 16*surfacelistindex;
-               ca = d->alpha * alphascale;
-               // ensure alpha multiplier saturates properly
-               if (ca > 1.0f / 256.0f)
-                       ca = 1.0f / 256.0f;     
-               if (r_refdef.fogenabled)
-                       ca *= RSurf_FogVertex(d->org);
-               Vector4Set(c4f, d->color[0] * ca, d->color[1] * ca, d->color[2] * ca, 1);
-               Vector4Copy(c4f, c4f + 4);
-               Vector4Copy(c4f, c4f + 8);
-               Vector4Copy(c4f, c4f + 12);
-
-               // calculate vertex positions
-               size = d->size * cl_particles_size.value;
-               VectorVectors(d->normal, right, up);
-               VectorScale(right, size, right);
-               VectorScale(up, size, up);
-               v3f = particle_vertex3f + 12*surfacelistindex;
-               v3f[ 0] = d->org[0] - right[0] - up[0];
-               v3f[ 1] = d->org[1] - right[1] - up[1];
-               v3f[ 2] = d->org[2] - right[2] - up[2];
-               v3f[ 3] = d->org[0] - right[0] + up[0];
-               v3f[ 4] = d->org[1] - right[1] + up[1];
-               v3f[ 5] = d->org[2] - right[2] + up[2];
-               v3f[ 6] = d->org[0] + right[0] + up[0];
-               v3f[ 7] = d->org[1] + right[1] + up[1];
-               v3f[ 8] = d->org[2] + right[2] + up[2];
-               v3f[ 9] = d->org[0] + right[0] - up[0];
-               v3f[10] = d->org[1] + right[1] - up[1];
-               v3f[11] = d->org[2] + right[2] - up[2];
-
-               // calculate texcoords
-               tex = &particletexture[d->texnum];
-               t2f = particle_texcoord2f + 8*surfacelistindex;
-               t2f[0] = tex->s1;t2f[1] = tex->t2;
-               t2f[2] = tex->s1;t2f[3] = tex->t1;
-               t2f[4] = tex->s2;t2f[5] = tex->t1;
-               t2f[6] = tex->s2;t2f[7] = tex->t2;
-       }
-
-       // now render the decals all at once
-       // (this assumes they all use one particle font texture!)
-       GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
-       R_SetupShader_Generic(particletexture[63].texture, false, false, true);
-       R_Mesh_PrepareVertices_Generic_Arrays(numsurfaces * 4, particle_vertex3f, particle_color4f, particle_texcoord2f);
-       R_Mesh_Draw(0, numsurfaces * 4, 0, numsurfaces * 2, NULL, NULL, 0, particle_elements, NULL, 0);
-}
-
-void R_DrawDecals (void)
-{
-       int i;
-       int drawdecals = r_drawdecals.integer;
-       decal_t *decal;
-       float frametime;
-       float decalfade;
-       float drawdist2;
-       unsigned int killsequence = cl.decalsequence - bound(0, (unsigned int) cl_decals_max.integer, cl.decalsequence);
-
-       frametime = bound(0, cl.time - cl.decals_updatetime, 1);
-       cl.decals_updatetime = bound(cl.time - 1, cl.decals_updatetime + frametime, cl.time + 1);
-
-       // LadyHavoc: early out conditions
-       if (!cl.num_decals)
-               return;
-
-       decalfade = frametime * 256 / cl_decals_fadetime.value;
-       drawdist2 = r_drawdecals_drawdistance.value * r_refdef.view.quality;
-       drawdist2 = drawdist2*drawdist2;
-
-       for (i = 0, decal = cl.decals;i < cl.num_decals;i++, decal++)
-       {
-               if (!decal->typeindex)
-                       continue;
-
-               if (killsequence > decal->decalsequence)
-                       goto killdecal;
-
-               if (cl.time > decal->time2 + cl_decals_time.value)
-               {
-                       decal->alpha -= decalfade;
-                       if (decal->alpha <= 0)
-                               goto killdecal;
-               }
-
-               if (decal->owner)
-               {
-                       if (cl.entities[decal->owner].render.model == decal->ownermodel)
-                       {
-                               Matrix4x4_Transform(&cl.entities[decal->owner].render.matrix, decal->relativeorigin, decal->org);
-                               Matrix4x4_Transform3x3(&cl.entities[decal->owner].render.matrix, decal->relativenormal, decal->normal);
-                       }
-                       else
-                               goto killdecal;
-               }
-
-               if(cl_decals_visculling.integer && decal->clusterindex > -1000 && !CHECKPVSBIT(r_refdef.viewcache.world_pvsbits, decal->clusterindex))
-                       continue;
-
-               if (!drawdecals)
-                       continue;
-
-               if (!r_refdef.view.useperspective || (DotProduct(r_refdef.view.origin, decal->normal) > DotProduct(decal->org, decal->normal) && VectorDistance2(decal->org, r_refdef.view.origin) < drawdist2 * (decal->size * decal->size)))
-                       R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, decal->org, R_DrawDecal_TransparentCallback, NULL, i, NULL);
-               continue;
-killdecal:
-               decal->typeindex = 0;
-               if (cl.free_decal > i)
-                       cl.free_decal = i;
-       }
-
-       // reduce cl.num_decals if possible
-       while (cl.num_decals > 0 && cl.decals[cl.num_decals - 1].typeindex == 0)
-               cl.num_decals--;
-
-       if (cl.num_decals == cl.max_decals && cl.max_decals < MAX_DECALS)
-       {
-               decal_t *olddecals = cl.decals;
-               cl.max_decals = min(cl.max_decals * 2, MAX_DECALS);
-               cl.decals = (decal_t *) Mem_Alloc(cls.levelmempool, cl.max_decals * sizeof(decal_t));
-               memcpy(cl.decals, olddecals, cl.num_decals * sizeof(decal_t));
-               Mem_Free(olddecals);
-       }
-
-       r_refdef.stats[r_stat_totaldecals] = cl.num_decals;
-}
-
 static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
        vec3_t vecorg, vecvel, baseright, baseup;
@@ -2652,7 +2462,7 @@ static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const
        float palpha, spintime, spinrad, spincos, spinsin, spinm1, spinm2, spinm3, spinm4;
        vec4_t colormultiplier;
        float minparticledist_start, minparticledist_end;
-       qboolean dofade;
+       qbool dofade;
 
        RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
 
@@ -2930,7 +2740,7 @@ void R_DrawParticles (void)
        float drawdist2;
        int hitent;
        trace_t trace;
-       qboolean update;
+       qbool update;
 
        frametime = bound(0, cl.time - cl.particles_updatetime, 1);
        cl.particles_updatetime = bound(cl.time - 1, cl.particles_updatetime + frametime, cl.time + 1);