]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
remove some stupid \n chars in infobar strings
[xonotic/darkplaces.git] / r_shadow.c
index 1e6aa9a7a3645373e2c3e61d79ed3afe93c5eadc..654cfa91b2e9c279aa67060cac0ac95f1966ed06 100644 (file)
@@ -349,6 +349,7 @@ static memexpandablearray_t r_shadow_worldlightsarray;
 dlight_t *r_shadow_selectedlight;
 dlight_t r_shadow_bufferlight;
 vec3_t r_editlights_cursorlocation;
+qboolean r_editlights_lockcursor;
 
 extern int con_vislines;
 
@@ -442,6 +443,12 @@ void R_Shadow_SetShadowMode(void)
                                        r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
                                break;
                        }
+                       // Cg has very little choice in depth texture sampling
+                       if (vid.cgcontext)
+                       {
+                               r_shadow_shadowmapsampler = false;
+                               r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
+                       }
                }
                break;
        case RENDERPATH_GL13:
@@ -659,7 +666,7 @@ void r_shadow_newmap(void)
        if (r_editlights_sprcubemaplight)         R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
        if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
        if (r_editlights_sprselection)            R_SkinFrame_MarkUsed(r_editlights_sprselection);
-       if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
+       if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
                R_Shadow_EditLights_Reload_f();
 }
 
@@ -754,7 +761,7 @@ void R_Shadow_Init(void)
        r_shadow_buffer_surfacesides = NULL;
        r_shadow_buffer_shadowtrispvs = NULL;
        r_shadow_buffer_lighttrispvs = NULL;
-       R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
+       R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
 }
 
 matrix4x4_t matrix_attenuationxyz =
@@ -1507,19 +1514,48 @@ int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
        }
        // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
        // check if frustum corners/origin cross plane sides
+#if 1
+    // infinite version, assumes frustum corners merely give direction and extend to infinite distance
+    Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
+    dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
+    masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
+    masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
+    dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
+    masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
+    masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
+    dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
+    masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
+    masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
+    for (i = 0;i < 4;i++)
+    {
+        Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
+        VectorSubtract(n, p, n);
+        dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
+        if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
+        if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
+        dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
+        if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
+        if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
+        dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
+        if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
+        if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
+    }
+#else
+    // finite version, assumes corners are a finite distance from origin dependent on far plane
        for (i = 0;i < 5;i++)
        {
                Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
-               dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
+               dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
                masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
                masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
-               dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
+               dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
                masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
                masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
-               dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
+               dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
                masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
                masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
        }
+#endif
        return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
 }
 
@@ -1718,12 +1754,12 @@ static void R_Shadow_MakeTextures(void)
        // 1D gradient texture
        for (x = 0;x < ATTEN1DSIZE;x++)
                data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
-       r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
+       r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
        // 2D circle texture
        for (y = 0;y < ATTEN2DSIZE;y++)
                for (x = 0;x < ATTEN2DSIZE;x++)
                        data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
-       r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
+       r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
        // 3D sphere texture
        if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
        {
@@ -1731,7 +1767,7 @@ static void R_Shadow_MakeTextures(void)
                        for (y = 0;y < ATTEN3DSIZE;y++)
                                for (x = 0;x < ATTEN3DSIZE;x++)
                                        data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
-               r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
+               r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
        }
        else
                r_shadow_attenuation3dtexture = NULL;
@@ -2054,7 +2090,7 @@ static void R_Shadow_MakeVSDCT(void)
                0,   0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
                0,   0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
        };
-       r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
+       r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
 }
 
 static void R_Shadow_MakeShadowMap(int side, int size)
@@ -2108,15 +2144,15 @@ void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
        nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
        farclip = 1.0f;
        bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
-       r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
-       r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
+       r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
+       r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
        r_shadow_shadowmapside = side;
        r_shadow_shadowmapsize = size;
        switch (r_shadow_shadowmode)
        {
        case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
                r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
-               r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
+               r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
                R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
 
@@ -2133,7 +2169,7 @@ void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
                break;
        case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
                r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
-               r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
+               r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
                R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
 
@@ -2150,7 +2186,7 @@ void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
                break;
        case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
                r_shadow_shadowmap_parameters[0] = 1.0f;
-               r_shadow_shadowmap_parameters[1] = 1.0f;
+               r_shadow_shadowmap_parameters[2] = 1.0f;
                R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
                if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
 
@@ -2412,116 +2448,21 @@ int bboxedges[12][2] =
 
 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
 {
-       int i, ix1, iy1, ix2, iy2;
-       float x1, y1, x2, y2;
-       vec4_t v, v2;
-       float vertex[20][3];
-       int j, k;
-       vec4_t plane4f;
-       int numvertices;
-       float corner[8][4];
-       float dist[8];
-       int sign[8];
-       float f;
-
-       r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
-       r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
-       r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
-       r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
-
        if (!r_shadow_scissor.integer)
-               return false;
-
-       // if view is inside the light box, just say yes it's visible
-       if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
-               return false;
-
-       x1 = y1 = x2 = y2 = 0;
-
-       // transform all corners that are infront of the nearclip plane
-       VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
-       plane4f[3] = r_refdef.view.frustum[4].dist;
-       numvertices = 0;
-       for (i = 0;i < 8;i++)
-       {
-               Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
-               dist[i] = DotProduct4(corner[i], plane4f);
-               sign[i] = dist[i] > 0;
-               if (!sign[i])
-               {
-                       VectorCopy(corner[i], vertex[numvertices]);
-                       numvertices++;
-               }
-       }
-       // if some points are behind the nearclip, add clipped edge points to make
-       // sure that the scissor boundary is complete
-       if (numvertices > 0 && numvertices < 8)
        {
-               // add clipped edge points
-               for (i = 0;i < 12;i++)
-               {
-                       j = bboxedges[i][0];
-                       k = bboxedges[i][1];
-                       if (sign[j] != sign[k])
-                       {
-                               f = dist[j] / (dist[j] - dist[k]);
-                               VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
-                               numvertices++;
-                       }
-               }
-       }
-
-       // if we have no points to check, the light is behind the view plane
-       if (!numvertices)
-               return true;
-
-       // if we have some points to transform, check what screen area is covered
-       x1 = y1 = x2 = y2 = 0;
-       v[3] = 1.0f;
-       //Con_Printf("%i vertices to transform...\n", numvertices);
-       for (i = 0;i < numvertices;i++)
-       {
-               VectorCopy(vertex[i], v);
-               R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
-               //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
-               if (i)
-               {
-                       if (x1 > v2[0]) x1 = v2[0];
-                       if (x2 < v2[0]) x2 = v2[0];
-                       if (y1 > v2[1]) y1 = v2[1];
-                       if (y2 < v2[1]) y2 = v2[1];
-               }
-               else
-               {
-                       x1 = x2 = v2[0];
-                       y1 = y2 = v2[1];
-               }
+               r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
+               r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
+               r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
+               r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
+               return false;
        }
-
-       // now convert the scissor rectangle to integer screen coordinates
-       ix1 = (int)(x1 - 1.0f);
-       iy1 = vid.height - (int)(y2 - 1.0f);
-       ix2 = (int)(x2 + 1.0f);
-       iy2 = vid.height - (int)(y1 + 1.0f);
-       //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
-
-       // clamp it to the screen
-       if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
-       if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
-       if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
-       if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
-
-       // if it is inside out, it's not visible
-       if (ix2 <= ix1 || iy2 <= iy1)
-               return true;
-
-       // the light area is visible, set up the scissor rectangle
-       r_shadow_lightscissor[0] = ix1;
-       r_shadow_lightscissor[1] = iy1;
-       r_shadow_lightscissor[2] = ix2 - ix1;
-       r_shadow_lightscissor[3] = iy2 - iy1;
-
-       r_refdef.stats.lights_scissored++;
+       if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
+               return true; // invisible
+       if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
+       || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
+       || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
+       || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
+               r_refdef.stats.lights_scissored++;
        return false;
 }
 
@@ -3456,19 +3397,19 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight)
        static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
        static entity_render_t *shadowentities[MAX_EDICTS];
        static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
+       qboolean nolight;
 
        rtlight->draw = false;
 
        // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
        // skip lights that are basically invisible (color 0 0 0)
-       if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
-               return;
+       nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
 
        // loading is done before visibility checks because loading should happen
        // all at once at the start of a level, not when it stalls gameplay.
        // (especially important to benchmarks)
        // compile light
-       if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
+       if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
        {
                if (rtlight->compiled)
                        R_RTLight_Uncompile(rtlight);
@@ -3493,6 +3434,10 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight)
        if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
                return;
 
+       // skip processing on corona-only lights
+       if (nolight)
+               return;
+
        // if the light box is offscreen, skip it
        if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
                return;
@@ -4066,9 +4011,9 @@ void R_Shadow_PrepareLights(void)
                        r_shadow_prepass_width = vid.width;
                        r_shadow_prepass_height = vid.height;
                        r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
-                       r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
-                       r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
-                       r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
+                       r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
+                       r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
+                       r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
 
                        // set up the geometry pass fbo (depth + normalmap)
                        qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
@@ -4203,12 +4148,13 @@ extern cvar_t r_shadows_castfrombmodels;
 extern cvar_t r_shadows_throwdistance;
 extern cvar_t r_shadows_throwdirection;
 extern cvar_t r_shadows_focus;
+extern cvar_t r_shadows_shadowmapscale;
 
 void R_Shadow_PrepareModelShadows(void)
 {
        int i;
        float scale, size, radius, dot1, dot2;
-       vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowmins, shadowmaxs;
+       vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
        entity_render_t *ent;
 
        if (!r_refdef.scene.numentities)
@@ -4218,7 +4164,9 @@ void R_Shadow_PrepareModelShadows(void)
        {
        case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
        case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
-               break;
+               if (r_shadows.integer >= 2) 
+                       break;
+               // fall through
        case R_SHADOW_SHADOWMODE_STENCIL:
                for (i = 0;i < r_refdef.scene.numentities;i++)
                {
@@ -4232,8 +4180,9 @@ void R_Shadow_PrepareModelShadows(void)
        }
 
        size = 2*r_shadow_shadowmapmaxsize;
-       scale = r_shadow_shadowmapping_precision.value;
+       scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
        radius = 0.5f * size / scale;
+
        Math_atov(r_shadows_throwdirection.string, shadowdir);
        VectorNormalize(shadowdir);
        dot1 = DotProduct(r_refdef.view.forward, shadowdir);
@@ -4244,8 +4193,13 @@ void R_Shadow_PrepareModelShadows(void)
                VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
        VectorNormalize(shadowforward);
        CrossProduct(shadowdir, shadowforward, shadowright);
-       Math_atov(r_shadows_focus.string, shadoworigin);
+       Math_atov(r_shadows_focus.string, shadowfocus);
+       VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
+       VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
+       VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
        VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
+       if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
+               dot1 = 1;
        VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
 
        shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
@@ -4269,14 +4223,14 @@ void R_Shadow_PrepareModelShadows(void)
 void R_DrawModelShadowMaps(void)
 {
        int i;
-       float relativethrowdistance, scale, size, radius, nearclip, farclip, dot1, dot2;
+       float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
        entity_render_t *ent;
        vec3_t relativelightorigin;
        vec3_t relativelightdirection, relativeforward, relativeright;
        vec3_t relativeshadowmins, relativeshadowmaxs;
-       vec3_t shadowdir, shadowforward, shadowright, shadoworigin;
+       vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
        float m[12];
-       matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix;
+       matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
        r_viewport_t viewport;
        GLuint fbo = 0;
 
@@ -4320,19 +4274,23 @@ void R_DrawModelShadowMaps(void)
        }
 
        size = 2*r_shadow_shadowmapmaxsize;
-
-       r_shadow_shadowmap_parameters[0] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
-       r_shadow_shadowmap_parameters[1] = 1.0f;
-       r_shadow_shadowmap_parameters[2] = size;
-       r_shadow_shadowmap_parameters[3] = size;
-
-       scale = r_shadow_shadowmapping_precision.value;
-       radius = 0.5f * size / scale;
+       scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
+       radius = 0.5f / scale;
        nearclip = -r_shadows_throwdistance.value;
        farclip = r_shadows_throwdistance.value;
+       bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
+
+       r_shadow_shadowmap_parameters[0] = size;
+       r_shadow_shadowmap_parameters[1] = size;
+       r_shadow_shadowmap_parameters[2] = 1.0;
+       r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
+
        Math_atov(r_shadows_throwdirection.string, shadowdir);
        VectorNormalize(shadowdir);
-       Math_atov(r_shadows_focus.string, shadoworigin);
+       Math_atov(r_shadows_focus.string, shadowfocus);
+       VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
+       VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
+       VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
        VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
        dot1 = DotProduct(r_refdef.view.forward, shadowdir);
        dot2 = DotProduct(r_refdef.view.up, shadowdir);
@@ -4342,15 +4300,17 @@ void R_DrawModelShadowMaps(void)
                VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
        VectorNormalize(shadowforward);
        VectorM(scale, shadowforward, &m[0]);
-       m[3] = fabs(dot1) * 0.5f * size - DotProduct(shadoworigin, &m[0]);
+       if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
+               dot1 = 1;
+       m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
        CrossProduct(shadowdir, shadowforward, shadowright);
        VectorM(scale, shadowright, &m[4]);
-       m[7] = 0.5f * size - DotProduct(shadoworigin, &m[4]);
+       m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
        VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
        m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
        Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
        Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
-       R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, size, size, 0, 0, -1, NULL); 
+       R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); 
 
        VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
  
@@ -4377,10 +4337,6 @@ void R_DrawModelShadowMaps(void)
        GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
        CHECKGLERROR
 
-       r_refdef.view.cullface_front = r_shadow_cullface_back;
-       r_refdef.view.cullface_back = r_shadow_cullface_front;
-       GL_CullFace(r_refdef.view.cullface_back);
-
        for (i = 0;i < r_refdef.scene.numentities;i++)
        {
                ent = r_refdef.scene.entities[i];
@@ -4409,7 +4365,10 @@ void R_DrawModelShadowMaps(void)
 
        Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
        Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
-       Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &shadowmatrix, &invmvpmatrix);
+       Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
+       Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
+       Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
+       Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
 
        r_shadow_usingshadowmaportho = true;
        switch (r_shadow_shadowmode)
@@ -4435,7 +4394,7 @@ void R_DrawModelShadows(void)
        vec3_t relativeshadowmins, relativeshadowmaxs;
        vec3_t tmp, shadowdir;
 
-       if (!r_refdef.scene.numentities || !vid.stencil || r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL)
+       if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
                return;
 
        CHECKGLERROR
@@ -4475,26 +4434,34 @@ void R_DrawModelShadows(void)
                        {
                                if(ent->entitynumber != 0)
                                {
-                                       // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
-                                       int entnum, entnum2, recursion;
-                                       entnum = entnum2 = ent->entitynumber;
-                                       for(recursion = 32; recursion > 0; --recursion)
+                                       if(ent->entitynumber >= MAX_EDICTS) // csqc entity
                                        {
-                                               entnum2 = cl.entities[entnum].state_current.tagentity;
-                                               if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
-                                                       entnum = entnum2;
-                                               else
-                                                       break;
+                                               // FIXME handle this
+                                               VectorNegate(ent->modellight_lightdir, relativelightdirection);
                                        }
-                                       if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
+                                       else
                                        {
-                                               VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
-                                               // transform into modelspace of OUR entity
-                                               Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
-                                               Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
+                                               // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
+                                               int entnum, entnum2, recursion;
+                                               entnum = entnum2 = ent->entitynumber;
+                                               for(recursion = 32; recursion > 0; --recursion)
+                                               {
+                                                       entnum2 = cl.entities[entnum].state_current.tagentity;
+                                                       if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
+                                                               entnum = entnum2;
+                                                       else
+                                                               break;
+                                               }
+                                               if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
+                                               {
+                                                       VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
+                                                       // transform into modelspace of OUR entity
+                                                       Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
+                                                       Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
+                                               }
+                                               else
+                                                       VectorNegate(ent->modellight_lightdir, relativelightdirection);
                                        }
-                                       else
-                                               VectorNegate(ent->modellight_lightdir, relativelightdirection);
                                }
                                else
                                        VectorNegate(ent->modellight_lightdir, relativelightdirection);
@@ -4869,7 +4836,8 @@ void R_Shadow_DrawLightSprites(void)
                if (light)
                        R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
        }
-       R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
+       if (!r_editlights_lockcursor)
+               R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
 }
 
 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
@@ -4901,6 +4869,9 @@ void R_Shadow_SelectLightInView(void)
        size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
        best = NULL;
        bestrating = 0;
+
+       if (r_editlights_lockcursor)
+               return;
        for (lightindex = 0;lightindex < range;lightindex++)
        {
                light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
@@ -4931,8 +4902,7 @@ void R_Shadow_LoadWorldLights(void)
                Con_Print("No map loaded.\n");
                return;
        }
-       FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
-       strlcat (name, ".rtlights", sizeof (name));
+       dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
        lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
        if (lightsstring)
        {
@@ -5042,8 +5012,7 @@ void R_Shadow_SaveWorldLights(void)
                Con_Print("No map loaded.\n");
                return;
        }
-       FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
-       strlcat (name, ".rtlights", sizeof (name));
+       dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
        bufchars = bufmaxchars = 0;
        buf = NULL;
        for (lightindex = 0;lightindex < range;lightindex++)
@@ -5091,8 +5060,7 @@ void R_Shadow_LoadLightsFile(void)
                Con_Print("No map loaded.\n");
                return;
        }
-       FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
-       strlcat (name, ".lights", sizeof (name));
+       dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
        lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
        if (lightsstring)
        {
@@ -5154,8 +5122,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                return;
        }
        // try to load a .ent file first
-       FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
-       strlcat (key, ".ent", sizeof (key));
+       dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
        data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
        // and if that is not found, fall back to the bsp file entity string
        if (!data)
@@ -5404,7 +5371,7 @@ void R_Shadow_EditLights_Reload_f(void)
 {
        if (!cl.worldmodel)
                return;
-       strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
+       strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
        R_Shadow_ClearWorldLights();
        R_Shadow_LoadWorldLights();
        if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
@@ -5769,7 +5736,7 @@ void R_Shadow_EditLights_Edit_f(void)
 void R_Shadow_EditLights_EditAll_f(void)
 {
        size_t lightindex;
-       dlight_t *light;
+       dlight_t *light, *oldselected;
        size_t range;
 
        if (!r_editlights.integer)
@@ -5778,6 +5745,7 @@ void R_Shadow_EditLights_EditAll_f(void)
                return;
        }
 
+       oldselected = r_shadow_selectedlight;
        // EditLights doesn't seem to have a "remove" command or something so:
        range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
        for (lightindex = 0;lightindex < range;lightindex++)
@@ -5788,6 +5756,8 @@ void R_Shadow_EditLights_EditAll_f(void)
                R_Shadow_SelectLight(light);
                R_Shadow_EditLights_Edit_f();
        }
+       // return to old selected (to not mess editing once selection is locked)
+       R_Shadow_SelectLight(oldselected);
 }
 
 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
@@ -5897,6 +5867,7 @@ void R_Shadow_EditLights_Help_f(void)
 "r_editlights_help : this help\n"
 "r_editlights_clear : remove all lights\n"
 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
+"r_editlights_lock : lock selection to current light, if already locked - unlock\n"
 "r_editlights_save : save to .rtlights file\n"
 "r_editlights_spawn : create a light with default settings\n"
 "r_editlights_edit command : edit selected light - more documentation below\n"
@@ -5981,6 +5952,26 @@ void R_Shadow_EditLights_PasteInfo_f(void)
        R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname, r_shadow_bufferlight.coronasizescale, r_shadow_bufferlight.ambientscale, r_shadow_bufferlight.diffusescale, r_shadow_bufferlight.specularscale, r_shadow_bufferlight.flags);
 }
 
+void R_Shadow_EditLights_Lock_f(void)
+{
+       if (!r_editlights.integer)
+       {
+               Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
+               return;
+       }
+       if (r_editlights_lockcursor)
+       {
+               r_editlights_lockcursor = false;
+               return;
+       }
+       if (!r_shadow_selectedlight)
+       {
+               Con_Print("No selected light to lock on.\n");
+               return;
+       }
+       r_editlights_lockcursor = true;
+}
+
 void R_Shadow_EditLights_Init(void)
 {
        Cvar_RegisterVariable(&r_editlights);
@@ -6003,6 +5994,7 @@ void R_Shadow_EditLights_Init(void)
        Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
        Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
        Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");
+       Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
 }
 
 
@@ -6015,7 +6007,7 @@ LIGHT SAMPLING
 =============================================================================
 */
 
-void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
+void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, qboolean dynamic, qboolean rtworld)
 {
        VectorClear(diffusecolor);
        VectorClear(diffusenormal);
@@ -6030,16 +6022,57 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu
 
        if (dynamic)
        {
-               int i;
-               float f, v[3];
+               int i, numlights, flag;
+               float f, relativepoint[3], dist, dist2, lightradius2;
                rtlight_t *light;
+               dlight_t *dlight;
+
+               // sample rtlights
+               if (rtworld)
+               {
+                       flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+                       numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
+                       for (i = 0; i < numlights; i++)
+                       {
+                               dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
+                               if (!dlight)
+                                       continue;
+                               light = &dlight->rtlight;
+                               if (!(light->flags & flag))
+                                       continue;
+                               // sample
+                               lightradius2 = light->radius * light->radius;
+                               VectorSubtract(light->shadoworigin, p, relativepoint);
+                               dist2 = VectorLength2(relativepoint);
+                               if (dist2 >= lightradius2)
+                                       continue;
+                               dist = sqrt(dist2) / light->radius;
+                               f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
+                               if (f <= 0)
+                                       continue;
+                               // todo: add to both ambient and diffuse
+                               if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
+                                       VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
+                       }
+               }
+
+               // sample dlights
                for (i = 0;i < r_refdef.scene.numlights;i++)
                {
                        light = r_refdef.scene.lights[i];
-                       Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
-                       f = 1 - VectorLength2(v);
-                       if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
-                               VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
+                       // sample
+                       lightradius2 = light->radius * light->radius;
+                       VectorSubtract(light->shadoworigin, p, relativepoint);
+                       dist2 = VectorLength2(relativepoint);
+                       if (dist2 >= lightradius2)
+                               continue;
+                       dist = sqrt(dist2) / light->radius;
+                       f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
+                       if (f <= 0)
+                               continue;
+                       // todo: add to both ambient and diffuse
+                       if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
+                               VectorMA(ambientcolor, f, light->color, ambientcolor);
                }
        }
 }