lights now have an orientation (this isn't editable yet, and is infact not really...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Fri, 28 Feb 2003 11:28:10 +0000 (11:28 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Fri, 28 Feb 2003 11:28:10 +0000 (11:28 +0000)
lights now use bbox culling instead of radius (because they aren't round in 2D texture mode)
fixed LOTS of light culling bugs (particularly with surface selection)
fixed scissor to be more efficient (smaller) when easily done (entirely infront of view) and fixed some bugs
got rid of ShadowSphere code in gl_rmain.c (it was not used)
added back RadiusFromBounds (and optimized it) and added RadiusFromBoundsAndOrigin
removed trailing whitespace in mathlib.c
added BoxesOverlap macro to mathlib.h
fixed a portal-flow bug when a light lies directly inside a portal polygon (now checks both leafs involved, very mild search tolerance for leafs around the light)
added back 3d attenuation texture (true spherical lights make a return, r_shadow_texture3d cvar controls this)
fixed light-bleeding in attenuation textures at the edges (fixed a bug in the biasing during texture generation, now the edge is always black as it should be)
realtime lighting texture generation (attenuation/normalizationcubemap) now has some macros for more easily adjusting texture resolutions
reduced resolution of attenuation and normalization textures
added a bunch more rendering paths for diffuse and specular lighting, to reduce number of passes in a few cases (and allow use of 3D attenuation texture)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@2793 d7cf8633-e32d-0410-b094-e92efae38249

gl_models.c
gl_rmain.c
gl_rsurf.c
mathlib.c
mathlib.h
model_alias.c
model_brush.c
model_shared.h
portals.c
r_shadow.c
r_shadow.h

index 128214a..4a703a2 100644 (file)
@@ -416,7 +416,7 @@ void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightor
        }
 }
 
-void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor)
+void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz)
 {
        int c, meshnum, layernum;
        float fog, ifog, lightcolor2[3];
@@ -468,7 +468,7 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v
                        if (layer->flags & ALIASLAYER_SPECULAR)
                        {
                                c_alias_polys += mesh->num_triangles;
-                               R_Shadow_SpecularLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_elements, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, mesh->data_texcoords, relativelightorigin, relativeeyeorigin, lightradius, lightcolor2, layer->texture, layer->nmap, NULL);
+                               R_Shadow_SpecularLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_elements, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, mesh->data_texcoords, relativelightorigin, relativeeyeorigin, lightradius, lightcolor2, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, NULL);
                        }
                        else if (layer->flags & ALIASLAYER_DIFFUSE)
                        {
@@ -497,7 +497,7 @@ void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v
                                        lightcolor2[2] *= bcolor[2] * (1.0f / 255.0f);
                                }
                                c_alias_polys += mesh->num_triangles;
-                               R_Shadow_DiffuseLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_elements, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, mesh->data_texcoords, relativelightorigin, lightradius, lightcolor2, layer->texture, layer->nmap, NULL);
+                               R_Shadow_DiffuseLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_elements, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, mesh->data_texcoords, relativelightorigin, lightradius, lightcolor2, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, NULL);
                        }
                }
        }
index 448d405..1e751c9 100644 (file)
@@ -754,7 +754,7 @@ void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float c
        vec3_t relativelightorigin;
        #if 0
        int i;
-       vec3_t p, p2, temp, relativelightorigin/*, mins, maxs*/;
+       vec3_t temp;
        float dist, projectdistance;
        float points[16][3];
        #endif
@@ -825,69 +825,7 @@ void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float c
 
 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light);
 
-#define SHADOWSPHERE_SEGMENTS 16
-
-shadowmesh_t *shadowsphere;
-void R_CreateShadowSphere(void)
-{
-       int i, j;
-       vec3_t angles, angles2, angles3, angles4;
-       float verts[12];
-       shadowsphere = Mod_ShadowMesh_Begin(zonemempool, SHADOWSPHERE_SEGMENTS * SHADOWSPHERE_SEGMENTS / 2);
-       for (i = 0;i < SHADOWSPHERE_SEGMENTS / 2;i++)
-       {
-               for (j = 0;j < SHADOWSPHERE_SEGMENTS;j++)
-               {
-                       angles[0] = (i * 360.0f / SHADOWSPHERE_SEGMENTS) + 90.0f;
-                       angles[1] = j * 360.0f / SHADOWSPHERE_SEGMENTS;
-                       angles[2] = 0;
-                       VectorCopy(angles, angles2);
-                       VectorCopy(angles, angles3);
-                       VectorCopy(angles, angles4);
-                       angles2[1] += 360.0f / SHADOWSPHERE_SEGMENTS;
-                       angles3[0] += 360.0f / SHADOWSPHERE_SEGMENTS;
-                       angles3[1] += 360.0f / SHADOWSPHERE_SEGMENTS;
-                       angles4[0] += 360.0f / SHADOWSPHERE_SEGMENTS;
-                       AngleVectorsFLU(angles, verts, NULL, NULL);
-                       AngleVectorsFLU(angles2, verts + 9, NULL, NULL);
-                       AngleVectorsFLU(angles3, verts + 6, NULL, NULL);
-                       AngleVectorsFLU(angles4, verts + 3, NULL, NULL);
-                       VectorScale(&verts[0], 1.0f, &verts[0]);
-                       VectorScale(&verts[3], 1.0f, &verts[3]);
-                       VectorScale(&verts[6], 1.0f, &verts[6]);
-                       VectorScale(&verts[9], 1.0f, &verts[9]);
-                       Mod_ShadowMesh_AddPolygon(zonemempool, shadowsphere, 4, verts);
-               }
-       }
-       shadowsphere = Mod_ShadowMesh_Finish(zonemempool, shadowsphere);
-}
-
-
-void R_DrawShadowSphere(vec3_t origin, float cullradius, float lightradius)
-{
-       shadowmesh_t *mesh;
-       matrix4x4_t matrix;
-       if (!shadowsphere)
-               R_CreateShadowSphere();
-       Matrix4x4_CreateScale(&matrix, lightradius);
-       Matrix4x4_ConcatTranslate(&matrix, origin[0], origin[1], origin[2]);
-       R_Mesh_Matrix(&matrix);
-       for (mesh = shadowsphere;mesh;mesh = mesh->next)
-       {
-               memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
-               R_Shadow_RenderVolume(mesh->numverts, mesh->numtriangles, mesh->elements);
-       }
-       Matrix4x4_CreateScale(&matrix, -cullradius);
-       Matrix4x4_ConcatTranslate(&matrix, origin[0], origin[1], origin[2]);
-       R_Mesh_Matrix(&matrix);
-       for (mesh = shadowsphere;mesh;mesh = mesh->next)
-       {
-               memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
-               R_Shadow_RenderVolume(mesh->numverts, mesh->numtriangles, mesh->elements);
-       }
-}
-
-extern void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces);
+extern void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
 void R_ShadowVolumeLighting (int visiblevolumes)
 {
        int i;
@@ -896,10 +834,12 @@ void R_ShadowVolumeLighting (int visiblevolumes)
        float f, lightradius, cullradius;
        vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs;
        worldlight_t *wl;
-       //mlight_t *sl;
        rdlight_t *rd;
        rmeshstate_t m;
        mleaf_t *leaf;
+       matrix4x4_t matrix;
+       matrix4x4_t matrix_worldtofilter, matrix_worldtoattenuationxyz, matrix_worldtoattenuationz;
+       matrix4x4_t matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
 
        if (visiblevolumes)
        {
@@ -919,9 +859,8 @@ void R_ShadowVolumeLighting (int visiblevolumes)
        {
                if (d_lightstylevalue[wl->style] <= 0)
                        continue;
-               cullradius = wl->cullradius;
-               lightradius = wl->lightradius;
-               if (R_CullSphere(wl->origin, lightradius))
+               if (R_CullBox(wl->mins, wl->maxs))
+               //if (R_CullSphere(wl->origin, cullradius))
                        continue;
                //if (R_CullBox(wl->mins, wl->maxs) || R_CullSphere(wl->origin, lightradius))
                //      continue;
@@ -930,6 +869,9 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
                        continue;
 
+               cullradius = wl->cullradius;
+               lightradius = wl->lightradius;
+
                if (cl.worldmodel != NULL)
                {
                        for (i = 0;i < wl->numleafs;i++)
@@ -940,7 +882,7 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                        leaf = wl->leafs[i++];
                        VectorCopy(leaf->mins, clipmins);
                        VectorCopy(leaf->maxs, clipmaxs);
-                       for (i++;i < wl->numleafs;i++)
+                       for (;i < wl->numleafs;i++)
                        {
                                leaf = wl->leafs[i];
                                if (leaf->visframe == r_framecount)
@@ -954,10 +896,10 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                                }
                        }
                        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 (clipmins[1] < wl->mins[1]) clipmins[1] = wl->mins[1];
                        if (clipmaxs[1] > wl->maxs[1]) clipmaxs[1] = wl->maxs[1];
+                       if (clipmins[2] < wl->mins[2]) clipmins[2] = wl->mins[2];
                        if (clipmaxs[2] > wl->maxs[2]) clipmaxs[2] = wl->maxs[2];
                }
                else
@@ -966,7 +908,8 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                        VectorCopy(wl->maxs, clipmaxs);
                }
 
-               if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, wl->origin, wl->cullradius))
+               //if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, wl->origin, wl->cullradius))
+               if (R_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
                        continue;
 
                // mark the leafs we care about so only things in those leafs will matter
@@ -1002,15 +945,32 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                                R_Shadow_Stage_LightWithShadows();
                        else
                                R_Shadow_Stage_LightWithoutShadows();
+
+                       // calculate world to filter matrix
+                       Matrix4x4_CreateFromQuakeEntity(&matrix, wl->origin[0], wl->origin[1], wl->origin[2], wl->angles[0], wl->angles[1], wl->angles[2], lightradius);
+                       Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
+                       // calculate world to attenuationxyz/xy matrix
+                       Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
+                       Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
+                       // calculate world to attenuationz matrix
+                       matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
+                       matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0  ;matrix.m[1][3] = 0.5;
+                       matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0  ;matrix.m[2][3] = 0.5;
+                       matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0  ;matrix.m[3][3] = 1;
+                       Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
+
                        ent = &cl_entities[0].render;
                        if (ent->model && ent->model->DrawLight)
                        {
                                Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
                                Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
+                               Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
+                               Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
+                               Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
                                if (wl->numsurfaces)
-                                       R_Model_Brush_DrawLightForSurfaceList(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, wl->surfaces, wl->numsurfaces);
+                                       R_Model_Brush_DrawLightForSurfaceList(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, wl->surfaces, wl->numsurfaces, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
                                else
-                                       ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor);
+                                       ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
                        }
                        if (r_drawentities.integer)
                        {
@@ -1018,103 +978,44 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                                {
                                        ent = r_refdef.entities[i];
                                        if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
-                                        && 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->maxs[0] >= clipmins[0] && ent->mins[0] <= clipmaxs[0]
+                                        && ent->maxs[1] >= clipmins[1] && ent->mins[1] <= clipmaxs[1]
+                                        && ent->maxs[2] >= clipmins[2] && ent->mins[2] <= clipmaxs[2]
                                         && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
                                        {
                                                Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
                                                Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
-                                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor);
+                                               Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
+                                               Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
+                                               Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
+                                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
                                        }
                                }
                        }
                }
        }
-       /*
-       for (lnum = 0, sl = cl.worldmodel->lights;lnum < cl.worldmodel->numlights;lnum++, sl++)
-       {
-               if (d_lightstylevalue[sl->style] <= 0)
-                       continue;
-               if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
-                       continue;
-               cullradius = sl->cullradius;
-               lightradius = sl->lightradius;
-               if (VIS_CullBox(sl->mins, sl->maxs) || VIS_CullSphere(sl->origin, lightradius))
-                       continue;
-
-               f = d_lightstylevalue[sl->style] * (1.0f / 32768.0f);
-               VectorScale(sl->light, f, lightcolor);
-
-               if (!visiblevolumes)
-                       R_Shadow_Stage_ShadowVolumes();
-               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);
-               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);
-                       }
-               }
-
-               if (!visiblevolumes)
-               {
-                       R_Shadow_Stage_Light();
-                       ent = &cl_entities[0].render;
-                       if (ent->model && ent->model->DrawLight)
-                       {
-                               Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin);
-                               Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
-                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, sl->distbias, sl->subtract, lightcolor);
-                       }
-                       if (r_drawentities.integer)
-                       {
-                               for (i = 0;i < r_refdef.numentities;i++)
-                               {
-                                       ent = r_refdef.entities[i];
-                                       if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
-                                        && 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)
-                                       {
-                                               Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin);
-                                               Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
-                                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, sl->distbias, sl->subtract, lightcolor);
-                                       }
-                               }
-                       }
-               }
-       }
-       */
        for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
        {
-               cullradius = rd->cullradius;
                lightradius = rd->cullradius;
-               if (VIS_CullSphere(rd->origin, lightradius))
+               clipmins[0] = rd->origin[0] - lightradius;
+               clipmins[1] = rd->origin[1] - lightradius;
+               clipmins[2] = rd->origin[2] - lightradius;
+               clipmaxs[0] = rd->origin[0] + lightradius;
+               clipmaxs[1] = rd->origin[1] + lightradius;
+               clipmaxs[2] = rd->origin[2] + lightradius;
+               if (VIS_CullBox(clipmins, clipmaxs))
                        continue;
 
-               VectorScale(rd->light, (1.0f / 8192.0f), lightcolor);
-               clipmins[0] = rd->origin[0] - cullradius;
-               clipmins[1] = rd->origin[1] - cullradius;
-               clipmins[2] = rd->origin[2] - cullradius;
-               clipmaxs[0] = rd->origin[0] + cullradius;
-               clipmaxs[1] = rd->origin[1] + cullradius;
-               clipmaxs[2] = rd->origin[2] + cullradius;
-
-               if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, rd->origin, rd->cullradius))
+               //if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, rd->origin, cullradius))
+               if (R_Shadow_ScissorForBBox(clipmins, clipmaxs))
                        continue;
 
                if (!visiblevolumes)
                        R_Shadow_Stage_ShadowVolumes();
+
+               cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin);
+               VectorScale(rd->light, (1.0f / 4096.0f), lightcolor);
+
                ent = &cl_entities[0].render;
                R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs);
                if (r_drawentities.integer)
@@ -1130,12 +1031,29 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                if (!visiblevolumes)
                {
                        R_Shadow_Stage_LightWithShadows();
+
+                       // calculate world to filter matrix
+                       Matrix4x4_CreateFromQuakeEntity(&matrix, rd->origin[0], rd->origin[1], rd->origin[2], 0, 0, 0, lightradius);
+                       Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
+                       // calculate world to attenuationxyz/xy matrix
+                       Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
+                       Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
+                       // calculate world to attenuationz matrix
+                       matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
+                       matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0  ;matrix.m[1][3] = 0.5;
+                       matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0  ;matrix.m[2][3] = 0.5;
+                       matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0  ;matrix.m[3][3] = 1;
+                       Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
+
                        ent = &cl_entities[0].render;
                        if (ent->model && ent->model->DrawLight)
                        {
                                Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
                                Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
-                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor);
+                               Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
+                               Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
+                               Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
+                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
                        }
                        if (r_drawentities.integer)
                        {
@@ -1143,11 +1061,17 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                                {
                                        ent = r_refdef.entities[i];
                                        if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
+                                        && ent->maxs[0] >= clipmins[0] && ent->mins[0] <= clipmaxs[0]
+                                        && ent->maxs[1] >= clipmins[1] && ent->mins[1] <= clipmaxs[1]
+                                        && ent->maxs[2] >= clipmins[2] && ent->mins[2] <= clipmaxs[2]
                                         && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
                                        {
                                                Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
                                                Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
-                                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor);
+                                               Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
+                                               Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
+                                               Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
+                                               ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
                                        }
                                }
                        }
index 5931325..4c16a11 100644 (file)
@@ -1845,7 +1845,7 @@ void R_Model_Brush_DrawShadowVolume (entity_render_t *ent, vec3_t relativelighto
        }
 }
 
-void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces)
+void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz)
 {
        int surfnum;
        msurface_t *surf;
@@ -1867,35 +1867,37 @@ void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relative
                                {
                                        R_Mesh_ResizeCheck(mesh->numverts);
                                        memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
-                                       R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, lightradius, lightcolor, t->skin.base, t->skin.nmap, NULL);
-                                       R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, t->skin.gloss, t->skin.nmap, NULL);
+                                       R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, NULL);
+                                       R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.gloss, t->skin.nmap, NULL);
                                }
                        }
                }
        }
 }
 
-void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor)
+void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz)
 {
        int surfnum;
        msurface_t *surf;
        texture_t *t;
-       float f, lightradius2, temp[3];
+       float f, lightmins[3], lightmaxs[3];
        surfmesh_t *mesh;
        if (ent->model == NULL)
                return;
        R_Mesh_Matrix(&ent->matrix);
-       lightradius2 = lightradius * lightradius;
+       lightmins[0] = relativelightorigin[0] - lightradius;
+       lightmins[1] = relativelightorigin[1] - lightradius;
+       lightmins[2] = relativelightorigin[2] - lightradius;
+       lightmaxs[0] = relativelightorigin[0] + lightradius;
+       lightmaxs[1] = relativelightorigin[1] + lightradius;
+       lightmaxs[2] = relativelightorigin[2] + lightradius;
        R_UpdateTextureInfo(ent);
        if (ent != &cl_entities[0].render)
        {
                // bmodel, cull crudely to view and light
                for (surfnum = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;surfnum < ent->model->nummodelsurfaces;surfnum++, surf++)
                {
-                       temp[0] = bound(surf->poly_mins[0], relativelightorigin[0], surf->poly_maxs[0]) - relativelightorigin[0];
-                       temp[1] = bound(surf->poly_mins[1], relativelightorigin[1], surf->poly_maxs[1]) - relativelightorigin[1];
-                       temp[2] = bound(surf->poly_mins[2], relativelightorigin[2], surf->poly_maxs[2]) - relativelightorigin[2];
-                       if (DotProduct(temp, temp) < lightradius2)
+                       if (BoxesOverlap(surf->poly_mins, surf->poly_maxs, lightmins, lightmaxs))
                        {
                                f = PlaneDiff(relativelightorigin, surf->plane);
                                if (surf->flags & SURF_PLANEBACK)
@@ -1914,8 +1916,8 @@ void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v
                                                        {
                                                                R_Mesh_ResizeCheck(mesh->numverts);
                                                                memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
-                                                               R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, lightradius, lightcolor, t->skin.base, t->skin.nmap, NULL);
-                                                               R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, t->skin.gloss, t->skin.nmap, NULL);
+                                                               R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, NULL);
+                                                               R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.gloss, t->skin.nmap, NULL);
                                                        }
                                                }
                                        }
@@ -1928,28 +1930,22 @@ void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, v
                // world, already culled to view, just cull to light
                for (surfnum = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;surfnum < ent->model->nummodelsurfaces;surfnum++, surf++)
                {
-                       if (surf->visframe == r_framecount)
+                       if (surf->visframe == r_framecount && BoxesOverlap(surf->poly_mins, surf->poly_maxs, lightmins, lightmaxs))
                        {
-                               temp[0] = bound(surf->poly_mins[0], relativelightorigin[0], surf->poly_maxs[0]) - relativelightorigin[0];
-                               temp[1] = bound(surf->poly_mins[1], relativelightorigin[1], surf->poly_maxs[1]) - relativelightorigin[1];
-                               temp[2] = bound(surf->poly_mins[2], relativelightorigin[2], surf->poly_maxs[2]) - relativelightorigin[2];
-                               if (DotProduct(temp, temp) < lightradius2)
+                               f = PlaneDiff(relativelightorigin, surf->plane);
+                               if (surf->flags & SURF_PLANEBACK)
+                                       f = -f;
+                               if (f >= -0.1 && f < lightradius)
                                {
-                                       f = PlaneDiff(relativelightorigin, surf->plane);
-                                       if (surf->flags & SURF_PLANEBACK)
-                                               f = -f;
-                                       if (f >= -0.1 && f < lightradius)
+                                       t = surf->texinfo->texture->currentframe;
+                                       if (t->rendertype == SURFRENDER_OPAQUE && t->flags & SURF_SHADOWLIGHT)
                                        {
-                                               t = surf->texinfo->texture->currentframe;
-                                               if (t->rendertype == SURFRENDER_OPAQUE && t->flags & SURF_SHADOWLIGHT)
+                                               for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                                                {
-                                                       for (mesh = surf->mesh;mesh;mesh = mesh->chain)
-                                                       {
-                                                               R_Mesh_ResizeCheck(mesh->numverts);
-                                                               memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
-                                                               R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, lightradius, lightcolor, t->skin.base, t->skin.nmap, NULL);
-                                                               R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, t->skin.gloss, t->skin.nmap, NULL);
-                                                       }
+                                                       R_Mesh_ResizeCheck(mesh->numverts);
+                                                       memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
+                                                       R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, NULL);
+                                                       R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.gloss, t->skin.nmap, NULL);
                                                }
                                        }
                                }
index 4dea77d..a55ab9d 100644 (file)
--- a/mathlib.c
+++ b/mathlib.c
@@ -29,66 +29,66 @@ float ixtable[4096];
 
 float m_bytenormals[NUMVERTEXNORMALS][3] =
 {
-{-0.525731, 0.000000, 0.850651}, {-0.442863, 0.238856, 0.864188}, 
-{-0.295242, 0.000000, 0.955423}, {-0.309017, 0.500000, 0.809017}, 
+{-0.525731, 0.000000, 0.850651}, {-0.442863, 0.238856, 0.864188},
+{-0.295242, 0.000000, 0.955423}, {-0.309017, 0.500000, 0.809017},
 {-0.162460, 0.262866, 0.951056}, {0.000000, 0.000000, 1.000000},
-{0.000000, 0.850651, 0.525731}, {-0.147621, 0.716567, 0.681718}, 
-{0.147621, 0.716567, 0.681718}, {0.000000, 0.525731, 0.850651}, 
-{0.309017, 0.500000, 0.809017}, {0.525731, 0.000000, 0.850651}, 
-{0.295242, 0.000000, 0.955423}, {0.442863, 0.238856, 0.864188}, 
-{0.162460, 0.262866, 0.951056}, {-0.681718, 0.147621, 0.716567}, 
-{-0.809017, 0.309017, 0.500000}, {-0.587785, 0.425325, 0.688191}, 
+{0.000000, 0.850651, 0.525731}, {-0.147621, 0.716567, 0.681718},
+{0.147621, 0.716567, 0.681718}, {0.000000, 0.525731, 0.850651},
+{0.309017, 0.500000, 0.809017}, {0.525731, 0.000000, 0.850651},
+{0.295242, 0.000000, 0.955423}, {0.442863, 0.238856, 0.864188},
+{0.162460, 0.262866, 0.951056}, {-0.681718, 0.147621, 0.716567},
+{-0.809017, 0.309017, 0.500000}, {-0.587785, 0.425325, 0.688191},
 {-0.850651, 0.525731, 0.000000}, {-0.864188, 0.442863, 0.238856},
-{-0.716567, 0.681718, 0.147621}, {-0.688191, 0.587785, 0.425325}, 
-{-0.500000, 0.809017, 0.309017}, {-0.238856, 0.864188, 0.442863}, 
-{-0.425325, 0.688191, 0.587785}, {-0.716567, 0.681718, -0.147621}, 
-{-0.500000, 0.809017, -0.309017}, {-0.525731, 0.850651, 0.000000}, 
+{-0.716567, 0.681718, 0.147621}, {-0.688191, 0.587785, 0.425325},
+{-0.500000, 0.809017, 0.309017}, {-0.238856, 0.864188, 0.442863},
+{-0.425325, 0.688191, 0.587785}, {-0.716567, 0.681718, -0.147621},
+{-0.500000, 0.809017, -0.309017}, {-0.525731, 0.850651, 0.000000},
 {0.000000, 0.850651, -0.525731}, {-0.238856, 0.864188, -0.442863},
-{0.000000, 0.955423, -0.295242}, {-0.262866, 0.951056, -0.162460}, 
+{0.000000, 0.955423, -0.295242}, {-0.262866, 0.951056, -0.162460},
 {0.000000, 1.000000, 0.000000}, {0.000000, 0.955423, 0.295242},
-{-0.262866, 0.951056, 0.162460}, {0.238856, 0.864188, 0.442863}, 
-{0.262866, 0.951056, 0.162460}, {0.500000, 0.809017, 0.309017}, 
-{0.238856, 0.864188, -0.442863}, {0.262866, 0.951056, -0.162460}, 
-{0.500000, 0.809017, -0.309017}, {0.850651, 0.525731, 0.000000}, 
-{0.716567, 0.681718, 0.147621}, {0.716567, 0.681718, -0.147621}, 
-{0.525731, 0.850651, 0.000000}, {0.425325, 0.688191, 0.587785}, 
-{0.864188, 0.442863, 0.238856}, {0.688191, 0.587785, 0.425325}, 
+{-0.262866, 0.951056, 0.162460}, {0.238856, 0.864188, 0.442863},
+{0.262866, 0.951056, 0.162460}, {0.500000, 0.809017, 0.309017},
+{0.238856, 0.864188, -0.442863}, {0.262866, 0.951056, -0.162460},
+{0.500000, 0.809017, -0.309017}, {0.850651, 0.525731, 0.000000},
+{0.716567, 0.681718, 0.147621}, {0.716567, 0.681718, -0.147621},
+{0.525731, 0.850651, 0.000000}, {0.425325, 0.688191, 0.587785},
+{0.864188, 0.442863, 0.238856}, {0.688191, 0.587785, 0.425325},
 {0.809017, 0.309017, 0.500000}, {0.681718, 0.147621, 0.716567},
-{0.587785, 0.425325, 0.688191}, {0.955423, 0.295242, 0.000000}, 
+{0.587785, 0.425325, 0.688191}, {0.955423, 0.295242, 0.000000},
 {1.000000, 0.000000, 0.000000}, {0.951056, 0.162460, 0.262866},
-{0.850651, -0.525731, 0.000000}, {0.955423, -0.295242, 0.000000}, 
-{0.864188, -0.442863, 0.238856}, {0.951056, -0.162460, 0.262866}, 
+{0.850651, -0.525731, 0.000000}, {0.955423, -0.295242, 0.000000},
+{0.864188, -0.442863, 0.238856}, {0.951056, -0.162460, 0.262866},
 {0.809017, -0.309017, 0.500000}, {0.681718, -0.147621, 0.716567},
 {0.850651, 0.000000, 0.525731}, {0.864188, 0.442863, -0.238856},
-{0.809017, 0.309017, -0.500000}, {0.951056, 0.162460, -0.262866}, 
-{0.525731, 0.000000, -0.850651}, {0.681718, 0.147621, -0.716567}, 
+{0.809017, 0.309017, -0.500000}, {0.951056, 0.162460, -0.262866},
+{0.525731, 0.000000, -0.850651}, {0.681718, 0.147621, -0.716567},
 {0.681718, -0.147621, -0.716567}, {0.850651, 0.000000, -0.525731},
-{0.809017, -0.309017, -0.500000}, {0.864188, -0.442863, -0.238856}, 
+{0.809017, -0.309017, -0.500000}, {0.864188, -0.442863, -0.238856},
 {0.951056, -0.162460, -0.262866}, {0.147621, 0.716567, -0.681718},
-{0.309017, 0.500000, -0.809017}, {0.425325, 0.688191, -0.587785}, 
-{0.442863, 0.238856, -0.864188}, {0.587785, 0.425325, -0.688191}, 
-{0.688191, 0.587785, -0.425325}, {-0.147621, 0.716567, -0.681718}, 
+{0.309017, 0.500000, -0.809017}, {0.425325, 0.688191, -0.587785},
+{0.442863, 0.238856, -0.864188}, {0.587785, 0.425325, -0.688191},
+{0.688191, 0.587785, -0.425325}, {-0.147621, 0.716567, -0.681718},
 {-0.309017, 0.500000, -0.809017}, {0.000000, 0.525731, -0.850651},
 {-0.525731, 0.000000, -0.850651}, {-0.442863, 0.238856, -0.864188},
-{-0.295242, 0.000000, -0.955423}, {-0.162460, 0.262866, -0.951056}, 
-{0.000000, 0.000000, -1.000000}, {0.295242, 0.000000, -0.955423}, 
-{0.162460, 0.262866, -0.951056}, {-0.442863, -0.238856, -0.864188}, 
-{-0.309017, -0.500000, -0.809017}, {-0.162460, -0.262866, -0.951056}, 
-{0.000000, -0.850651, -0.525731}, {-0.147621, -0.716567, -0.681718}, 
-{0.147621, -0.716567, -0.681718}, {0.000000, -0.525731, -0.850651}, 
-{0.309017, -0.500000, -0.809017}, {0.442863, -0.238856, -0.864188}, 
-{0.162460, -0.262866, -0.951056}, {0.238856, -0.864188, -0.442863}, 
-{0.500000, -0.809017, -0.309017}, {0.425325, -0.688191, -0.587785}, 
-{0.716567, -0.681718, -0.147621}, {0.688191, -0.587785, -0.425325}, 
+{-0.295242, 0.000000, -0.955423}, {-0.162460, 0.262866, -0.951056},
+{0.000000, 0.000000, -1.000000}, {0.295242, 0.000000, -0.955423},
+{0.162460, 0.262866, -0.951056}, {-0.442863, -0.238856, -0.864188},
+{-0.309017, -0.500000, -0.809017}, {-0.162460, -0.262866, -0.951056},
+{0.000000, -0.850651, -0.525731}, {-0.147621, -0.716567, -0.681718},
+{0.147621, -0.716567, -0.681718}, {0.000000, -0.525731, -0.850651},
+{0.309017, -0.500000, -0.809017}, {0.442863, -0.238856, -0.864188},
+{0.162460, -0.262866, -0.951056}, {0.238856, -0.864188, -0.442863},
+{0.500000, -0.809017, -0.309017}, {0.425325, -0.688191, -0.587785},
+{0.716567, -0.681718, -0.147621}, {0.688191, -0.587785, -0.425325},
 {0.587785, -0.425325, -0.688191}, {0.000000, -0.955423, -0.295242},
-{0.000000, -1.000000, 0.000000}, {0.262866, -0.951056, -0.162460}, 
-{0.000000, -0.850651, 0.525731}, {0.000000, -0.955423, 0.295242}, 
-{0.238856, -0.864188, 0.442863}, {0.262866, -0.951056, 0.162460}, 
-{0.500000, -0.809017, 0.309017}, {0.716567, -0.681718, 0.147621}, 
-{0.525731, -0.850651, 0.000000}, {-0.238856, -0.864188, -0.442863}, 
-{-0.500000, -0.809017, -0.309017}, {-0.262866, -0.951056, -0.162460}, 
+{0.000000, -1.000000, 0.000000}, {0.262866, -0.951056, -0.162460},
+{0.000000, -0.850651, 0.525731}, {0.000000, -0.955423, 0.295242},
+{0.238856, -0.864188, 0.442863}, {0.262866, -0.951056, 0.162460},
+{0.500000, -0.809017, 0.309017}, {0.716567, -0.681718, 0.147621},
+{0.525731, -0.850651, 0.000000}, {-0.238856, -0.864188, -0.442863},
+{-0.500000, -0.809017, -0.309017}, {-0.262866, -0.951056, -0.162460},
 {-0.850651, -0.525731, 0.000000}, {-0.716567, -0.681718, -0.147621},
-{-0.716567, -0.681718, 0.147621}, {-0.525731, -0.850651, 0.000000}, 
+{-0.716567, -0.681718, 0.147621}, {-0.525731, -0.850651, 0.000000},
 {-0.500000, -0.809017, 0.309017}, {-0.238856, -0.864188, 0.442863},
 {-0.262866, -0.951056, 0.162460}, {-0.864188, -0.442863, 0.238856},
 {-0.809017, -0.309017, 0.500000}, {-0.688191, -0.587785, 0.425325},
@@ -436,7 +436,7 @@ float VectorNormalizeLength (vec3_t v)
                v[1] *= ilength;
                v[2] *= ilength;
        }
-               
+
        return length;
 
 }
@@ -482,6 +482,21 @@ void R_ConcatTransforms (const float in1[3*4], const float in2[3*4], float out[3
        out[2*4+3] = in1[2*4+0] * in2[0*4+3] + in1[2*4+1] * in2[1*4+3] + in1[2*4+2] * in2[2*4+3] + in1[2*4+3];
 }
 
+float RadiusFromBounds (const vec3_t mins, const vec3_t maxs)
+{
+       vec3_t m1, m2;
+       VectorMultiply(mins, mins, m1);
+       VectorMultiply(maxs, maxs, m2);
+       return sqrt(max(m1[0], m2[0]) + max(m1[1], m2[1]) + max(m1[2], m2[2]));
+}
+
+float RadiusFromBoundsAndOrigin (const vec3_t mins, const vec3_t maxs, const vec3_t origin)
+{
+       vec3_t m1, m2;
+       VectorSubtract(mins, origin, m1);VectorMultiply(m1, m1, m1);
+       VectorSubtract(maxs, origin, m2);VectorMultiply(m2, m2, m2);
+       return sqrt(max(m1[0], m2[0]) + max(m1[1], m2[1]) + max(m1[2], m2[2]));
+}
 
 void Mathlib_Init(void)
 {
index d99a2d4..29b9c6c 100644 (file)
--- a/mathlib.h
+++ b/mathlib.h
@@ -90,6 +90,7 @@ extern vec3_t vec3_origin;
 }
 #define VectorRandom(v) do{(v)[0] = lhrandom(-1, 1);(v)[1] = lhrandom(-1, 1);(v)[2] = lhrandom(-1, 1);}while(DotProduct(v, v) > 1)
 #define VectorBlend(b1, b2, blend, c) do{float iblend = 1 - (blend);VectorMAM(iblend, b1, blend, b2, c);}while(0)
+#define BoxesOverlap(a,b,c,d) ((a)[0] <= (d)[0] && (b)[0] >= (c)[0] && (a)[1] <= (d)[1] && (b)[1] >= (c)[1] && (a)[2] <= (d)[2] && (b)[2] >= (c)[2])
 
 /*
 // LordHavoc: quaternion math, untested, don't know if these are correct,
@@ -182,6 +183,9 @@ tinydoubleplane_t;
 
 void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees);
 
+float RadiusFromBounds (const vec3_t mins, const vec3_t maxs);
+float RadiusFromBoundsAndOrigin (const vec3_t mins, const vec3_t maxs, const vec3_t origin);
+
 // print a matrix to the console
 struct matrix4x4_s;
 void Matrix4x4_Print(const struct matrix4x4_s *in);
index 4912638..db4ce0e 100644 (file)
@@ -309,7 +309,7 @@ void Mod_BuildMDLMD2MeshInfo(int numverts, int numtris, int *elements, float *te
 extern void R_Model_Alias_Draw(entity_render_t *ent);
 extern void R_Model_Alias_DrawFakeShadow(entity_render_t *ent);
 extern void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
-extern void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
+extern void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
 void Mod_LoadQ1AliasModel (model_t *mod, void *buffer)
 {
        int i, j, version, totalposes, totalskins, skinwidth, skinheight, totalverts, groupframes, groupskins, *elements, numverts, numtris;
@@ -881,7 +881,7 @@ extern void R_Model_Zymotic_DrawSky(entity_render_t *ent);
 extern void R_Model_Zymotic_Draw(entity_render_t *ent);
 extern void R_Model_Zymotic_DrawFakeShadow(entity_render_t *ent);
 extern void R_Model_Zymotic_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
-extern void R_Model_Zymotic_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
+extern void R_Model_Zymotic_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
 void Mod_LoadZymoticModel(model_t *mod, void *buffer)
 {
        zymtype1header_t *pinmodel, *pheader;
index d7825c7..20a57fa 100644 (file)
@@ -2625,7 +2625,7 @@ Mod_LoadBrushModel
 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
 extern void R_Model_Brush_Draw(entity_render_t *ent);
 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
-extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
+extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
 void Mod_LoadBrushModel (model_t *mod, void *buffer)
 {
        int i, j, k;
index 0c6578d..43cadd1 100644 (file)
@@ -87,6 +87,8 @@ shadowmesh_t;
 #include "model_sprite.h"
 #include "model_alias.h"
 
+#include "matrixlib.h"
+
 typedef struct model_s
 {
        char                    name[MAX_QPATH];
@@ -264,7 +266,7 @@ typedef struct model_s
        // draw a shadow volume for the model based on light source
        void(*DrawShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius);
        // draw the lighting on a model (through stencil)
-       void(*DrawLight)(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
+       void(*DrawLight)(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
 
        // memory pool for allocations
        mempool_t               *mempool;
index 18e17b7..6c1a191 100644 (file)
--- a/portals.c
+++ b/portals.c
@@ -135,12 +135,12 @@ int Portal_RecursiveFlowSearch (mleaf_t *leaf, vec3_t eye, int firstclipplane, i
                                {
                                        if (Portal_RecursiveFlowSearch(p->past, eye, firstclipplane + numclipplanes, newpoints))
                                                return true;
-                       }
+                               }
                                else
                                {
                                        if (Portal_RecursiveFlowSearch(p->past, eye, firstclipplane, numclipplanes))
                                                return true;
-                       }
+                               }
                        }
                }
        }
@@ -322,6 +322,7 @@ vec3_t trianglepoints[3];
 typedef struct portalrecursioninfo_s
 {
        int exact;
+       int numfrustumplanes;
        float nradius;
        qbyte *surfacemark;
        qbyte *leafmark;
@@ -446,6 +447,23 @@ void Portal_RecursiveFlow (portalrecursioninfo_t *info, mleaf_t *leaf, int first
        }
 }
 
+void Portal_RecursiveFindLeafForFlow(portalrecursioninfo_t *info, mnode_t *node)
+{
+       if (node->contents)
+       {
+               if (node->contents != CONTENTS_SKY && node->contents != CONTENTS_SOLID)
+                       Portal_RecursiveFlow(info, (mleaf_t *)node, 0, info->numfrustumplanes);
+       }
+       else
+       {
+               float f = DotProduct(info->eye, node->plane->normal) - node->plane->dist;
+               if (f > -0.1)
+                       Portal_RecursiveFindLeafForFlow(info, node->children[0]);
+               if (f < 0.1)
+                       Portal_RecursiveFindLeafForFlow(info, node->children[1]);
+       }
+}
+
 void Portal_Visibility(model_t *model, const vec3_t eye, qbyte *leafmark, qbyte *surfacemark, const mplane_t *frustumplanes, int numfrustumplanes, int exact, float radius)
 {
        int i;
@@ -476,8 +494,9 @@ void Portal_Visibility(model_t *model, const vec3_t eye, qbyte *leafmark, qbyte
        info.leafmark = leafmark;
        info.model = model;
        VectorCopy(eye, info.eye);
+       info.numfrustumplanes = numfrustumplanes;
 
-       Portal_RecursiveFlow(&info, Mod_PointInLeaf(eye, model), 0, numfrustumplanes);
+       Portal_RecursiveFindLeafForFlow(&info, model->nodes);
 
        if (ranoutofportalplanes)
                Con_Printf("Portal_RecursiveFlow: ran out of %d plane stack when recursing through portals\n", MAXRECURSIVEPORTALPLANES);
index 0c0e19a..72307ef 100644 (file)
@@ -26,6 +26,7 @@ qbyte *trianglefacinglight;
 rtexturepool_t *r_shadow_texturepool;
 rtexture_t *r_shadow_normalscubetexture;
 rtexture_t *r_shadow_attenuation2dtexture;
+rtexture_t *r_shadow_attenuation3dtexture;
 rtexture_t *r_shadow_blankbumptexture;
 rtexture_t *r_shadow_blankglosstexture;
 rtexture_t *r_shadow_blankwhitetexture;
@@ -42,6 +43,7 @@ cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0
 cvar_t r_shadow_shadownudge = {0, "r_shadow_shadownudge", "1"};
 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "100000"};
+cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
 
 int c_rt_lights, c_rt_clears, c_rt_scissored;
 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
@@ -63,6 +65,7 @@ void r_shadow_start(void)
        trianglefacinglight = NULL;
        r_shadow_normalscubetexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
+       r_shadow_attenuation3dtexture = NULL;
        r_shadow_blankbumptexture = NULL;
        r_shadow_blankglosstexture = NULL;
        r_shadow_blankwhitetexture = NULL;
@@ -77,6 +80,7 @@ void r_shadow_shutdown(void)
        r_shadow_reloadlights = true;
        r_shadow_normalscubetexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
+       r_shadow_attenuation3dtexture = NULL;
        r_shadow_blankbumptexture = NULL;
        r_shadow_blankglosstexture = NULL;
        r_shadow_blankwhitetexture = NULL;
@@ -108,6 +112,7 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_shadownudge);
        Cvar_RegisterVariable(&r_shadow_portallight);
        Cvar_RegisterVariable(&r_shadow_projectdistance);
+       Cvar_RegisterVariable(&r_shadow_texture3d);
        R_Shadow_EditLights_Init();
        R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
 }
@@ -369,14 +374,17 @@ void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh)
 float r_shadow_attenpower, r_shadow_attenscale;
 static void R_Shadow_MakeTextures(void)
 {
-       int x, y, d, side;
+       int x, y, z, d, side;
        float v[3], s, t, intensity;
        qbyte *data;
        R_FreeTexturePool(&r_shadow_texturepool);
        r_shadow_texturepool = R_AllocTexturePool();
        r_shadow_attenpower = r_shadow_lightattenuationpower.value;
        r_shadow_attenscale = r_shadow_lightattenuationscale.value;
-       data = Mem_Alloc(tempmempool, 6*128*128*4);
+#define NORMSIZE 64
+#define ATTEN2DSIZE 64
+#define ATTEN3DSIZE 32
+       data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
        data[0] = 128;
        data[1] = 128;
        data[2] = 255;
@@ -394,12 +402,12 @@ static void R_Shadow_MakeTextures(void)
        r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
        for (side = 0;side < 6;side++)
        {
-               for (y = 0;y < 128;y++)
+               for (y = 0;y < NORMSIZE;y++)
                {
-                       for (x = 0;x < 128;x++)
+                       for (x = 0;x < NORMSIZE;x++)
                        {
-                               s = (x + 0.5f) * (2.0f / 128.0f) - 1.0f;
-                               t = (y + 0.5f) * (2.0f / 128.0f) - 1.0f;
+                               s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
+                               t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
                                switch(side)
                                {
                                case 0:
@@ -434,33 +442,56 @@ static void R_Shadow_MakeTextures(void)
                                        break;
                                }
                                intensity = 127.0f / sqrt(DotProduct(v, v));
-                               data[((side*128+y)*128+x)*4+0] = 128.0f + intensity * v[0];
-                               data[((side*128+y)*128+x)*4+1] = 128.0f + intensity * v[1];
-                               data[((side*128+y)*128+x)*4+2] = 128.0f + intensity * v[2];
-                               data[((side*128+y)*128+x)*4+3] = 255;
+                               data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
+                               data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
+                               data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
+                               data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
                        }
                }
        }
-       r_shadow_normalscubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalscube", 128, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
-       for (y = 0;y < 128;y++)
+       r_shadow_normalscubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalscube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
+       for (y = 0;y < ATTEN2DSIZE;y++)
        {
-               for (x = 0;x < 128;x++)
+               for (x = 0;x < ATTEN2DSIZE;x++)
                {
-                       v[0] = (x + 0.5f) * (2.0f / (128.0f - 8.0f)) - 1.0f;
-                       v[1] = (y + 0.5f) * (2.0f / (128.0f - 8.0f)) - 1.0f;
+                       v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
+                       v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
                        v[2] = 0;
                        intensity = 1.0f - sqrt(DotProduct(v, v));
                        if (intensity > 0)
-                               intensity = pow(intensity, r_shadow_attenpower);
-                       intensity = bound(0, intensity * r_shadow_attenscale * 256.0f, 255.0f);
+                               intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
                        d = bound(0, intensity, 255);
-                       data[((0*128+y)*128+x)*4+0] = d;
-                       data[((0*128+y)*128+x)*4+1] = d;
-                       data[((0*128+y)*128+x)*4+2] = d;
-                       data[((0*128+y)*128+x)*4+3] = d;
+                       data[(y*ATTEN2DSIZE+x)*4+0] = d;
+                       data[(y*ATTEN2DSIZE+x)*4+1] = d;
+                       data[(y*ATTEN2DSIZE+x)*4+2] = d;
+                       data[(y*ATTEN2DSIZE+x)*4+3] = d;
                }
        }
-       r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", 128, 128, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
+       r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
+       if (r_shadow_texture3d.integer)
+       {
+               for (z = 0;z < ATTEN3DSIZE;z++)
+               {
+                       for (y = 0;y < ATTEN3DSIZE;y++)
+                       {
+                               for (x = 0;x < ATTEN3DSIZE;x++)
+                               {
+                                       v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
+                                       v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
+                                       v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
+                                       intensity = 1.0f - sqrt(DotProduct(v, v));
+                                       if (intensity > 0)
+                                               intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
+                                       d = bound(0, intensity, 255);
+                                       data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
+                                       data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
+                                       data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
+                                       data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
+                               }
+                       }
+               }
+               r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
+       }
        Mem_Free(data);
 }
 
@@ -468,8 +499,12 @@ void R_Shadow_Stage_Begin(void)
 {
        rmeshstate_t m;
 
+       if (r_shadow_texture3d.integer && !gl_texture3d)
+               Cvar_SetValueQuick(&r_shadow_texture3d, 0);
+
        //cl.worldmodel->numlights = min(cl.worldmodel->numlights, 1);
        if (!r_shadow_attenuation2dtexture
+        || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
         || r_shadow_lightattenuationpower.value != r_shadow_attenpower
         || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
                R_Shadow_MakeTextures();
@@ -599,6 +634,7 @@ void R_Shadow_Stage_End(void)
        r_shadowstage = SHADOWSTAGE_NONE;
 }
 
+#if 0
 int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const float *origin, float radius)
 {
        int i, ix1, iy1, ix2, iy2;
@@ -737,36 +773,190 @@ int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const
        c_rt_scissored++;
        return false;
 }
+#endif
 
-void R_Shadow_GenTexCoords_Attenuation2D1D(float *out2d, float *out1d, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, float lightradius)
+int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
 {
-       int i;
-       float lightvec[3], iradius;
-       iradius = 0.5f / lightradius;
-       for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out2d += 4, out1d += 4)
-       {
-               VectorSubtract(vertex, relativelightorigin, lightvec);
-               out2d[0] = 0.5f + DotProduct(svectors, lightvec) * iradius;
-               out2d[1] = 0.5f + DotProduct(tvectors, lightvec) * iradius;
-               out2d[2] = 0;
-               out1d[0] = 0.5f + DotProduct(normals, lightvec) * iradius;
-               out1d[1] = 0.5f;
-               out1d[2] = 0;
+       int i, ix1, iy1, ix2, iy2;
+       float x1, y1, x2, y2, x, y, f;
+       vec3_t smins, smaxs;
+       vec4_t v, v2;
+       if (!r_shadow_scissor.integer)
+               return false;
+       // if view is inside the box, just say yes it's visible
+       if (BoxesOverlap(r_origin, r_origin, mins, maxs))
+       {
+               qglDisable(GL_SCISSOR_TEST);
+               return false;
+       }
+       for (i = 0;i < 3;i++)
+       {
+               if (vpn[i] >= 0)
+               {
+                       v[i] = mins[i];
+                       v2[i] = maxs[i];
+               }
+               else
+               {
+                       v[i] = maxs[i];
+                       v2[i] = mins[i];
+               }
+       }
+       f = DotProduct(vpn, r_origin) + 1;
+       if (DotProduct(vpn, v2) <= f)
+       {
+               // entirely behind nearclip plane
+               qglDisable(GL_SCISSOR_TEST);
+               return false;
+       }
+       if (DotProduct(vpn, v) >= f)
+       {
+               // entirely infront of nearclip plane
+               x1 = y1 = x2 = y2 = 0;
+               for (i = 0;i < 8;i++)
+               {
+                       v[0] = (i & 1) ? mins[0] : maxs[0];
+                       v[1] = (i & 2) ? mins[1] : maxs[1];
+                       v[2] = (i & 4) ? mins[2] : maxs[2];
+                       v[3] = 1.0f;
+                       GL_TransformToScreen(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]);
+                       x = v2[0];
+                       y = v2[1];
+                       if (i)
+                       {
+                               if (x1 > x) x1 = x;
+                               if (x2 < x) x2 = x;
+                               if (y1 > y) y1 = y;
+                               if (y2 < y) y2 = y;
+                       }
+                       else
+                       {
+                               x1 = x2 = x;
+                               y1 = y2 = y;
+                       }
+               }
+       }
+       else
+       {
+               // clipped by nearclip plane
+               // this is nasty and crude...
+               // create viewspace bbox
+               for (i = 0;i < 8;i++)
+               {
+                       v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_origin[0];
+                       v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_origin[1];
+                       v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_origin[2];
+                       v2[0] = DotProduct(v, vright);
+                       v2[1] = DotProduct(v, vup);
+                       v2[2] = DotProduct(v, vpn);
+                       if (i)
+                       {
+                               if (smins[0] > v2[0]) smins[0] = v2[0];
+                               if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
+                               if (smins[1] > v2[1]) smins[1] = v2[1];
+                               if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
+                               if (smins[2] > v2[2]) smins[2] = v2[2];
+                               if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
+                       }
+                       else
+                       {
+                               smins[0] = smaxs[0] = v2[0];
+                               smins[1] = smaxs[1] = v2[1];
+                               smins[2] = smaxs[2] = v2[2];
+                       }
+               }
+               // now we have a bbox in viewspace
+               // clip it to the view plane
+               if (smins[2] < 1)
+                       smins[2] = 1;
+               // return true if that culled the box
+               if (smins[2] >= smaxs[2])
+                       return true;
+               // ok some of it is infront of the view, transform each corner back to
+               // worldspace and then to screenspace and make screen rect
+               // initialize these variables just to avoid compiler warnings
+               x1 = y1 = x2 = y2 = 0;
+               for (i = 0;i < 8;i++)
+               {
+                       v2[0] = (i & 1) ? smins[0] : smaxs[0];
+                       v2[1] = (i & 2) ? smins[1] : smaxs[1];
+                       v2[2] = (i & 4) ? smins[2] : smaxs[2];
+                       v[0] = v2[0] * vright[0] + v2[1] * vup[0] + v2[2] * vpn[0] + r_origin[0];
+                       v[1] = v2[0] * vright[1] + v2[1] * vup[1] + v2[2] * vpn[1] + r_origin[1];
+                       v[2] = v2[0] * vright[2] + v2[1] * vup[2] + v2[2] * vpn[2] + r_origin[2];
+                       v[3] = 1.0f;
+                       GL_TransformToScreen(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]);
+                       x = v2[0];
+                       y = v2[1];
+                       if (i)
+                       {
+                               if (x1 > x) x1 = x;
+                               if (x2 < x) x2 = x;
+                               if (y1 > y) y1 = y;
+                               if (y2 < y) y2 = y;
+                       }
+                       else
+                       {
+                               x1 = x2 = x;
+                               y1 = y2 = y;
+                       }
+               }
+               /*
+               // this code doesn't handle boxes with any points behind view properly
+               x1 = 1000;x2 = -1000;
+               y1 = 1000;y2 = -1000;
+               for (i = 0;i < 8;i++)
+               {
+                       v[0] = (i & 1) ? mins[0] : maxs[0];
+                       v[1] = (i & 2) ? mins[1] : maxs[1];
+                       v[2] = (i & 4) ? mins[2] : maxs[2];
+                       v[3] = 1.0f;
+                       GL_TransformToScreen(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 (v2[2] > 0)
+                       {
+                               x = v2[0];
+                               y = v2[1];
+
+                               if (x1 > x) x1 = x;
+                               if (x2 < x) x2 = x;
+                               if (y1 > y) y1 = y;
+                               if (y2 < y) y2 = y;
+                       }
+               }
+               */
        }
+       ix1 = x1 - 1.0f;
+       iy1 = y1 - 1.0f;
+       ix2 = x2 + 1.0f;
+       iy2 = y2 + 1.0f;
+       //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
+       if (ix1 < r_refdef.x) ix1 = r_refdef.x;
+       if (iy1 < r_refdef.y) iy1 = r_refdef.y;
+       if (ix2 > r_refdef.x + r_refdef.width) ix2 = r_refdef.x + r_refdef.width;
+       if (iy2 > r_refdef.y + r_refdef.height) iy2 = r_refdef.y + r_refdef.height;
+       if (ix2 <= ix1 || iy2 <= iy1)
+               return true;
+       // set up the scissor rectangle
+       qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
+       qglEnable(GL_SCISSOR_TEST);
+       c_rt_scissored++;
+       return false;
 }
 
-void R_Shadow_GenTexCoords_Diffuse_Attenuation3D(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, float lightradius)
+// FIXME: this should be done in a vertex program when possible
+// FIXME: if vertex program not available, this would really benefit from 3DNow! or SSE
+void R_Shadow_TransformVertices(float *out, int numverts, const float *vertex, const matrix4x4_t *matrix)
 {
-       int i;
-       float lightvec[3], iradius;
-       iradius = 0.5f / lightradius;
-       for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
+       do
        {
-               VectorSubtract(vertex, relativelightorigin, lightvec);
-               out[0] = 0.5f + DotProduct(svectors, lightvec) * iradius;
-               out[1] = 0.5f + DotProduct(tvectors, lightvec) * iradius;
-               out[2] = 0.5f + DotProduct(normals, lightvec) * iradius;
+               Matrix4x4_Transform(matrix, vertex, out);
+               vertex += 4;
+               out += 4;
        }
+       while (--numverts);
 }
 
 void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin)
@@ -783,27 +973,6 @@ void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out, int numverts, const
        }
 }
 
-void R_Shadow_GenTexCoords_Specular_Attenuation3D(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin, float lightradius)
-{
-       int i;
-       float lightdir[3], eyedir[3], halfdir[3], lightdirlen, iradius;
-       iradius = 0.5f / lightradius;
-       for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
-       {
-               VectorSubtract(vertex, relativelightorigin, lightdir);
-               // this is used later to make the attenuation correct
-               lightdirlen = sqrt(DotProduct(lightdir, lightdir)) * iradius;
-               VectorNormalizeFast(lightdir);
-               VectorSubtract(vertex, relativeeyeorigin, eyedir);
-               VectorNormalizeFast(eyedir);
-               VectorAdd(lightdir, eyedir, halfdir);
-               VectorNormalizeFast(halfdir);
-               out[0] = 0.5f + DotProduct(svectors, halfdir) * lightdirlen;
-               out[1] = 0.5f + DotProduct(tvectors, halfdir) * lightdirlen;
-               out[2] = 0.5f + DotProduct(normals, halfdir) * lightdirlen;
-       }
-}
-
 void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
 {
        int i;
@@ -822,16 +991,7 @@ void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out, int numverts, cons
        }
 }
 
-void R_Shadow_GenTexCoords_LightCubeMap(float *out, int numverts, const float *vertex, const vec3_t relativelightorigin)
-{
-       int i;
-       // FIXME: this needs to be written
-       // this code assumes the vertices are in worldspace (a false assumption)
-       for (i = 0;i < numverts;i++, vertex += 4, out += 4)
-               VectorSubtract(vertex, relativelightorigin, out);
-}
-
-void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, float lightradius, const float *lightcolor, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
+void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, float lightradius, const float *lightcolor, const matrix4x4_t *matrix_worldtofilter, const matrix4x4_t *matrix_worldtoattenuationxyz, const matrix4x4_t *matrix_worldtoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
 {
        int renders;
        float color[3];
@@ -843,38 +1003,37 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
        // mult is how many times the final pass of the lighting will be
        // performed to get more brightness than otherwise possible
        // limit mult to 64 for sanity sake
-       if (r_textureunits.integer >= 4)
+       if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
        {
-               // 4 texture no3D combine path, two pass
+               // 3/2 3D combine path
                m.tex[0] = R_GetTexture(bumptexture);
                m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+               m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
                m.texcombinergb[0] = GL_REPLACE;
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-               m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
                R_Mesh_TextureState(&m);
                qglColorMask(0,0,0,1);
                qglDisable(GL_BLEND);
                GL_Color(1,1,1,1);
                memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
                R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin);
-               R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[2], varray_texcoord[3], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
+               R_Shadow_TransformVertices(varray_texcoord[2], numverts, varray_vertex, matrix_worldtoattenuationxyz);
                R_Mesh_Draw(numverts, numtriangles, elements);
                c_rt_lightmeshes++;
                c_rt_lighttris += numtriangles;
 
                m.tex[0] = R_GetTexture(basetexture);
+               m.tex[1] = 0;
                m.texcubemap[1] = R_GetTexture(lightcubemap);
+               m.tex3d[2] = 0;
                m.texcombinergb[0] = GL_MODULATE;
                m.texcombinergb[1] = GL_MODULATE;
-               m.tex[2] = 0;
-               m.tex[3] = 0;
                R_Mesh_TextureState(&m);
                qglColorMask(1,1,1,0);
                qglBlendFunc(GL_DST_ALPHA, GL_ONE);
                qglEnable(GL_BLEND);
                if (lightcubemap)
-                       R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
+                       R_Shadow_TransformVertices(varray_texcoord[1], numverts, varray_vertex, matrix_worldtofilter);
 
                VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color);
                for (renders = 0;renders < 64 && (color[0] > 0 || color[1] > 0 || color[2] > 0);renders++, color[0] = max(0, color[0] - 1.0f), color[1] = max(0, color[1] - 1.0f), color[2] = max(0, color[2] - 1.0f))
@@ -885,22 +1044,21 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                        c_rt_lighttris += numtriangles;
                }
        }
-       else
+       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
        {
-               // 2 texture no3D combine path, three pass
-               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               // 1/2/2 3D combine path
+               m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
                R_Mesh_TextureState(&m);
                qglColorMask(0,0,0,1);
                qglDisable(GL_BLEND);
                GL_Color(1,1,1,1);
-               R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[0], varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
+               R_Shadow_TransformVertices(varray_texcoord[0], numverts, varray_vertex, matrix_worldtoattenuationxyz);
                R_Mesh_Draw(numverts, numtriangles, elements);
                c_rt_lightmeshes++;
                c_rt_lighttris += numtriangles;
 
                m.tex[0] = R_GetTexture(bumptexture);
-               m.tex[1] = 0;
+               m.tex3d[0] = 0;
                m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
                m.texcombinergb[0] = GL_REPLACE;
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
@@ -921,7 +1079,7 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                qglColorMask(1,1,1,0);
                qglBlendFunc(GL_DST_ALPHA, GL_ONE);
                if (lightcubemap)
-                       R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
+                       R_Shadow_TransformVertices(varray_texcoord[1], numverts, varray_vertex, matrix_worldtofilter);
 
                VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color);
                for (renders = 0;renders < 64 && (color[0] > 0 || color[1] > 0 || color[2] > 0);renders++, color[0] = max(0, color[0] - 1.0f), color[1] = max(0, color[1] - 1.0f), color[2] = max(0, color[2] - 1.0f))
@@ -932,74 +1090,124 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
                        c_rt_lighttris += numtriangles;
                }
        }
-}
-
-void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
-{
-       int renders;
-       float color[3];
-       rmeshstate_t m;
-       memset(&m, 0, sizeof(m));
-       if (!bumptexture)
-               bumptexture = r_shadow_blankbumptexture;
-       if (!glosstexture)
-               glosstexture = r_shadow_blankglosstexture;
-       if (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture))
+       else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
        {
-               // 2 texture no3D combine path, five pass
-               memset(&m, 0, sizeof(m));
-
+               // 2/2 3D combine path
                m.tex[0] = R_GetTexture(bumptexture);
+               m.tex3d[0] = 0;
                m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+               m.texcombinergb[0] = GL_REPLACE;
                m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                R_Mesh_TextureState(&m);
+               GL_Color(1,1,1,1);
                qglColorMask(0,0,0,1);
                qglDisable(GL_BLEND);
-               GL_Color(1,1,1,1);
                memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
-               R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, relativeeyeorigin);
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin);
                R_Mesh_Draw(numverts, numtriangles, elements);
                c_rt_lightmeshes++;
                c_rt_lighttris += numtriangles;
 
-               m.tex[0] = 0;
-               m.texcubemap[1] = 0;
+               m.tex[0] = R_GetTexture(basetexture);
+               m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
+               m.texcombinergb[0] = GL_MODULATE;
                m.texcombinergb[1] = GL_MODULATE;
                R_Mesh_TextureState(&m);
-               // square alpha in framebuffer a few times to make it shiny
-               qglBlendFunc(GL_ZERO, GL_DST_ALPHA);
+               qglColorMask(1,1,1,0);
+               qglBlendFunc(GL_DST_ALPHA, GL_ONE);
                qglEnable(GL_BLEND);
-               // these comments are a test run through this math for intensity 0.5
-               // 0.5 * 0.5 = 0.25
-               R_Mesh_Draw(numverts, numtriangles, elements);
-               c_rt_lightmeshes++;
-               c_rt_lighttris += numtriangles;
-               // 0.25 * 0.25 = 0.0625
+               R_Shadow_TransformVertices(varray_texcoord[1], numverts, varray_vertex, matrix_worldtoattenuationxyz);
+
+               VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color);
+               for (renders = 0;renders < 64 && (color[0] > 0 || color[1] > 0 || color[2] > 0);renders++, color[0] = max(0, color[0] - 1.0f), color[1] = max(0, color[1] - 1.0f), color[2] = max(0, color[2] - 1.0f))
+               {
+                       GL_Color(color[0], color[1], color[2], 1);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+               }
+       }
+       else if (r_textureunits.integer >= 4)
+       {
+               // 4/2 2D combine path
+               m.tex[0] = R_GetTexture(bumptexture);
+               m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+               m.texcombinergb[0] = GL_REPLACE;
+               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+               m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
+               R_Mesh_TextureState(&m);
+               qglColorMask(0,0,0,1);
+               qglDisable(GL_BLEND);
+               GL_Color(1,1,1,1);
+               memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin);
+               R_Shadow_TransformVertices(varray_texcoord[2], numverts, varray_vertex, matrix_worldtoattenuationxyz);
+               R_Shadow_TransformVertices(varray_texcoord[3], numverts, varray_vertex, matrix_worldtoattenuationz);
                R_Mesh_Draw(numverts, numtriangles, elements);
                c_rt_lightmeshes++;
                c_rt_lighttris += numtriangles;
-               // 0.0625 * 0.0625 = 0.00390625
+
+               m.tex[0] = R_GetTexture(basetexture);
+               m.texcubemap[1] = R_GetTexture(lightcubemap);
+               m.texcombinergb[0] = GL_MODULATE;
+               m.texcombinergb[1] = GL_MODULATE;
+               m.tex[2] = 0;
+               m.tex[3] = 0;
+               R_Mesh_TextureState(&m);
+               qglColorMask(1,1,1,0);
+               qglBlendFunc(GL_DST_ALPHA, GL_ONE);
+               qglEnable(GL_BLEND);
+               if (lightcubemap)
+                       R_Shadow_TransformVertices(varray_texcoord[1], numverts, varray_vertex, matrix_worldtofilter);
+
+               VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color);
+               for (renders = 0;renders < 64 && (color[0] > 0 || color[1] > 0 || color[2] > 0);renders++, color[0] = max(0, color[0] - 1.0f), color[1] = max(0, color[1] - 1.0f), color[2] = max(0, color[2] - 1.0f))
+               {
+                       GL_Color(color[0], color[1], color[2], 1);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+               }
+       }
+       else
+       {
+               // 2/2/2 2D combine path
+               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               R_Mesh_TextureState(&m);
+               qglColorMask(0,0,0,1);
+               qglDisable(GL_BLEND);
+               GL_Color(1,1,1,1);
+               R_Shadow_TransformVertices(varray_texcoord[0], numverts, varray_vertex, matrix_worldtoattenuationxyz);
+               R_Shadow_TransformVertices(varray_texcoord[1], numverts, varray_vertex, matrix_worldtoattenuationz);
                R_Mesh_Draw(numverts, numtriangles, elements);
                c_rt_lightmeshes++;
                c_rt_lighttris += numtriangles;
 
-               m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
-               m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+               m.tex[0] = R_GetTexture(bumptexture);
+               m.tex[1] = 0;
+               m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+               m.texcombinergb[0] = GL_REPLACE;
+               m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
                R_Mesh_TextureState(&m);
                qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
-               R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[0], varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
+               qglEnable(GL_BLEND);
+               memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+               R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin);
                R_Mesh_Draw(numverts, numtriangles, elements);
                c_rt_lightmeshes++;
                c_rt_lighttris += numtriangles;
 
-               m.tex[0] = R_GetTexture(glosstexture);
+               m.tex[0] = R_GetTexture(basetexture);
                m.texcubemap[1] = R_GetTexture(lightcubemap);
+               m.texcombinergb[0] = GL_MODULATE;
+               m.texcombinergb[1] = GL_MODULATE;
                R_Mesh_TextureState(&m);
                qglColorMask(1,1,1,0);
                qglBlendFunc(GL_DST_ALPHA, GL_ONE);
-               memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
                if (lightcubemap)
-                       R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
+                       R_Shadow_TransformVertices(varray_texcoord[1], numverts, varray_vertex, matrix_worldtofilter);
 
                VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color);
                for (renders = 0;renders < 64 && (color[0] > 0 || color[1] > 0 || color[2] > 0);renders++, color[0] = max(0, color[0] - 1.0f), color[1] = max(0, color[1] - 1.0f), color[2] = max(0, color[2] - 1.0f))
@@ -1012,6 +1220,207 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen
        }
 }
 
+void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, const matrix4x4_t *matrix_worldtofilter, const matrix4x4_t *matrix_worldtoattenuationxyz, const matrix4x4_t *matrix_worldtoattenuationz, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
+{
+       int renders;
+       float color[3];
+       rmeshstate_t m;
+       memset(&m, 0, sizeof(m));
+       if (!bumptexture)
+               bumptexture = r_shadow_blankbumptexture;
+       if (!glosstexture)
+               glosstexture = r_shadow_blankglosstexture;
+       if (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture))
+       {
+               if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
+               {
+                       // 2/0/0/0/1/2 3D combine path
+                       m.tex[0] = R_GetTexture(bumptexture);
+                       m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+                       m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+                       R_Mesh_TextureState(&m);
+                       qglColorMask(0,0,0,1);
+                       qglDisable(GL_BLEND);
+                       GL_Color(1,1,1,1);
+                       memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+                       R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, relativeeyeorigin);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+
+                       m.tex[0] = 0;
+                       m.texcubemap[1] = 0;
+                       m.texcombinergb[1] = GL_MODULATE;
+                       R_Mesh_TextureState(&m);
+                       // square alpha in framebuffer a few times to make it shiny
+                       qglBlendFunc(GL_ZERO, GL_DST_ALPHA);
+                       qglEnable(GL_BLEND);
+                       // these comments are a test run through this math for intensity 0.5
+                       // 0.5 * 0.5 = 0.25
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+                       // 0.25 * 0.25 = 0.0625
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+                       // 0.0625 * 0.0625 = 0.00390625
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+
+                       m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
+                       R_Mesh_TextureState(&m);
+                       qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
+                       R_Shadow_TransformVertices(varray_texcoord[0], numverts, varray_vertex, matrix_worldtoattenuationxyz);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+
+                       m.tex3d[0] = 0;
+                       m.tex[0] = R_GetTexture(glosstexture);
+                       m.texcubemap[1] = R_GetTexture(lightcubemap);
+                       R_Mesh_TextureState(&m);
+                       qglColorMask(1,1,1,0);
+                       qglBlendFunc(GL_DST_ALPHA, GL_ONE);
+                       memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+                       if (lightcubemap)
+                               R_Shadow_TransformVertices(varray_texcoord[1], numverts, varray_vertex, matrix_worldtofilter);
+
+                       VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color);
+                       for (renders = 0;renders < 64 && (color[0] > 0 || color[1] > 0 || color[2] > 0);renders++, color[0] = max(0, color[0] - 1.0f), color[1] = max(0, color[1] - 1.0f), color[2] = max(0, color[2] - 1.0f))
+                       {
+                               GL_Color(color[0], color[1], color[2], 1);
+                               R_Mesh_Draw(numverts, numtriangles, elements);
+                               c_rt_lightmeshes++;
+                               c_rt_lighttris += numtriangles;
+                       }
+               }
+               else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
+               {
+                       // 2/0/0/0/2 3D combine path
+                       m.tex[0] = R_GetTexture(bumptexture);
+                       m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+                       m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+                       R_Mesh_TextureState(&m);
+                       qglColorMask(0,0,0,1);
+                       qglDisable(GL_BLEND);
+                       GL_Color(1,1,1,1);
+                       memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+                       R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, relativeeyeorigin);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+
+                       m.tex[0] = 0;
+                       m.texcubemap[1] = 0;
+                       m.texcombinergb[1] = GL_MODULATE;
+                       R_Mesh_TextureState(&m);
+                       // square alpha in framebuffer a few times to make it shiny
+                       qglBlendFunc(GL_ZERO, GL_DST_ALPHA);
+                       qglEnable(GL_BLEND);
+                       // these comments are a test run through this math for intensity 0.5
+                       // 0.5 * 0.5 = 0.25
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+                       // 0.25 * 0.25 = 0.0625
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+                       // 0.0625 * 0.0625 = 0.00390625
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+
+                       m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
+                       m.tex[1] = R_GetTexture(glosstexture);
+                       R_Mesh_TextureState(&m);
+                       R_Shadow_TransformVertices(varray_texcoord[0], numverts, varray_vertex, matrix_worldtoattenuationxyz);
+                       memcpy(varray_texcoord[1], texcoords, numverts * sizeof(float[4]));
+                       qglColorMask(1,1,1,0);
+                       qglBlendFunc(GL_DST_ALPHA, GL_ONE);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+
+                       VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color);
+                       for (renders = 0;renders < 64 && (color[0] > 0 || color[1] > 0 || color[2] > 0);renders++, color[0] = max(0, color[0] - 1.0f), color[1] = max(0, color[1] - 1.0f), color[2] = max(0, color[2] - 1.0f))
+                       {
+                               GL_Color(color[0], color[1], color[2], 1);
+                               R_Mesh_Draw(numverts, numtriangles, elements);
+                               c_rt_lightmeshes++;
+                               c_rt_lighttris += numtriangles;
+                       }
+               }
+               else if (r_textureunits.integer >= 2 /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
+               {
+                       // 2/0/0/0/2/2 2D combine path
+                       m.tex[0] = R_GetTexture(bumptexture);
+                       m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+                       m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+                       R_Mesh_TextureState(&m);
+                       qglColorMask(0,0,0,1);
+                       qglDisable(GL_BLEND);
+                       GL_Color(1,1,1,1);
+                       memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+                       R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, relativeeyeorigin);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+
+                       m.tex[0] = 0;
+                       m.texcubemap[1] = 0;
+                       m.texcombinergb[1] = GL_MODULATE;
+                       R_Mesh_TextureState(&m);
+                       // square alpha in framebuffer a few times to make it shiny
+                       qglBlendFunc(GL_ZERO, GL_DST_ALPHA);
+                       qglEnable(GL_BLEND);
+                       // these comments are a test run through this math for intensity 0.5
+                       // 0.5 * 0.5 = 0.25
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+                       // 0.25 * 0.25 = 0.0625
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+                       // 0.0625 * 0.0625 = 0.00390625
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+
+                       m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+                       m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+                       R_Mesh_TextureState(&m);
+                       qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
+                       R_Shadow_TransformVertices(varray_texcoord[0], numverts, varray_vertex, matrix_worldtoattenuationxyz);
+                       R_Shadow_TransformVertices(varray_texcoord[1], numverts, varray_vertex, matrix_worldtoattenuationz);
+                       R_Mesh_Draw(numverts, numtriangles, elements);
+                       c_rt_lightmeshes++;
+                       c_rt_lighttris += numtriangles;
+
+                       m.tex[0] = R_GetTexture(glosstexture);
+                       m.texcubemap[1] = R_GetTexture(lightcubemap);
+                       R_Mesh_TextureState(&m);
+                       qglColorMask(1,1,1,0);
+                       qglBlendFunc(GL_DST_ALPHA, GL_ONE);
+                       memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+                       if (lightcubemap)
+                               R_Shadow_TransformVertices(varray_texcoord[1], numverts, varray_vertex, matrix_worldtofilter);
+
+                       VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color);
+                       for (renders = 0;renders < 64 && (color[0] > 0 || color[1] > 0 || color[2] > 0);renders++, color[0] = max(0, color[0] - 1.0f), color[1] = max(0, color[1] - 1.0f), color[2] = max(0, color[2] - 1.0f))
+                       {
+                               GL_Color(color[0], color[1], color[2], 1);
+                               R_Mesh_Draw(numverts, numtriangles, elements);
+                               c_rt_lightmeshes++;
+                               c_rt_lighttris += numtriangles;
+                       }
+               }
+       }
+}
+
 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light)
 {
        R_Mesh_Matrix(matrix);
@@ -1034,8 +1443,7 @@ static int castshadowcount = 1;
 void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style, const char *cubemapname, int castshadow)
 {
        int i, j, k, l, maxverts, *mark, tris;
-       float *verts, *v, f, temp[3], radius2;
-       //float projectdistance, *v0, *v1, temp2[3], temp3[3];
+       float *verts;
        worldlight_t *e;
        shadowmesh_t *mesh, *castmesh;
        mleaf_t *leaf;
@@ -1062,12 +1470,11 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style
        e->castshadows = castshadow;
 
        e->cullradius = e->lightradius;
-       e->mins[0] = e->origin[0] - e->lightradius;
-       e->maxs[0] = e->origin[0] + e->lightradius;
-       e->mins[1] = e->origin[1] - e->lightradius;
-       e->maxs[1] = e->origin[1] + e->lightradius;
-       e->mins[2] = e->origin[2] - e->lightradius;
-       e->maxs[2] = e->origin[2] + e->lightradius;
+       for (k = 0;k < 3;k++)
+       {
+               e->mins[k] = e->origin[k] - e->lightradius;
+               e->maxs[k] = e->origin[k] + e->lightradius;
+       }
 
        e->next = r_shadow_worldlightchain;
        r_shadow_worldlightchain = e;
@@ -1080,43 +1487,24 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style
        if (cl.worldmodel)
        {
                castshadowcount++;
-               if (r_shadow_portallight.integer)
+               i = Mod_PointContents(e->origin, cl.worldmodel);
+               if (r_shadow_portallight.integer && i != CONTENTS_SOLID && i != CONTENTS_SKY)
                {
                        qbyte *byteleafpvs;
                        qbyte *bytesurfacepvs;
+
                        byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->numleafs + 1);
                        bytesurfacepvs = Mem_Alloc(tempmempool, cl.worldmodel->numsurfaces);
-                       Portal_Visibility(cl.worldmodel, e->origin, byteleafpvs, bytesurfacepvs, NULL, 0, true, e->lightradius);
+
+                       Portal_Visibility(cl.worldmodel, e->origin, byteleafpvs, bytesurfacepvs, NULL, 0, true, RadiusFromBoundsAndOrigin(e->mins, e->maxs, e->origin));
 
                        for (i = 0, leaf = cl.worldmodel->leafs + 1;i < cl.worldmodel->numleafs;i++, leaf++)
-                       {
-                               if (byteleafpvs[i+1])
-                               {
-                                       temp[0] = bound(leaf->mins[0], e->origin[0], leaf->maxs[0]) - e->origin[0];
-                                       temp[1] = bound(leaf->mins[1], e->origin[1], leaf->maxs[1]) - e->origin[1];
-                                       temp[2] = bound(leaf->mins[2], e->origin[2], leaf->maxs[2]) - e->origin[2];
-                                       if (DotProduct(temp, temp) < e->lightradius * e->lightradius)
-                                               leaf->worldnodeframe = castshadowcount;
-                               }
-                       }
+                               if (byteleafpvs[i+1] && BoxesOverlap(leaf->mins, leaf->maxs, e->mins, e->maxs))
+                                       leaf->worldnodeframe = castshadowcount;
 
                        for (i = 0, surf = cl.worldmodel->surfaces;i < cl.worldmodel->numsurfaces;i++, surf++)
-                       {
-                               if (bytesurfacepvs[i])
-                               {
-                                       f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
-                                       if (surf->flags & SURF_PLANEBACK)
-                                               f = -f;
-                                       if (f > 0 && f < e->lightradius)
-                                       {
-                                               temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
-                                               temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
-                                               temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
-                                               if (DotProduct(temp, temp) < e->lightradius * e->lightradius)
-                                                       surf->castshadow = castshadowcount;
-                                       }
-                               }
-                       }
+                               if (bytesurfacepvs[i] && BoxesOverlap(surf->poly_mins, surf->poly_maxs, e->mins, e->maxs))
+                                       surf->castshadow = castshadowcount;
 
                        Mem_Free(byteleafpvs);
                        Mem_Free(bytesurfacepvs);
@@ -1127,37 +1515,14 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style
                        pvs = Mod_LeafPVS(leaf, cl.worldmodel);
                        for (i = 0, leaf = cl.worldmodel->leafs + 1;i < cl.worldmodel->numleafs;i++, leaf++)
                        {
-                               if (pvs[i >> 3] & (1 << (i & 7)))
+                               if (pvs[i >> 3] & (1 << (i & 7)) && BoxesOverlap(leaf->mins, leaf->maxs, e->mins, e->maxs))
                                {
-                                       VectorCopy(origin, temp);
-                                       if (temp[0] < leaf->mins[0]) temp[0] = leaf->mins[0];
-                                       if (temp[0] > leaf->maxs[0]) temp[0] = leaf->maxs[0];
-                                       if (temp[1] < leaf->mins[1]) temp[1] = leaf->mins[1];
-                                       if (temp[1] > leaf->maxs[1]) temp[1] = leaf->maxs[1];
-                                       if (temp[2] < leaf->mins[2]) temp[2] = leaf->mins[2];
-                                       if (temp[2] > leaf->maxs[2]) temp[2] = leaf->maxs[2];
-                                       VectorSubtract(temp, origin, temp);
-                                       if (DotProduct(temp, temp) < e->lightradius * e->lightradius)
+                                       leaf->worldnodeframe = castshadowcount;
+                                       for (j = 0, mark = leaf->firstmarksurface;j < leaf->nummarksurfaces;j++, mark++)
                                        {
-                                               leaf->worldnodeframe = castshadowcount;
-                                               for (j = 0, mark = leaf->firstmarksurface;j < leaf->nummarksurfaces;j++, mark++)
-                                               {
-                                                       surf = cl.worldmodel->surfaces + *mark;
-                                                       if (surf->castshadow != castshadowcount)
-                                                       {
-                                                               f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
-                                                               if (surf->flags & SURF_PLANEBACK)
-                                                                       f = -f;
-                                                               if (f > 0 && f < e->lightradius)
-                                                               {
-                                                                       temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
-                                                                       temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
-                                                                       temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
-                                                                       if (DotProduct(temp, temp) < e->lightradius * e->lightradius)
-                                                                               surf->castshadow = castshadowcount;
-                                                               }
-                                                       }
-                                               }
+                                               surf = cl.worldmodel->surfaces + *mark;
+                                               if (surf->castshadow != castshadowcount && BoxesOverlap(surf->poly_mins, surf->poly_maxs, e->mins, e->maxs))
+                                                       surf->castshadow = castshadowcount;
                                        }
                                }
                        }
@@ -1184,34 +1549,26 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style
                for (i = 0, surf = cl.worldmodel->surfaces + cl.worldmodel->firstmodelsurface;i < cl.worldmodel->nummodelsurfaces;i++, surf++)
                        if (surf->castshadow == castshadowcount)
                                e->surfaces[e->numsurfaces++] = surf;
-               // find bounding box and sphere of lit surfaces
-               // (these will be used for creating a shape to clip the light)
-               radius2 = 0;
+
+               // find bounding box of lit leafs
                VectorCopy(e->origin, e->mins);
                VectorCopy(e->origin, e->maxs);
-               for (j = 0;j < e->numsurfaces;j++)
+               for (j = 0;j < e->numleafs;j++)
                {
-                       surf = e->surfaces[j];
-                       for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
+                       leaf = e->leafs[j];
+                       for (k = 0;k < 3;k++)
                        {
-                               if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
-                               if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
-                               if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
-                               VectorSubtract(v, e->origin, temp);
-                               f = DotProduct(temp, temp);
-                               if (radius2 < f)
-                                       radius2 = f;
+                               if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k];
+                               if (e->maxs[k] < leaf->maxs[k]) e->maxs[k] = leaf->maxs[k];
                        }
                }
-               e->cullradius = sqrt(radius2);
-               if (e->cullradius > e->lightradius)
-                       e->cullradius = e->lightradius;
-               if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
-               if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
-               if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
-               if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
-               if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
-               if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
+
+               for (k = 0;k < 3;k++)
+               {
+                       if (e->mins[k] < e->origin[k] - e->lightradius) e->mins[k] = e->origin[k] - e->lightradius;
+                       if (e->maxs[k] > e->origin[k] + e->lightradius) e->maxs[k] = e->origin[k] + e->lightradius;
+               }
+               e->cullradius = RadiusFromBoundsAndOrigin(e->mins, e->maxs, e->origin);
 
                if (e->castshadows)
                {
index 1c6ded7..46dac70 100644 (file)
@@ -12,8 +12,8 @@ extern cvar_t r_shadow_bumpscale_basetexture;
 
 void R_Shadow_Init(void);
 void R_Shadow_Volume(int numverts, int numtris, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance);
-void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, float lightradius, const float *lightcolor, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap);
-void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap);
+void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, float lightradius, const float *lightcolor, const matrix4x4_t *matrix_worldtofilter, const matrix4x4_t *matrix_worldtoattenuationxyz, const matrix4x4_t *matrix_worldtoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap);
+void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, const matrix4x4_t *matrix_worldtofilter, const matrix4x4_t *matrix_worldtoattenuationxyz, const matrix4x4_t *matrix_worldtoattenuationz, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap);
 void R_Shadow_ClearStencil(void);
 
 void R_Shadow_RenderVolume(int numverts, int numtris, int *elements);
@@ -23,7 +23,8 @@ void R_Shadow_Stage_ShadowVolumes(void);
 void R_Shadow_Stage_LightWithShadows(void);
 void R_Shadow_Stage_LightWithoutShadows(void);
 void R_Shadow_Stage_End(void);
-int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const float *origin, float radius);
+//int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const float *origin, float radius);
+int R_Shadow_ScissorForBBox(const float *mins, const float *maxs);
 
 typedef struct worldlight_s
 {
@@ -31,9 +32,22 @@ typedef struct worldlight_s
        vec3_t origin;
        vec_t lightradius;
        vec3_t light;
+       vec3_t angles;
        int castshadows;
        char *cubemapname;
 
+       // shadow volumes are done entirely in model space, so there are no matrices for dealing with them...
+
+       // note that the world to light matrices are inversely scaled (divided) by lightradius
+
+       // matrix for transforming world coordinates to light filter coordinates
+       //matrix4x4_t matrix_worldtofilter;
+       // based on worldtofilter this transforms -1 to +1 to 0 to 1 for purposes
+       // of attenuation texturing in full 3D (z result often ignored)
+       //matrix4x4_t matrix_worldtoattenuationxyz;
+       // this transforms only the Z to S, and T is always 0.5
+       //matrix4x4_t matrix_worldtoattenuationz;
+
        // generated properties
        vec3_t mins;
        vec3_t maxs;