]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
Fix severe bugs in mul128 implementation which was breaking the Lehmer RNG.
[xonotic/darkplaces.git] / r_shadow.c
index d300d50fcf32ff4118acbce1f01ea3f469c02904..0d05ac1e4544a73ed4b4fcdfb8caebca3b638f0c 100644 (file)
@@ -359,6 +359,7 @@ cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bounc
 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
 cvar_t r_shadow_bouncegrid_sortlightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_sortlightpaths", "1", "sort light paths before accumulating them into the bouncegrid texture, this reduces cpu cache misses"};
 cvar_t r_shadow_bouncegrid_lightpathsize = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize", "1", "width of the light path for accumulation of light in the bouncegrid texture"};
+cvar_t r_shadow_bouncegrid_normalizevectors = { CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)" };
 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
 cvar_t r_shadow_bouncegrid_static_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_static_bounceminimumintensity", "0.01", "stop bouncing once intensity drops below this fraction of the original particle color" };
 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
@@ -823,6 +824,7 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
@@ -2575,8 +2577,9 @@ static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t
        settings->spacing[0]                    = spacing;
        settings->spacing[1]                    = spacing;
        settings->spacing[2]                    = spacing;
-       settings->stablerandom                  = s ? 1 : r_shadow_bouncegrid_dynamic_stablerandom.integer;
+       settings->stablerandom                  = r_shadow_bouncegrid_dynamic_stablerandom.integer;
        settings->bounceminimumintensity2       = bounceminimumintensity * bounceminimumintensity;
+       settings->normalizevectors              = r_shadow_bouncegrid_normalizevectors.integer != 0;
 
        // bound the values for sanity
        settings->maxphotons = bound(1, settings->maxphotons, 25000000);
@@ -2748,7 +2751,7 @@ static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *se
        dlight_t *light;
        rtlight_t *rtlight;
        normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
-       for (lightindex = 0; lightindex < range2; lightindex++)
+       for (lightindex = 0;lightindex < range2;lightindex++)
        {
                if (lightindex < range)
                {
@@ -2795,8 +2798,8 @@ static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *se
                        if (R_CullBox(cullmins, cullmaxs))
                                continue;
                        if (r_refdef.scene.worldmodel
-                               && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
-                               && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
+                        && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
+                        && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
                                continue;
                        if (w * VectorLength2(rtlight->color) == 0.0f)
                                continue;
@@ -2808,7 +2811,7 @@ static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *se
                w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
                VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
                // skip lights that will emit no photons
-               if (VectorLength2(rtlight->bouncegrid_photoncolor) <= 0.0f)
+               if (!VectorLength2(rtlight->bouncegrid_photoncolor))
                        continue;
                // shoot particles from this light
                // use a calculation for the number of particles that will not
@@ -3273,7 +3276,7 @@ static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t sett
        //trace_t cliptrace2;
        //trace_t cliptrace3;
        unsigned int lightindex;
-       unsigned int seed = (unsigned int)(realtime * 1000.0f);
+       unsigned int seed;
        randomseed_t randomseed;
        vec3_t shotcolor;
        vec3_t baseshotcolor;
@@ -3284,8 +3287,18 @@ static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t sett
        vec_t radius;
        vec_t s;
        rtlight_t *rtlight;
+       union
+       {
+               unsigned int s[4];
+               double d;
+       }
+       rseed;
 
-       Math_RandomSeed_FromInt(&randomseed, seed);
+       // compute a seed for the unstable random modes
+       memset(&rseed, 0, sizeof(rseed));
+       rseed.d = realtime;
+       Math_RandomSeed_FromInts(&randomseed, rseed.s[0], rseed.s[1], rseed.s[2], rseed.s[3]);
+       seed = rseed.s[0] ^ rseed.s[1] ^ rseed.s[2] ^ rseed.s[3];
 
        r_shadow_bouncegrid_state.numsplatpaths = 0;
 
@@ -3294,7 +3307,7 @@ static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t sett
                hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
        else
                hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
-       skipsupercontentsmask = SUPERCONTENTS_SKY; // skipsurfaces with this contents, even if they also have SUPERCONTENTS_SOLID (basically this is for e1m5.bsp sky trick)
+       skipsupercontentsmask = SUPERCONTENTS_SKY; // this allows the e1m5 sky shadow to work by ignoring the sky surfaces
        maxbounce = settings.maxbounce;
 
        for (lightindex = 0;lightindex < range2;lightindex++)
@@ -3325,21 +3338,33 @@ static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t sett
                r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
                // we stop caring about bounces once the brightness goes below this fraction of the original intensity
                bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
-               switch (settings.stablerandom)
+
+               // for stablerandom we start the RNG with the position of the light
+               if (settings.stablerandom > 0)
                {
-               default:
-                       break;
-               case 1:
-                       Math_RandomSeed_FromInt(&randomseed, lightindex * 11937);
-                       // prime the random number generator a bit
-                       Math_crandomf(&randomseed);
-                       break;
-               case 2:
-                       seed = lightindex * 11937;
-                       // prime the random number generator a bit
-                       lhcheeserand(seed);
-                       break;
+                       union
+                       {
+                               unsigned int i[4];
+                               float f[4];
+                       }
+                       u;
+                       u.f[0] = rtlight->shadoworigin[0];
+                       u.f[1] = rtlight->shadoworigin[1];
+                       u.f[2] = rtlight->shadoworigin[2];
+                       u.f[3] = 1;
+                       switch (settings.stablerandom)
+                       {
+                       default:
+                               break;
+                       case 1:
+                               seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3];
+                               break;
+                       case 2:
+                               Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3]);
+                               break;
+                       }
                }
+
                for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
                {
                        VectorCopy(baseshotcolor, shotcolor);
@@ -3358,25 +3383,30 @@ static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t sett
                                break;
                        case -1:
                        case 1:
-                               VectorLehmerRandom(&randomseed, clipend);
+                               VectorCheeseRandom(seed, clipend);
                                if (settings.bounceanglediffuse)
                                {
                                        // we want random to be stable, so we still have to do all the random we would have done
                                        for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
-                                               VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
+                                               VectorCheeseRandom(seed, bouncerandom[bouncecount]);
                                }
                                break;
                        case -2:
                        case 2:
-                               VectorCheeseRandom(seed, clipend);
+                               VectorLehmerRandom(&randomseed, clipend);
                                if (settings.bounceanglediffuse)
                                {
                                        // we want random to be stable, so we still have to do all the random we would have done
                                        for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
-                                               VectorCheeseRandom(seed, bouncerandom[bouncecount]);
+                                               VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
                                }
                                break;
                        }
+
+                       // we want a uniform distribution spherically, not merely within the sphere
+                       if (settings.normalizevectors)
+                               VectorNormalize(clipend);
+
                        VectorMA(clipstart, radius, clipend, clipend);
                        for (bouncecount = 0;;bouncecount++)
                        {
@@ -3393,7 +3423,7 @@ static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t sett
                                else
                                {
                                        // dynamic mode fires many rays and most will match the cache from the previous frame
-                                       cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS, hitsupercontentsmask, skipsupercontentsmask);
+                                       cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask);
                                }
                                if (bouncecount > 0 || settings.includedirectlighting)
                                {
@@ -7191,7 +7221,7 @@ void R_Shadow_EditLights_DrawSelectedLightProperties(void)
                return;
        x = vid_conwidth.value - 320;
        y = 5;
-       DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
+       DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
        lightnumber = -1;
        lightcount = 0;
        range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked