]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_particles.c
now that performance of cl_decals_newsystem is not terrible, enable it
[xonotic/darkplaces.git] / cl_particles.c
index 2cc4e658b8253be2a070af995cac5b1f65ee2d01..1e9675ba290ce4c4f9858efc6c6c443eb38ac81b 100644 (file)
@@ -219,7 +219,7 @@ cvar_t cl_decals = {CVAR_SAVE, "cl_decals", "1", "enables decals (bullet holes,
 cvar_t cl_decals_visculling = {CVAR_SAVE, "cl_decals_visculling", "1", "perform a very cheap check if each decal is visible before drawing"};
 cvar_t cl_decals_time = {CVAR_SAVE, "cl_decals_time", "20", "how long before decals start to fade away"};
 cvar_t cl_decals_fadetime = {CVAR_SAVE, "cl_decals_fadetime", "1", "how long decals take to fade away"};
-cvar_t cl_decals_newsystem = {CVAR_SAVE, "cl_decals_newsystem", "0", "enables new advanced decal system"};
+cvar_t cl_decals_newsystem = {CVAR_SAVE, "cl_decals_newsystem", "1", "enables new advanced decal system"};
 cvar_t cl_decals_newsystem_intensitymultiplier = {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_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_models = {CVAR_SAVE, "cl_decals_models", "0", "enables decals on animated models (if newsystem is also 1)"};
@@ -842,7 +842,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o
                {
                        // bloodhack checks if this effect's color matches regular or lightning blood and if so spawns a blood effect instead
                        if (count == 1024)
-                               CL_ParticleExplosion(center);
+                               CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0);
                        else if (cl_particles_blood_bloodhack.integer && !cl_particles_quake.integer && (palettecolor == 73 || palettecolor == 225))
                                CL_ParticleEffect(EFFECT_TE_BLOOD, count / 2.0f, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0);
                        else
@@ -1827,6 +1827,8 @@ void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, in
 
 static cvar_t r_drawparticles = {0, "r_drawparticles", "1", "enables drawing of particles"};
 static cvar_t r_drawparticles_drawdistance = {CVAR_SAVE, "r_drawparticles_drawdistance", "2000", "particles further than drawdistance*size will not be drawn"};
+static cvar_t r_drawparticles_nearclip_min = {CVAR_SAVE, "r_drawparticles_nearclip_min", "4", "particles closer than drawnearclip_min will not be drawn"};
+static cvar_t r_drawparticles_nearclip_max = {CVAR_SAVE, "r_drawparticles_nearclip_max", "4", "particles closer than drawnearclip_min will be faded"};
 static cvar_t r_drawdecals = {0, "r_drawdecals", "1", "enables drawing of decals"};
 static cvar_t r_drawdecals_drawdistance = {CVAR_SAVE, "r_drawdecals_drawdistance", "500", "decals further than drawdistance*size will not be drawn"};
 
@@ -1941,7 +1943,7 @@ static void R_InitBloodTextures (unsigned char *particletexturedata)
 {
        int i, j, k, m;
        size_t datasize = PARTICLETEXTURESIZE*PARTICLETEXTURESIZE*4;
-       unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, datasize);
+       unsigned char *data = Mem_Alloc(tempmempool, datasize);
 
        // blood particles
        for (i = 0;i < 8;i++)
@@ -2157,7 +2159,7 @@ static void R_InitParticleTexture (void)
        }
 
 #ifndef DUMPPARTICLEFONT
-       particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR, true, r_texture_convertsRGB_particles.integer != 0);
+       particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR, true, r_texture_convertsRGB_particles.integer);
        if (!particletexture[tex_beam].texture)
 #endif
        {
@@ -2292,6 +2294,8 @@ void R_Particles_Init (void)
 
        Cvar_RegisterVariable(&r_drawparticles);
        Cvar_RegisterVariable(&r_drawparticles_drawdistance);
+       Cvar_RegisterVariable(&r_drawparticles_nearclip_min);
+       Cvar_RegisterVariable(&r_drawparticles_nearclip_max);
        Cvar_RegisterVariable(&r_drawdecals);
        Cvar_RegisterVariable(&r_drawdecals_drawdistance);
        R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap, NULL, NULL);
@@ -2305,11 +2309,15 @@ void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t
        particletexture_t *tex;
        float right[3], up[3], size, ca;
        float alphascale = (1.0f / 65536.0f) * cl_particles_alpha.value;
+       float particle_vertex3f[BATCHSIZE*12], particle_texcoord2f[BATCHSIZE*8], particle_color4f[BATCHSIZE*16];
 
        RSurf_ActiveWorldEntity();
 
        r_refdef.stats.drawndecals += numsurfaces;
        R_Mesh_ResetTextureState();
+       R_Mesh_VertexPointer(particle_vertex3f, 0, 0);
+       R_Mesh_TexCoordPointer(0, 2, particle_texcoord2f, 0, 0);
+       R_Mesh_ColorPointer(particle_color4f, 0, 0);
        GL_DepthMask(false);
        GL_DepthRange(0, 1);
        GL_PolygonOffset(0, 0);
@@ -2366,8 +2374,7 @@ void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t
        // (this assumes they all use one particle font texture!)
        GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
        R_SetupShader_Generic(particletexture[63].texture, NULL, GL_MODULATE, 1);
-       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);
+       R_Mesh_Draw(0, numsurfaces * 4, 0, numsurfaces * 2, NULL, particle_elements, 0, 0);
 }
 
 void R_DrawDecals (void)
@@ -2459,8 +2466,10 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
        particletexture_t *tex;
        float up2[3], v[3], right[3], up[3], fog, ifog, size, len, lenfactor, alpha;
        float ambient[3], diffuse[3], diffusenormal[3];
-       float spintime, spinrad, spincos, spinsin, spinm1, spinm2, spinm3, spinm4, baseright[3], baseup[3];
+       float palpha, spintime, spinrad, spincos, spinsin, spinm1, spinm2, spinm3, spinm4, baseright[3], baseup[3];
        vec4_t colormultiplier;
+       float minparticledist_start, minparticledist_end;
+       qboolean dofade;
 
        RSurf_ActiveWorldEntity();
 
@@ -2468,6 +2477,9 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
 
        r_refdef.stats.particles += numsurfaces;
        R_Mesh_ResetTextureState();
+       R_Mesh_VertexPointer(particle_vertex3f, 0, 0);
+       R_Mesh_TexCoordPointer(0, 2, particle_texcoord2f, 0, 0);
+       R_Mesh_ColorPointer(particle_color4f, 0, 0);
        GL_DepthMask(false);
        GL_DepthRange(0, 1);
        GL_PolygonOffset(0, 0);
@@ -2477,18 +2489,25 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
 
        spintime = r_refdef.scene.time;
 
+       minparticledist_start = DotProduct(r_refdef.view.origin, r_refdef.view.forward) + r_drawparticles_nearclip_min.value;
+       minparticledist_end = DotProduct(r_refdef.view.origin, r_refdef.view.forward) + r_drawparticles_nearclip_max.value;
+       dofade = (minparticledist_start < minparticledist_end);
+
        // first generate all the vertices at once
        for (surfacelistindex = 0, v3f = particle_vertex3f, t2f = particle_texcoord2f, c4f = particle_color4f;surfacelistindex < numsurfaces;surfacelistindex++, v3f += 3*4, t2f += 2*4, c4f += 4*4)
        {
                p = cl.particles + surfacelist[surfacelistindex];
 
                blendmode = (pblend_t)p->blendmode;
+               palpha = p->alpha;
+               if(dofade && p->orientation != PARTICLE_VBEAM && p->orientation != PARTICLE_HBEAM)
+                       palpha *= min(1, (DotProduct(p->org, r_refdef.view.forward)  - minparticledist_start) / (minparticledist_end - minparticledist_start));
 
                switch (blendmode)
                {
                case PBLEND_INVALID:
                case PBLEND_INVMOD:
-                       alpha = p->alpha * colormultiplier[3];
+                       alpha = palpha * colormultiplier[3];
                        // ensure alpha multiplier saturates properly
                        if (alpha > 1.0f)
                                alpha = 1.0f;
@@ -2503,7 +2522,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
                        c4f[3] = 1;
                        break;
                case PBLEND_ADD:
-                       alpha = p->alpha * colormultiplier[3];
+                       alpha = palpha * colormultiplier[3];
                        // ensure alpha multiplier saturates properly
                        if (alpha > 1.0f)
                                alpha = 1.0f;
@@ -2520,11 +2539,11 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
                        c4f[0] = p->color[0] * colormultiplier[0];
                        c4f[1] = p->color[1] * colormultiplier[1];
                        c4f[2] = p->color[2] * colormultiplier[2];
-                       c4f[3] = p->alpha * colormultiplier[3];
+                       c4f[3] = palpha * colormultiplier[3];
                        // note: lighting is not cheap!
                        if (particletype[p->typeindex].lighting)
                        {
-                               R_CompleteLightPoint(ambient, diffuse, diffusenormal, p->org, true);
+                               R_CompleteLightPoint(ambient, diffuse, diffusenormal, p->org, true, false);
                                c4f[0] *= (ambient[0] + 0.5 * diffuse[0]);
                                c4f[1] *= (ambient[1] + 0.5 * diffuse[1]);
                                c4f[2] *= (ambient[2] + 0.5 * diffuse[2]);
@@ -2666,7 +2685,6 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
        texture = NULL;
        batchstart = 0;
        batchcount = 0;
-       R_Mesh_PrepareVertices_Generic_Arrays(numsurfaces * 4, particle_vertex3f, particle_color4f, particle_texcoord2f);
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
        {
                p = cl.particles + surfacelist[surfacelistindex];
@@ -2704,7 +2722,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
                }
 
                batchcount = surfacelistindex - batchstart;
-               R_Mesh_Draw(batchstart * 4, batchcount * 4, batchstart * 2, batchcount * 2, NULL, NULL, 0, particle_elements, NULL, 0);
+               R_Mesh_Draw(batchstart * 4, batchcount * 4, batchstart * 2, batchcount * 2, NULL, particle_elements, 0, 0);
        }
 }
 
@@ -2712,7 +2730,7 @@ void R_DrawParticles (void)
 {
        int i, a;
        int drawparticles = r_drawparticles.integer;
-       float minparticledist;
+       float minparticledist_start;
        particle_t *p;
        float gravity, frametime, f, dist, oldorg[3];
        float drawdist2;
@@ -2727,7 +2745,7 @@ void R_DrawParticles (void)
        if (!cl.num_particles)
                return;
 
-       minparticledist = DotProduct(r_refdef.view.origin, r_refdef.view.forward) + 4.0f;
+       minparticledist_start = DotProduct(r_refdef.view.origin, r_refdef.view.forward) + r_drawparticles_nearclip_min.value;
        gravity = frametime * cl.movevars_gravity;
        update = frametime > 0;
        drawdist2 = r_drawparticles_drawdistance.value * r_refdef.view.quality;
@@ -2777,7 +2795,7 @@ void R_DrawParticles (void)
                                VectorCopy(p->org, oldorg);
                                VectorMA(p->org, frametime, p->vel, p->org);
 //                             if (p->bounce && cl.time >= p->delayedcollisions)
-                               if (p->bounce && cl_particles_collisions.integer)
+                               if (p->bounce && cl_particles_collisions.integer && VectorLength(p->vel))
                                {
                                        trace = CL_TraceLine(oldorg, p->org, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, &hitent, false);
                                        // if the trace started in or hit something of SUPERCONTENTS_NODROP
@@ -2834,11 +2852,16 @@ void R_DrawParticles (void)
                                                        // anything else - bounce off solid
                                                        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);
                                                }
                                        }
                                }
+
+                               if (VectorLength2(p->vel) < 0.03)
+                               {
+                                       if(p->orientation == PARTICLE_SPARK) // sparks are virtually invisible if very slow, so rather let them go off
+                                               goto killparticle;
+                                       VectorClear(p->vel);
+                               }
                        }
 
                        if (p->typeindex != pt_static)
@@ -2908,7 +2931,7 @@ void R_DrawParticles (void)
                                                                continue;
                                        }
                        // anything else just has to be in front of the viewer and visible at this distance
-                       if (DotProduct(p->org, r_refdef.view.forward) >= minparticledist && VectorDistance2(p->org, r_refdef.view.origin) < drawdist2 * (p->size * p->size))
+                       if (DotProduct(p->org, r_refdef.view.forward) >= minparticledist_start && VectorDistance2(p->org, r_refdef.view.origin) < drawdist2 * (p->size * p->size))
                                R_MeshQueue_AddTransparent(p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
                        break;
                }