]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
entity shadow casting is now optional per entity (EF_NOSHADOW added), and special...
[xonotic/darkplaces.git] / gl_rmain.c
index 24c9baa056c896a373b90581408c14f15e44402c..fe0052d2830c1a4ae443dd2b3b7ae59a41123781 100644 (file)
@@ -51,13 +51,14 @@ unsigned short d_lightstylevalue[256];
 
 cvar_t r_drawentities = {0, "r_drawentities","1"};
 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
-cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "1"};
-cvar_t r_staticworldlights = {0, "r_staticworldlights", "1"};
+cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0"};
+cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
 cvar_t r_speeds = {0, "r_speeds","0"};
 cvar_t r_fullbright = {0, "r_fullbright","0"};
 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
+cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
 
 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
@@ -221,14 +222,15 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable (&r_drawentities);
        Cvar_RegisterVariable (&r_drawviewmodel);
        Cvar_RegisterVariable (&r_shadows);
-       Cvar_RegisterVariable (&r_staticworldlights);
+       Cvar_RegisterVariable (&r_shadow_staticworldlights);
        Cvar_RegisterVariable (&r_speeds);
        Cvar_RegisterVariable (&r_fullbrights);
        Cvar_RegisterVariable (&r_wateralpha);
        Cvar_RegisterVariable (&r_dynamic);
        Cvar_RegisterVariable (&r_fullbright);
        Cvar_RegisterVariable (&r_textureunits);
-       if (gamemode == GAME_NEHAHRA)
+       Cvar_RegisterVariable (&r_shadow_cull);
+       if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXIUZ)
                Cvar_SetValue("r_fullbrights", 0);
        R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
 }
@@ -381,6 +383,8 @@ int PVS_CullBox(const vec3_t mins, const vec3_t maxs)
 {
        int stackpos, sides;
        mnode_t *node, *stack[4096];
+       if (cl.worldmodel == NULL)
+               return false;
        stackpos = 0;
        stack[stackpos++] = cl.worldmodel->nodes;
        while (stackpos)
@@ -409,6 +413,8 @@ int VIS_CullBox(const vec3_t mins, const vec3_t maxs)
        mnode_t *node, *stack[4096];
        if (R_CullBox(mins, maxs))
                return true;
+       if (cl.worldmodel == NULL)
+               return false;
        stackpos = 0;
        stack[stackpos++] = cl.worldmodel->nodes;
        while (stackpos)
@@ -444,6 +450,8 @@ int PVS_CullSphere(const vec3_t origin, vec_t radius)
        int stackpos;
        mnode_t *node, *stack[4096];
        float dist;
+       if (cl.worldmodel == NULL)
+               return false;
        stackpos = 0;
        stack[stackpos++] = cl.worldmodel->nodes;
        while (stackpos)
@@ -473,6 +481,8 @@ int VIS_CullSphere(const vec3_t origin, vec_t radius)
        float dist;
        if (R_CullSphere(origin, radius))
                return true;
+       if (cl.worldmodel == NULL)
+               return false;
        stackpos = 0;
        stack[stackpos++] = cl.worldmodel->nodes;
        while (stackpos)
@@ -577,6 +587,7 @@ int R_DrawBrushModelsSky (void)
 R_DrawViewModel
 =============
 */
+/*
 void R_DrawViewModel (void)
 {
        entity_render_t *ent;
@@ -593,6 +604,7 @@ void R_DrawViewModel (void)
        R_UpdateEntLights(ent);
        ent->model->Draw(ent);
 }
+*/
 
 void R_DrawNoModel(entity_render_t *ent);
 void R_DrawModels ()
@@ -603,7 +615,6 @@ void R_DrawModels ()
        if (!r_drawentities.integer)
                return;
 
-       R_DrawViewModel();
        for (i = 0;i < r_refdef.numentities;i++)
        {
                ent = r_refdef.entities[i];
@@ -631,7 +642,7 @@ void R_DrawFakeShadows (void)
        for (i = 0;i < r_refdef.numentities;i++)
        {
                ent = r_refdef.entities[i];
-               if (ent->model && ent->model->DrawFakeShadow)
+               if ((ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawFakeShadow)
                        ent->model->DrawFakeShadow(ent);
        }
 }
@@ -644,6 +655,8 @@ int Light_CullBox(const vec3_t mins, const vec3_t maxs)
 {
        int stackpos, sides;
        mnode_t *node, *stack[4096];
+       if (cl.worldmodel == NULL)
+               return false;
        stackpos = 0;
        stack[stackpos++] = cl.worldmodel->nodes;
        while (stackpos)
@@ -672,6 +685,8 @@ int LightAndVis_CullBox(const vec3_t mins, const vec3_t maxs)
        mnode_t *node, *stack[4096];
        if (R_CullBox(mins, maxs))
                return true;
+       if (cl.worldmodel == NULL)
+               return false;
        stackpos = 0;
        stack[stackpos++] = cl.worldmodel->nodes;
        while (stackpos)
@@ -694,50 +709,118 @@ int LightAndVis_CullBox(const vec3_t mins, const vec3_t maxs)
        return true;
 }
 
+int LightAndVis_CullPointCloud(int numpoints, const float *points)
+{
+       int i;
+       const float *p;
+       int stackpos, sides;
+       mnode_t *node, *stack[4096];
+       //if (R_CullBox(mins, maxs))
+       //      return true;
+       if (cl.worldmodel == NULL)
+               return false;
+       stackpos = 0;
+       stack[stackpos++] = cl.worldmodel->nodes;
+       while (stackpos)
+       {
+               node = stack[--stackpos];
+               if (node->contents < 0)
+               {
+                       if (((mleaf_t *)node)->visframe == r_framecount && ((mleaf_t *)node)->worldnodeframe == shadowframecount)
+                               return false;
+               }
+               else
+               {
+                       sides = 0;
+                       for (i = 0, p = points;i < numpoints && sides != 3;i++, p += 3)
+                       {
+                               if (DotProduct(p, node->plane->normal) < node->plane->dist)
+                                       sides |= 1;
+                               else
+                                       sides |= 2;
+                       }
+                       if (sides & 2 && stackpos < 4096)
+                               stack[stackpos++] = node->children[1];
+                       if (sides & 1 && stackpos < 4096)
+                               stack[stackpos++] = node->children[0];
+               }
+       }
+       return true;
+}
 
-void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float cullradius, float lightradius, vec3_t clipmins, vec3_t clipmaxs)
+
+void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float cullradius, float lightradius, vec3_t lightmins, vec3_t lightmaxs, vec3_t clipmins, vec3_t clipmaxs)
 {
+       vec3_t relativelightorigin;
+       #if 0
        int i;
-       vec3_t p, p2, temp, relativelightorigin, mins, maxs;
+       vec3_t p, p2, temp, relativelightorigin/*, mins, maxs*/;
        float dist, projectdistance;
+       float points[16][3];
+       #endif
        // rough checks
-       if (ent->model && ent->model->DrawShadowVolume)
+       if (!(ent->flags & RENDER_SHADOW) || ent->model == NULL || ent->model->DrawShadowVolume == NULL)
+               return;
+       if (r_shadow_cull.integer)
+       {
+               if (ent->maxs[0] < lightmins[0] || ent->mins[0] > lightmaxs[0]
+                || ent->maxs[1] < lightmins[1] || ent->mins[1] > lightmaxs[1]
+                || ent->maxs[2] < lightmins[2] || ent->mins[2] > lightmaxs[2]
+                || Light_CullBox(ent->mins, ent->maxs))
+                       return;
+       }
+       #if 0
+       if (r_shadow_cull.integer)
        {
-               temp[0] = bound(ent->mins[0], lightorigin[0], ent->maxs[0]) - lightorigin[0];
-               temp[1] = bound(ent->mins[1], lightorigin[1], ent->maxs[1]) - lightorigin[1];
-               temp[2] = bound(ent->mins[2], lightorigin[2], ent->maxs[2]) - lightorigin[2];
-               dist = DotProduct(temp, temp);
-               if (dist < cullradius * cullradius)
+               projectdistance = cullradius;
+               // calculate projected bounding box and decide if it is on-screen
+               for (i = 0;i < 8;i++)
+               {
+                       temp[0] = i & 1 ? ent->model->normalmaxs[0] : ent->model->normalmins[0];
+                       temp[1] = i & 2 ? ent->model->normalmaxs[1] : ent->model->normalmins[1];
+                       temp[2] = i & 4 ? ent->model->normalmaxs[2] : ent->model->normalmins[2];
+                       Matrix4x4_Transform(&ent->matrix, temp, points[i]);
+                       VectorSubtract(points[i], lightorigin, temp);
+                       dist = projectdistance / sqrt(DotProduct(temp, temp));
+                       VectorMA(points[i], dist, temp, points[i+8]);
+               }
+               if (LightAndVis_CullPointCloud(16, points[0]))
+                       return;
+               /*
+               for (i = 0;i < 8;i++)
                {
-                       if (!Light_CullBox(ent->mins, ent->maxs))
+                       p2[0] = i & 1 ? ent->model->normalmaxs[0] : ent->model->normalmins[0];
+                       p2[1] = i & 2 ? ent->model->normalmaxs[1] : ent->model->normalmins[1];
+                       p2[2] = i & 4 ? ent->model->normalmaxs[2] : ent->model->normalmins[2];
+                       Matrix4x4_Transform(&ent->matrix, p2, p);
+                       VectorSubtract(p, lightorigin, temp);
+                       dist = projectdistance / sqrt(DotProduct(temp, temp));
+                       VectorMA(p, dist, temp, p2);
+                       if (i)
                        {
-                               projectdistance = cullradius - sqrt(dist);
-                               // calculate projected bounding box and decide if it is on-screen
-                               VectorCopy(ent->mins, mins);
-                               VectorCopy(ent->maxs, maxs);
-                               for (i = 0;i < 8;i++)
-                               {
-                                       p[0] = i & 1 ? ent->maxs[0] : ent->mins[0];
-                                       p[1] = i & 2 ? ent->maxs[1] : ent->mins[1];
-                                       p[2] = i & 4 ? ent->maxs[2] : ent->mins[2];
-                                       VectorSubtract(p, lightorigin, temp);
-                                       dist = projectdistance / sqrt(DotProduct(temp, temp));
-                                       VectorMA(p, dist, temp, p2);
-                                       if (mins[0] > p2[0]) mins[0] = p2[0];if (maxs[0] < p2[0]) maxs[0] = p2[0];
-                                       if (mins[1] > p2[1]) mins[1] = p2[1];if (maxs[1] < p2[1]) maxs[1] = p2[1];
-                                       if (mins[2] > p2[2]) mins[2] = p2[2];if (maxs[2] < p2[2]) maxs[2] = p2[2];
-                               }
-                               if (mins[0] < clipmaxs[0] && maxs[0] > clipmins[0]
-                                && mins[1] < clipmaxs[1] && maxs[1] > clipmins[1]
-                                && mins[2] < clipmaxs[2] && maxs[2] > clipmins[2]
-                                && !LightAndVis_CullBox(mins, maxs))
-                               {
-                                       Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
-                                       ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius);
-                               }
+                               if (mins[0] > p[0]) mins[0] = p[0];if (maxs[0] < p[0]) maxs[0] = p[0];
+                               if (mins[1] > p[1]) mins[1] = p[1];if (maxs[1] < p[1]) maxs[1] = p[1];
+                               if (mins[2] > p[2]) mins[2] = p[2];if (maxs[2] < p[2]) maxs[2] = p[2];
                        }
+                       else
+                       {
+                               VectorCopy(p, mins);
+                               VectorCopy(p, maxs);
+                       }
+                       if (mins[0] > p2[0]) mins[0] = p2[0];if (maxs[0] < p2[0]) maxs[0] = p2[0];
+                       if (mins[1] > p2[1]) mins[1] = p2[1];if (maxs[1] < p2[1]) maxs[1] = p2[1];
+                       if (mins[2] > p2[2]) mins[2] = p2[2];if (maxs[2] < p2[2]) maxs[2] = p2[2];
                }
+               if (mins[0] >= clipmaxs[0] || maxs[0] <= clipmins[0]
+                || mins[1] >= clipmaxs[1] || maxs[1] <= clipmins[1]
+                || mins[2] >= clipmaxs[2] || maxs[2] <= clipmins[2]
+                || LightAndVis_CullBox(mins, maxs))
+                       return;
+               */
        }
+       #endif
+       Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
+       ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius);
 }
 
 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light);
@@ -823,7 +906,10 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                memset(&m, 0, sizeof(m));
                m.blendfunc1 = GL_ONE;
                m.blendfunc2 = GL_ONE;
+               if (r_shadow_realtime.integer >= 3)
+                       m.depthdisable = true;
                R_Mesh_State(&m);
+               qglDisable(GL_CULL_FACE);
                GL_Color(0.0 * r_colorscale, 0.0125 * r_colorscale, 0.1 * r_colorscale, 1);
        }
        else
@@ -844,41 +930,49 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
                        continue;
 
-               for (i = 0;i < wl->numleafs;i++)
-                       if (wl->leafs[i]->visframe == r_framecount)
-                               break;
-               if (i == wl->numleafs)
-                       continue;
-               leaf = wl->leafs[i];
-               VectorCopy(leaf->mins, clipmins);
-               VectorCopy(leaf->maxs, clipmaxs);
-               for (i = 0;i < wl->numleafs;i++)
+               if (cl.worldmodel != NULL)
                {
-                       leaf = wl->leafs[i];
-                       if (leaf->visframe == r_framecount)
+                       for (i = 0;i < wl->numleafs;i++)
+                               if (wl->leafs[i]->visframe == r_framecount)
+                                       break;
+                       if (i == wl->numleafs)
+                               continue;
+                       leaf = wl->leafs[i++];
+                       VectorCopy(leaf->mins, clipmins);
+                       VectorCopy(leaf->maxs, clipmaxs);
+                       for (i++;i < wl->numleafs;i++)
                        {
-                               if (clipmins[0] > leaf->mins[0]) clipmins[0] = leaf->mins[0];
-                               if (clipmaxs[0] < leaf->maxs[0]) clipmaxs[0] = leaf->maxs[0];
-                               if (clipmins[1] > leaf->mins[1]) clipmins[1] = leaf->mins[1];
-                               if (clipmaxs[1] < leaf->maxs[1]) clipmaxs[1] = leaf->maxs[1];
-                               if (clipmins[2] > leaf->mins[2]) clipmins[2] = leaf->mins[2];
-                               if (clipmaxs[2] < leaf->maxs[2]) clipmaxs[2] = leaf->maxs[2];
+                               leaf = wl->leafs[i];
+                               if (leaf->visframe == r_framecount)
+                               {
+                                       if (clipmins[0] > leaf->mins[0]) clipmins[0] = leaf->mins[0];
+                                       if (clipmaxs[0] < leaf->maxs[0]) clipmaxs[0] = leaf->maxs[0];
+                                       if (clipmins[1] > leaf->mins[1]) clipmins[1] = leaf->mins[1];
+                                       if (clipmaxs[1] < leaf->maxs[1]) clipmaxs[1] = leaf->maxs[1];
+                                       if (clipmins[2] > leaf->mins[2]) clipmins[2] = leaf->mins[2];
+                                       if (clipmaxs[2] < leaf->maxs[2]) clipmaxs[2] = leaf->maxs[2];
+                               }
                        }
+                       if (clipmins[0] < wl->mins[0]) clipmins[0] = wl->mins[0];
+                       if (clipmins[1] < wl->mins[1]) clipmins[1] = wl->mins[1];
+                       if (clipmins[2] < wl->mins[2]) clipmins[2] = wl->mins[2];
+                       if (clipmaxs[0] > wl->maxs[0]) clipmaxs[0] = wl->maxs[0];
+                       if (clipmaxs[1] > wl->maxs[1]) clipmaxs[1] = wl->maxs[1];
+                       if (clipmaxs[2] > wl->maxs[2]) clipmaxs[2] = wl->maxs[2];
+               }
+               else
+               {
+                       VectorCopy(wl->mins, clipmins);
+                       VectorCopy(wl->maxs, clipmaxs);
                }
-               if (clipmins[0] < wl->mins[0]) clipmins[0] = wl->mins[0];
-               if (clipmins[1] < wl->mins[1]) clipmins[1] = wl->mins[1];
-               if (clipmins[2] < wl->mins[2]) clipmins[2] = wl->mins[2];
-               if (clipmaxs[0] > wl->maxs[0]) clipmaxs[0] = wl->maxs[0];
-               if (clipmaxs[1] > wl->maxs[1]) clipmaxs[1] = wl->maxs[1];
-               if (clipmaxs[2] > wl->maxs[2]) clipmaxs[2] = wl->maxs[2];
 
                if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, wl->origin, wl->cullradius))
                        continue;
 
                // mark the leafs we care about so only things in those leafs will matter
-               for (i = 0;i < wl->numleafs;i++)
-                       wl->leafs[i]->worldnodeframe = shadowframecount;
-
+               if (cl.worldmodel != NULL)
+                       for (i = 0;i < wl->numleafs;i++)
+                               wl->leafs[i]->worldnodeframe = shadowframecount;
 
                f = d_lightstylevalue[wl->style] * (1.0f / 256.0f);
                VectorScale(wl->light, f, lightcolor);
@@ -890,22 +984,14 @@ void R_ShadowVolumeLighting (int visiblevolumes)
 
                if (!visiblevolumes)
                        R_Shadow_Stage_ShadowVolumes();
-               if (wl->shadowvolume && r_staticworldlights.integer)
-                       R_Shadow_DrawWorldLightShadowVolume(&cl_entities[0].render.matrix, wl);
+               ent = &cl_entities[0].render;
+               if (wl->shadowvolume && r_shadow_staticworldlights.integer)
+                       R_Shadow_DrawWorldLightShadowVolume(&ent->matrix, wl);
                else
-                       R_TestAndDrawShadowVolume(&cl_entities[0].render, wl->origin, cullradius, lightradius, clipmins, clipmaxs);
+                       R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs);
                if (r_drawentities.integer)
-               {
                        for (i = 0;i < r_refdef.numentities;i++)
-                       {
-                               ent = r_refdef.entities[i];
-                               if (ent->maxs[0] >= wl->mins[0] && ent->mins[0] <= wl->maxs[0]
-                                && ent->maxs[1] >= wl->mins[1] && ent->mins[1] <= wl->maxs[1]
-                                && ent->maxs[2] >= wl->mins[2] && ent->mins[2] <= wl->maxs[2]
-                                && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
-                                       R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, clipmins, clipmaxs);
-                       }
-               }
+                               R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs);
 
                if (!visiblevolumes)
                {
@@ -918,7 +1004,7 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                                if (wl->numsurfaces)
                                        R_Model_Brush_DrawLightForSurfaceList(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, wl->surfaces, wl->numsurfaces);
                                else
-                                       ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor);
+                                       ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor);
                        }
                        if (r_drawentities.integer)
                        {
@@ -933,27 +1019,7 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                                        {
                                                Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
                                                Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
-                                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor);
-                                       }
-                               }
-                       }
-
-                       if (R_Shadow_Stage_EraseShadowVolumes())
-                       {
-                               if (wl->shadowvolume && r_staticworldlights.integer)
-                                       R_Shadow_DrawWorldLightShadowVolume(&cl_entities[0].render.matrix, wl);
-                               else
-                                       R_TestAndDrawShadowVolume(&cl_entities[0].render, wl->origin, cullradius, lightradius, clipmins, clipmaxs);
-                               if (r_drawentities.integer)
-                               {
-                                       for (i = 0;i < r_refdef.numentities;i++)
-                                       {
-                                               ent = r_refdef.entities[i];
-                                               if (ent->maxs[0] >= wl->mins[0] && ent->mins[0] <= wl->maxs[0]
-                                                && ent->maxs[1] >= wl->mins[1] && ent->mins[1] <= wl->maxs[1]
-                                                && ent->maxs[2] >= wl->mins[2] && ent->mins[2] <= wl->maxs[2]
-                                                && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
-                                                       R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, clipmins, clipmaxs);
+                                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor);
                                        }
                                }
                        }
@@ -976,7 +1042,7 @@ void R_ShadowVolumeLighting (int visiblevolumes)
 
                if (!visiblevolumes)
                        R_Shadow_Stage_ShadowVolumes();
-               if (sl->shadowvolume && r_staticworldlights.integer)
+               if (sl->shadowvolume && r_shadow_staticworldlights.integer)
                        R_DrawWorldLightShadowVolume(&cl_entities[0].render.matrix, sl->shadowvolume);
                else
                        R_TestAndDrawShadowVolume(&cl_entities[0].render, sl->origin, cullradius, lightradius);
@@ -1020,24 +1086,6 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                                        }
                                }
                        }
-
-                       R_Shadow_Stage_EraseShadowVolumes();
-                       if (sl->shadowvolume && r_staticworldlights.integer)
-                               R_DrawWorldLightShadowVolume(&cl_entities[0].render.matrix, sl->shadowvolume);
-                       else
-                               R_TestAndDrawShadowVolume(&cl_entities[0].render, sl->origin, cullradius, lightradius);
-                       if (r_drawentities.integer)
-                       {
-                               for (i = 0;i < r_refdef.numentities;i++)
-                               {
-                                       ent = r_refdef.entities[i];
-                                       if (ent->maxs[0] >= sl->mins[0] && ent->mins[0] <= sl->maxs[0]
-                                       && ent->maxs[1] >= sl->mins[1] && ent->mins[1] <= sl->maxs[1]
-                                       && ent->maxs[2] >= sl->mins[2] && ent->mins[2] <= sl->maxs[2]
-                                       && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
-                                               R_TestAndDrawShadowVolume(r_refdef.entities[i], sl->origin, cullradius, lightradius);
-                               }
-                       }
                }
        }
        */
@@ -1061,14 +1109,15 @@ void R_ShadowVolumeLighting (int visiblevolumes)
 
                if (!visiblevolumes)
                        R_Shadow_Stage_ShadowVolumes();
-               R_TestAndDrawShadowVolume(&cl_entities[0].render, rd->origin, cullradius, lightradius, clipmins, clipmaxs);
+               ent = &cl_entities[0].render;
+               R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs);
                if (r_drawentities.integer)
                {
                        for (i = 0;i < r_refdef.numentities;i++)
                        {
                                ent = r_refdef.entities[i];
-                               if (ent != rd->ent && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
-                                       R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs);
+                               if (ent != rd->ent)
+                                       R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs);
                        }
                }
 
@@ -1080,7 +1129,7 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                        {
                                Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
                                Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
-                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor);
+                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor);
                        }
                        if (r_drawentities.integer)
                        {
@@ -1092,21 +1141,7 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                                        {
                                                Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
                                                Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
-                                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor);
-                                       }
-                               }
-                       }
-
-                       if (R_Shadow_Stage_EraseShadowVolumes())
-                       {
-                               R_TestAndDrawShadowVolume(&cl_entities[0].render, rd->origin, cullradius, lightradius, clipmins, clipmaxs);
-                               if (r_drawentities.integer)
-                               {
-                                       for (i = 0;i < r_refdef.numentities;i++)
-                                       {
-                                               ent = r_refdef.entities[i];
-                                               if (ent != rd->ent && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
-                                                       R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs);
+                                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor);
                                        }
                                }
                        }
@@ -1115,31 +1150,35 @@ void R_ShadowVolumeLighting (int visiblevolumes)
 
        if (!visiblevolumes)
                R_Shadow_Stage_End();
+       qglEnable(GL_CULL_FACE);
        qglDisable(GL_SCISSOR_TEST);
 }
 
 static void R_SetFrustum (void)
 {
-       int i;
-
        // LordHavoc: note to all quake engine coders, the special case for 90
        // degrees assumed a square view (wrong), so I removed it, Quake2 has it
        // disabled as well.
+
        // rotate VPN right by FOV_X/2 degrees
        RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
+       frustum[0].dist = DotProduct (r_origin, frustum[0].normal);
+       PlaneClassify(&frustum[0]);
+
        // rotate VPN left by FOV_X/2 degrees
        RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
+       frustum[1].dist = DotProduct (r_origin, frustum[1].normal);
+       PlaneClassify(&frustum[1]);
+
        // rotate VPN up by FOV_X/2 degrees
        RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
+       frustum[2].dist = DotProduct (r_origin, frustum[2].normal);
+       PlaneClassify(&frustum[2]);
+
        // rotate VPN down by FOV_X/2 degrees
        RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
-
-       for (i = 0;i < 4;i++)
-       {
-               frustum[i].type = PLANE_ANYZ;
-               frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
-               PlaneClassify(&frustum[i]);
-       }
+       frustum[3].dist = DotProduct (r_origin, frustum[3].normal);
+       PlaneClassify(&frustum[3]);
 }
 
 /*
@@ -1226,7 +1265,7 @@ void R_RenderView (void)
                }
                else if (!gl_stencil)
                {
-                       Con_Printf("Stencil not enabled, turning off r_shadow_realtime, please type vid_stencil 1;vid_restart and try again\n");
+                       Con_Printf("Stencil not enabled, turning off r_shadow_realtime, please type vid_stencil 1;vid_bitsperpixel 32;vid_restart and try again\n");
                        Cvar_SetValueQuick(&r_shadow_realtime, 0);
                }
                else if (!gl_combine.integer)
@@ -1271,8 +1310,7 @@ void R_RenderView (void)
        R_Mesh_Start();
        R_MeshQueue_BeginScene();
 
-       if (r_shadow_lightingmode)
-               R_Shadow_UpdateWorldLightSelection();
+       R_Shadow_UpdateWorldLightSelection();
 
        if (R_DrawBrushModelsSky())
                R_TimeReport("bmodelsky");
@@ -1288,7 +1326,7 @@ void R_RenderView (void)
        R_DrawModels(r_shadow_lightingmode > 0);
        R_TimeReport("models");
 
-       if (r_shadows.integer == 1)
+       if (r_shadows.integer == 1 && r_shadow_lightingmode <= 0)
        {
                R_DrawFakeShadows();
                R_TimeReport("fakeshadow");
@@ -1320,7 +1358,7 @@ void R_RenderView (void)
 
        R_MeshQueue_Render();
        R_MeshQueue_EndScene();
-       if (r_shadow_realtime.integer == 2)
+       if (r_shadow_realtime.integer >= 2)
        {
                R_ShadowVolumeLighting(true);
                R_TimeReport("shadowvolume");
@@ -1445,7 +1483,7 @@ void R_DrawNoModel(entity_render_t *ent)
        //      R_DrawNoModelCallback(ent, 0);
 }
 
-void R_CalcBeamVerts (float *vert, vec3_t org1, vec3_t org2, float width)
+void R_CalcBeamVerts (float *vert, const vec3_t org1, const vec3_t org2, float width)
 {
        vec3_t right1, right2, diff, normal;