massive coding has been done on shadow volumes (some scrapped code which will be...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 3 Oct 2002 17:11:24 +0000 (17:11 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 3 Oct 2002 17:11:24 +0000 (17:11 +0000)
some model fixes relating to gl_combine - r_quickmodels is gone
off-screen models were not being culled (oops)

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

13 files changed:
gl_models.c
gl_rmain.c
gl_rsurf.c
model_alias.c
model_brush.c
model_brush.h
model_shared.c
model_shared.h
model_sprite.c
r_light.c
r_light.h
r_shadow.c
r_shadow.h

index a3af200..ceb9b5b 100644 (file)
@@ -3,8 +3,6 @@
 #include "cl_collision.h"
 #include "r_shadow.h"
 
-cvar_t r_quickmodels = {0, "r_quickmodels", "1"};
-
 typedef struct
 {
        float m[3][4];
@@ -47,33 +45,9 @@ void gl_models_newmap(void)
 
 void GL_Models_Init(void)
 {
-       Cvar_RegisterVariable(&r_quickmodels);
-
        R_RegisterModule("GL_Models", gl_models_start, gl_models_shutdown, gl_models_newmap);
 }
 
-/*
-void R_AliasTransformVerts(int vertcount)
-{
-       vec3_t point;
-       float *av;
-       av = aliasvert;
-       while (vertcount >= 4)
-       {
-               VectorCopy(av, point);softwaretransform(point, av);av += 4;
-               VectorCopy(av, point);softwaretransform(point, av);av += 4;
-               VectorCopy(av, point);softwaretransform(point, av);av += 4;
-               VectorCopy(av, point);softwaretransform(point, av);av += 4;
-               vertcount -= 4;
-       }
-       while(vertcount > 0)
-       {
-               VectorCopy(av, point);softwaretransform(point, av);av += 4;
-               vertcount--;
-       }
-}
-*/
-
 void R_AliasLerpVerts(int vertcount, float *vertices, float *normals,
                float lerp1, const trivertx_t *verts1, const vec3_t fscale1, const vec3_t translate1,
                float lerp2, const trivertx_t *verts2, const vec3_t fscale2, const vec3_t translate2,
@@ -237,9 +211,9 @@ void R_LerpMDLMD2Vertices(const entity_render_t *ent, float *vertices, float *no
 
 void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2)
 {
-       int i, c, pantsfullbright, shirtfullbright, colormapped, tex;
+       int i, c, fullbright, pantsfullbright, shirtfullbright, colormapped, tex;
        float pantscolor[3], shirtcolor[3];
-       float fog, colorscale;
+       float fog, ifog, colorscale;
        vec3_t diff;
        qbyte *bcolor;
        rmeshstate_t m;
@@ -248,9 +222,15 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2)
        const entity_render_t *ent = calldata1;
        int blendfunc1, blendfunc2;
 
-//     softwaretransformforentity(ent);
        R_Mesh_Matrix(&ent->matrix);
 
+       model = ent->model;
+       R_Mesh_ResizeCheck(model->numverts);
+
+       skinframe = R_FetchSkinFrame(ent);
+
+       fullbright = (ent->effects & EF_FULLBRIGHT) != 0;
+
        fog = 0;
        if (fogenabled)
        {
@@ -267,11 +247,7 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2)
                // 1. render model as normal, scaled by inverse of fog alpha (darkens it)
                // 2. render fog as additive
        }
-
-       model = ent->model;
-       R_Mesh_ResizeCheck(model->numverts);
-
-       skinframe = R_FetchSkinFrame(ent);
+       ifog = 1 - fog;
 
        if (ent->effects & EF_ADDITIVE)
        {
@@ -289,64 +265,31 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2)
                blendfunc2 = GL_ZERO;
        }
 
-       colorscale = r_colorscale;
-       if (gl_combine.integer)
-               colorscale *= 0.25f;
-
        if (!skinframe->base && !skinframe->pants && !skinframe->shirt && !skinframe->glow)
        {
                // untextured
                memset(&m, 0, sizeof(m));
                m.blendfunc1 = blendfunc1;
                m.blendfunc2 = blendfunc2;
+               colorscale = r_colorscale;
                if (gl_combine.integer)
+               {
+                       colorscale *= 0.25f;
                        m.texrgbscale[0] = 4;
+               }
                m.tex[0] = R_GetTexture(r_notexture);
                R_Mesh_State(&m);
-
                c_alias_polys += model->numtris;
                for (i = 0;i < model->numverts * 2;i++)
                        varray_texcoord[0][i] = model->mdlmd2data_texcoords[i] * 8.0f;
-               aliasvert = varray_vertex;
-               aliasvertcolor = varray_color;
-               R_LerpMDLMD2Vertices(ent, aliasvert, aliasvertnorm);
-               R_LightModel(ent, model->numverts, colorscale, colorscale, colorscale, false);
-               aliasvert = aliasvertbuf;
-               aliasvertcolor = aliasvertcolorbuf;
+               R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm);
+               R_LightModel(ent, model->numverts, varray_vertex, aliasvertnorm, varray_color, colorscale, colorscale, colorscale, false);
                GL_UseColorArray();
                R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
                return;
        }
 
-
        colormapped = !skinframe->merged || (ent->colormap >= 0 && skinframe->base && (skinframe->pants || skinframe->shirt));
-       if (r_quickmodels.integer && !colormapped && !fog && !skinframe->glow && !skinframe->fog)
-       {
-               // fastpath for the normal situation (one texture)
-               memset(&m, 0, sizeof(m));
-               m.blendfunc1 = blendfunc1;
-               m.blendfunc2 = blendfunc2;
-               if (gl_combine.integer)
-                       m.texrgbscale[0] = 4;
-               m.tex[0] = R_GetTexture(skinframe->merged);
-               R_Mesh_State(&m);
-
-               c_alias_polys += model->numtris;
-               memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2]));
-               aliasvert = varray_vertex;
-               aliasvertcolor = varray_color;
-               R_LerpMDLMD2Vertices(ent, aliasvert, aliasvertnorm);
-               R_LightModel(ent, model->numverts, colorscale, colorscale, colorscale, false);
-               aliasvert = aliasvertbuf;
-               aliasvertcolor = aliasvertcolorbuf;
-               GL_UseColorArray();
-               R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
-               return;
-       }
-
-       R_LerpMDLMD2Vertices(ent, aliasvert, aliasvertnorm);
-       R_LightModel(ent, model->numverts, colorscale * (1 - fog), colorscale * (1 - fog), colorscale * (1 - fog), false);
-
        if (colormapped)
        {
                // 128-224 are backwards ranges
@@ -371,19 +314,27 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2)
                memset(&m, 0, sizeof(m));
                m.blendfunc1 = blendfunc1;
                m.blendfunc2 = blendfunc2;
+               colorscale = r_colorscale;
                if (gl_combine.integer)
+               {
+                       colorscale *= 0.25f;
                        m.texrgbscale[0] = 4;
+               }
                m.tex[0] = tex;
                R_Mesh_State(&m);
-
-               blendfunc1 = GL_SRC_ALPHA;
-               blendfunc2 = GL_ONE;
-               c_alias_polys += model->numtris;
-               R_ModulateColors(aliasvertcolor, varray_color, model->numverts, colorscale, colorscale, colorscale);
-               memcpy(varray_vertex, aliasvert, model->numverts * sizeof(float[4]));
+               R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm);
                memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2]));
-               GL_UseColorArray();
+               if (fullbright)
+                       GL_Color(colorscale * ifog, colorscale * ifog, colorscale * ifog, ent->alpha);
+               else
+               {
+                       GL_UseColorArray();
+                       R_LightModel(ent, model->numverts, varray_vertex, aliasvertnorm, varray_color, colorscale * ifog, colorscale * ifog, colorscale * ifog, false);
+               }
                R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
+               c_alias_polys += model->numtris;
+               blendfunc1 = GL_SRC_ALPHA;
+               blendfunc2 = GL_ONE;
        }
 
        if (colormapped)
@@ -396,24 +347,27 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2)
                                memset(&m, 0, sizeof(m));
                                m.blendfunc1 = blendfunc1;
                                m.blendfunc2 = blendfunc2;
+                               colorscale = r_colorscale;
                                if (gl_combine.integer)
+                               {
+                                       colorscale *= 0.25f;
                                        m.texrgbscale[0] = 4;
+                               }
                                m.tex[0] = tex;
                                R_Mesh_State(&m);
-
-                               blendfunc1 = GL_SRC_ALPHA;
-                               blendfunc2 = GL_ONE;
-                               c_alias_polys += model->numtris;
+                               R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm);
+                               memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2]));
                                if (pantsfullbright)
-                                       GL_Color(pantscolor[0] * colorscale, pantscolor[1] * colorscale, pantscolor[2] * colorscale, ent->alpha);
+                                       GL_Color(pantscolor[0] * colorscale * ifog, pantscolor[1] * colorscale * ifog, pantscolor[2] * colorscale * ifog, ent->alpha);
                                else
                                {
                                        GL_UseColorArray();
-                                       R_ModulateColors(aliasvertcolor, varray_color, model->numverts, pantscolor[0] * colorscale, pantscolor[1] * colorscale, pantscolor[2] * colorscale);
+                                       R_LightModel(ent, model->numverts, varray_vertex, aliasvertnorm, varray_color, pantscolor[0] * colorscale * ifog, pantscolor[1] * colorscale * ifog, pantscolor[2] * colorscale * ifog, false);
                                }
-                               memcpy(varray_vertex, aliasvert, model->numverts * sizeof(float[4]));
-                               memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2]));
                                R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
+                               c_alias_polys += model->numtris;
+                               blendfunc1 = GL_SRC_ALPHA;
+                               blendfunc2 = GL_ONE;
                        }
                }
                if (skinframe->shirt)
@@ -424,24 +378,27 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2)
                                memset(&m, 0, sizeof(m));
                                m.blendfunc1 = blendfunc1;
                                m.blendfunc2 = blendfunc2;
+                               colorscale = r_colorscale;
                                if (gl_combine.integer)
+                               {
+                                       colorscale *= 0.25f;
                                        m.texrgbscale[0] = 4;
+                               }
                                m.tex[0] = tex;
                                R_Mesh_State(&m);
-
-                               blendfunc1 = GL_SRC_ALPHA;
-                               blendfunc2 = GL_ONE;
-                               c_alias_polys += model->numtris;
+                               R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm);
+                               memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2]));
                                if (shirtfullbright)
-                                       GL_Color(shirtcolor[0] * colorscale, shirtcolor[1] * colorscale, shirtcolor[2] * colorscale, ent->alpha);
+                                       GL_Color(shirtcolor[0] * colorscale * ifog, shirtcolor[1] * colorscale * ifog, shirtcolor[2] * colorscale * ifog, ent->alpha);
                                else
                                {
                                        GL_UseColorArray();
-                                       R_ModulateColors(aliasvertcolor, varray_color, model->numverts, shirtcolor[0] * colorscale, shirtcolor[1] * colorscale, shirtcolor[2] * colorscale);
+                                       R_LightModel(ent, model->numverts, varray_vertex, aliasvertnorm, varray_color, shirtcolor[0] * colorscale * ifog, shirtcolor[1] * colorscale * ifog, shirtcolor[2] * colorscale * ifog, false);
                                }
-                               memcpy(varray_vertex, aliasvert, model->numverts * sizeof(float[4]));
-                               memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2]));
                                R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
+                               c_alias_polys += model->numtris;
+                               blendfunc1 = GL_SRC_ALPHA;
+                               blendfunc2 = GL_ONE;
                        }
                }
        }
@@ -459,9 +416,9 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2)
                        blendfunc1 = GL_SRC_ALPHA;
                        blendfunc2 = GL_ONE;
                        c_alias_polys += model->numtris;
-                       memcpy(varray_vertex, aliasvert, model->numverts * sizeof(float[4]));
+                       R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm);
                        memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2]));
-                       GL_Color((1 - fog) * r_colorscale, (1 - fog) * r_colorscale, (1 - fog) * r_colorscale, ent->alpha);
+                       GL_Color(ifog * r_colorscale, ifog * r_colorscale, ifog * r_colorscale, ent->alpha);
                        R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
                }
        }
@@ -474,13 +431,25 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2)
                R_Mesh_State(&m);
 
                c_alias_polys += model->numtris;
-               memcpy(varray_vertex, aliasvert, model->numverts * sizeof(float[4]));
+               R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm);
                memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2]));
                GL_Color(fogcolor[0] * fog * r_colorscale, fogcolor[1] * fog * r_colorscale, fogcolor[2] * fog * r_colorscale, ent->alpha);
                R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
        }
 }
 
+void R_DrawQ1Q2AliasModelShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume)
+{
+       float projectdistance;
+       projectdistance = lightradius + ent->model->radius - sqrt(DotProduct(relativelightorigin, relativelightorigin));
+       if (projectdistance > 0.1)
+       {
+               R_Mesh_ResizeCheck(ent->model->numverts * 2);
+               R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm);
+               R_Shadow_Volume(ent->model->numverts, ent->model->numtris, varray_vertex, ent->model->mdlmd2data_indices, ent->model->mdlmd2data_triangleneighbors, relativelightorigin, lightradius, projectdistance, visiblevolume);
+       }
+}
+
 extern cvar_t r_shadows;
 void R_DrawQ1Q2AliasModelFakeShadow (entity_render_t *ent)
 {
@@ -488,13 +457,14 @@ void R_DrawQ1Q2AliasModelFakeShadow (entity_render_t *ent)
        rmeshstate_t m;
        model_t *model;
        float *v, planenormal[3], planedist, dist, projection[3], floororigin[3], surfnormal[3], lightdirection[3], v2[3];
-       mlight_t *sl;
-       rdlight_t *rd;
 
+       /*
        if (r_shadows.integer > 1)
        {
                float f, lightscale, lightcolor[3];
                vec3_t temp;
+               mlight_t *sl;
+               rdlight_t *rd;
                memset(&m, 0, sizeof(m));
                m.blendfunc1 = GL_ONE;
                m.blendfunc2 = GL_ONE;
@@ -544,6 +514,7 @@ void R_DrawQ1Q2AliasModelFakeShadow (entity_render_t *ent)
                }
                return;
        }
+       */
 
        lightdirection[0] = 0.5;
        lightdirection[1] = 0.2;
@@ -599,21 +570,6 @@ int ZymoticLerpBones(int count, const zymbonematrix *bonebase, const frameblend_
        zymbonematrix *out, rootmatrix, m;
        const zymbonematrix *bone1, *bone2, *bone3, *bone4;
 
-       /*
-       // LordHavoc: combine transform from zym coordinate space to quake coordinate space with model to world transform matrix
-       rootmatrix.m[0][0] = softwaretransform_matrix[0][1];
-       rootmatrix.m[0][1] = -softwaretransform_matrix[0][0];
-       rootmatrix.m[0][2] = softwaretransform_matrix[0][2];
-       rootmatrix.m[0][3] = softwaretransform_matrix[0][3];
-       rootmatrix.m[1][0] = softwaretransform_matrix[1][1];
-       rootmatrix.m[1][1] = -softwaretransform_matrix[1][0];
-       rootmatrix.m[1][2] = softwaretransform_matrix[1][2];
-       rootmatrix.m[1][3] = softwaretransform_matrix[1][3];
-       rootmatrix.m[2][0] = softwaretransform_matrix[2][1];
-       rootmatrix.m[2][1] = -softwaretransform_matrix[2][0];
-       rootmatrix.m[2][2] = softwaretransform_matrix[2][2];
-       rootmatrix.m[2][3] = softwaretransform_matrix[2][3];
-       */
        rootmatrix.m[0][0] = 1;
        rootmatrix.m[0][1] = 0;
        rootmatrix.m[0][2] = 0;
@@ -771,10 +727,10 @@ int ZymoticLerpBones(int count, const zymbonematrix *bonebase, const frameblend_
        return true;
 }
 
-void ZymoticTransformVerts(int vertcount, int *bonecounts, zymvertex_t *vert)
+void ZymoticTransformVerts(int vertcount, float *vertex, int *bonecounts, zymvertex_t *vert)
 {
        int c;
-       float *out = aliasvert;
+       float *out = vertex;
        zymbonematrix *matrix;
        while(vertcount--)
        {
@@ -805,13 +761,13 @@ void ZymoticTransformVerts(int vertcount, int *bonecounts, zymvertex_t *vert)
        }
 }
 
-void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist)
+void ZymoticCalcNormals(int vertcount, float *vertex, float *normals, int shadercount, int *renderlist)
 {
        int a, b, c, d;
        float *out, v1[3], v2[3], normal[3], s;
        int *u;
        // clear normals
-       memset(aliasvertnorm, 0, sizeof(float) * vertcount * 3);
+       memset(normals, 0, sizeof(float) * vertcount * 3);
        memset(aliasvertusage, 0, sizeof(int) * vertcount);
        // parse render list and accumulate surface normals
        while(shadercount--)
@@ -822,36 +778,36 @@ void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist)
                        a = renderlist[0]*4;
                        b = renderlist[1]*4;
                        c = renderlist[2]*4;
-                       v1[0] = aliasvert[a+0] - aliasvert[b+0];
-                       v1[1] = aliasvert[a+1] - aliasvert[b+1];
-                       v1[2] = aliasvert[a+2] - aliasvert[b+2];
-                       v2[0] = aliasvert[c+0] - aliasvert[b+0];
-                       v2[1] = aliasvert[c+1] - aliasvert[b+1];
-                       v2[2] = aliasvert[c+2] - aliasvert[b+2];
+                       v1[0] = vertex[a+0] - vertex[b+0];
+                       v1[1] = vertex[a+1] - vertex[b+1];
+                       v1[2] = vertex[a+2] - vertex[b+2];
+                       v2[0] = vertex[c+0] - vertex[b+0];
+                       v2[1] = vertex[c+1] - vertex[b+1];
+                       v2[2] = vertex[c+2] - vertex[b+2];
                        CrossProduct(v1, v2, normal);
                        VectorNormalizeFast(normal);
                        // add surface normal to vertices
                        a = renderlist[0] * 3;
-                       aliasvertnorm[a+0] += normal[0];
-                       aliasvertnorm[a+1] += normal[1];
-                       aliasvertnorm[a+2] += normal[2];
+                       normals[a+0] += normal[0];
+                       normals[a+1] += normal[1];
+                       normals[a+2] += normal[2];
                        aliasvertusage[renderlist[0]]++;
                        a = renderlist[1] * 3;
-                       aliasvertnorm[a+0] += normal[0];
-                       aliasvertnorm[a+1] += normal[1];
-                       aliasvertnorm[a+2] += normal[2];
+                       normals[a+0] += normal[0];
+                       normals[a+1] += normal[1];
+                       normals[a+2] += normal[2];
                        aliasvertusage[renderlist[1]]++;
                        a = renderlist[2] * 3;
-                       aliasvertnorm[a+0] += normal[0];
-                       aliasvertnorm[a+1] += normal[1];
-                       aliasvertnorm[a+2] += normal[2];
+                       normals[a+0] += normal[0];
+                       normals[a+1] += normal[1];
+                       normals[a+2] += normal[2];
                        aliasvertusage[renderlist[2]]++;
                        renderlist += 3;
                }
        }
        // FIXME: precalc this
        // average surface normals
-       out = aliasvertnorm;
+       out = normals;
        u = aliasvertusage;
        while(vertcount--)
        {
@@ -869,7 +825,7 @@ void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist)
 
 void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2)
 {
-       float fog, colorscale;
+       float fog, ifog, colorscale;
        vec3_t diff;
        int i, *renderlist, *elements;
        zymtype1header_t *m;
@@ -909,12 +865,7 @@ void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2)
                // 1. render model as normal, scaled by inverse of fog alpha (darkens it)
                // 2. render fog as additive
        }
-
-       ZymoticLerpBones(m->numbones, (zymbonematrix *)(m->lump_poses.start + (int) m), ent->frameblend, (zymbone_t *)(m->lump_bones.start + (int) m));
-       ZymoticTransformVerts(numverts, (int *)(m->lump_vertbonecounts.start + (int) m), (zymvertex_t *)(m->lump_verts.start + (int) m));
-       ZymoticCalcNormals(numverts, m->numshaders, (int *)(m->lump_render.start + (int) m));
-
-       R_LightModel(ent, numverts, 1 - fog, 1 - fog, 1 - fog, false);
+       ifog = 1 - fog;
 
        memset(&mstate, 0, sizeof(mstate));
        if (ent->effects & EF_ADDITIVE)
@@ -940,13 +891,14 @@ void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2)
        }
        mstate.tex[0] = R_GetTexture(texture);
        R_Mesh_State(&mstate);
-
-       c_alias_polys += numtriangles;
-       memcpy(varray_vertex, aliasvert, numverts * sizeof(float[4]));
-       R_ModulateColors(aliasvertcolor, varray_color, numverts, colorscale, colorscale, colorscale);
+       ZymoticLerpBones(m->numbones, (zymbonematrix *)(m->lump_poses.start + (int) m), ent->frameblend, (zymbone_t *)(m->lump_bones.start + (int) m));
+       ZymoticTransformVerts(numverts, varray_vertex, (int *)(m->lump_vertbonecounts.start + (int) m), (zymvertex_t *)(m->lump_verts.start + (int) m));
+       ZymoticCalcNormals(numverts, varray_vertex, aliasvertnorm, m->numshaders, (int *)(m->lump_render.start + (int) m));
        memcpy(varray_texcoord[0], (float *)(m->lump_texcoords.start + (int) m), numverts * sizeof(float[2]));
        GL_UseColorArray();
+       R_LightModel(ent, numverts, varray_vertex, aliasvertnorm, varray_color, ifog * colorscale, ifog * colorscale, ifog * colorscale, false);
        R_Mesh_Draw(numverts, numtriangles, elements);
+       c_alias_polys += numtriangles;
 
        if (fog)
        {
@@ -956,12 +908,9 @@ void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2)
                // FIXME: need alpha mask for fogging...
                //mstate.tex[0] = R_GetTexture(texture);
                R_Mesh_State(&mstate);
-
-               c_alias_polys += numtriangles;
-               memcpy(varray_vertex, aliasvert, numverts * sizeof(float[4]));
-               //memcpy(mesh_texcoord[0], (float *)(m->lump_texcoords.start + (int) m), numverts * sizeof(float[2]));
                GL_Color(fogcolor[0] * r_colorscale, fogcolor[1] * r_colorscale, fogcolor[2] * r_colorscale, ent->alpha * fog);
                R_Mesh_Draw(numverts, numtriangles, elements);
+               c_alias_polys += numtriangles;
        }
 }
 
index 184af30..7ab983c 100644 (file)
@@ -460,7 +460,6 @@ static void R_MarkEntities (void)
                        VectorAdd(ent->angles, r_refdef.viewangles, ent->angles);
                }
 
-               ent->visframe = r_framecount;
                VectorCopy(ent->angles, v);
                if (!ent->model || ent->model->type != mod_brush)
                        v[0] = -v[0];
@@ -468,9 +467,11 @@ static void R_MarkEntities (void)
                Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
                R_LerpAnimation(ent);
                R_UpdateEntLights(ent);
-               if (R_CullBox(ent->mins, ent->maxs))
-                       continue;
-               R_FarClip_Box(ent->mins, ent->maxs);
+               if (R_NotCulledBox(ent->mins, ent->maxs))
+               {
+                       ent->visframe = r_framecount;
+                       R_FarClip_Box(ent->mins, ent->maxs);
+               }
        }
 }
 
@@ -549,12 +550,12 @@ void R_DrawFakeShadows (void)
        int i;
        entity_render_t *ent;
 
-       if (!r_drawentities.integer)
-               return;
-
        ent = &cl_entities[0].render;
        if (ent->model && ent->model->DrawFakeShadow)
                ent->model->DrawFakeShadow(ent);
+
+       if (!r_drawentities.integer)
+               return;
        for (i = 0;i < r_refdef.numentities;i++)
        {
                ent = r_refdef.entities[i];
@@ -563,6 +564,204 @@ void R_DrawFakeShadows (void)
        }
 }
 
+void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float lightradius, int visiblevolume)
+{
+       int i;
+       vec3_t p, p2, temp, relativelightorigin;
+       float dist, projectdistance;
+       // rough checks
+       if (ent->model && ent->model->DrawShadowVolume)
+       {
+               temp[0] = bound(ent->mins[0], lightorigin[0], ent->maxs[0]) - lightorigin[0];
+               temp[1] = bound(ent->mins[1], lightorigin[1], ent->maxs[1]) - lightorigin[1];
+               temp[2] = bound(ent->mins[2], lightorigin[2], ent->maxs[2]) - lightorigin[2];
+               dist = DotProduct(temp, temp);
+               if (dist < lightradius * lightradius)
+               {
+                       projectdistance = lightradius - sqrt(dist);
+                       {
+#if 0
+                       int d0, d1, d2, d3;
+                       // calculate projected bounding box and decide if it is on-screen
+                       d0 = false;
+                       d1 = false;
+                       d2 = false;
+                       d3 = false;
+                       for (i = 0;i < 8;i++)
+                       {
+                               p[0] = i & 1 ? ent->maxs[0] : ent->mins[0];
+                               p[1] = i & 2 ? ent->maxs[1] : ent->mins[1];
+                               p[2] = i & 4 ? ent->maxs[2] : ent->mins[2];
+                               VectorSubtract(p, lightorigin, temp);
+                               dist = projectdistance / sqrt(DotProduct(temp, temp));
+                               VectorMA(p, dist, temp, p2);
+                               if (!d0 && (DotProduct(p , frustum[0].normal) < frustum[0].dist || DotProduct(p2, frustum[0].normal) < frustum[0].dist))
+                                       d0 = true;
+                               if (!d1 && (DotProduct(p , frustum[1].normal) < frustum[1].dist || DotProduct(p2, frustum[1].normal) < frustum[1].dist))
+                                       d1 = true;
+                               if (!d2 && (DotProduct(p , frustum[2].normal) < frustum[2].dist || DotProduct(p2, frustum[2].normal) < frustum[2].dist))
+                                       d2 = true;
+                               if (!d3 && (DotProduct(p , frustum[3].normal) < frustum[3].dist || DotProduct(p2, frustum[3].normal) < frustum[3].dist))
+                                       d3 = true;
+                       }
+                       if (d0 && d1 && d2 && d3)
+#else
+                       vec3_t mins, maxs;
+                       // calculate projected bounding box and decide if it is on-screen
+                       VectorCopy(ent->mins, mins);
+                       VectorCopy(ent->maxs, maxs);
+                       for (i = 0;i < 8;i++)
+                       {
+                               p[0] = i & 1 ? ent->maxs[0] : ent->mins[0];
+                               p[1] = i & 2 ? ent->maxs[1] : ent->mins[1];
+                               p[2] = i & 4 ? ent->maxs[2] : ent->mins[2];
+                               VectorSubtract(p, lightorigin, temp);
+                               dist = projectdistance / sqrt(DotProduct(temp, temp));
+                               VectorMA(p, dist, temp, p2);
+                               if (mins[0] > p2[0]) mins[0] = p2[0];if (maxs[0] < p2[0]) maxs[0] = p2[0];
+                               if (mins[1] > p2[1]) mins[1] = p2[1];if (maxs[1] < p2[1]) maxs[1] = p2[1];
+                               if (mins[2] > p2[2]) mins[2] = p2[2];if (maxs[2] < p2[2]) maxs[2] = p2[2];
+                       }
+                       if (R_NotCulledBox(mins, maxs))
+#endif
+                       {
+                               Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
+                               R_Mesh_Matrix(&ent->matrix);
+                               ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius, visiblevolume);
+                       }
+                       }
+               }
+       }
+}
+
+void R_DrawWorldLightShadowVolume(mlight_t *sl)
+{
+       shadowmesh_t *mesh;
+       R_Mesh_Matrix(&cl_entities[0].render.matrix);
+       for (mesh = sl->shadowvolume;mesh;mesh = mesh->next)
+       {
+               memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
+               R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->elements);
+       }
+}
+
+void R_DrawShadowVolumes (void)
+{
+       int i, lnum;
+       entity_render_t *ent;
+       vec3_t mins, maxs;//, relativelightorigin;
+       mlight_t *sl;
+       rdlight_t *rd;
+       rmeshstate_t m;
+
+       for (lnum = 0, sl = cl.worldmodel->lights;lnum < cl.worldmodel->numlights;lnum++, sl++)
+       {
+               if (d_lightstylevalue[sl->style] <= 0)
+                       continue;
+               mins[0] = sl->origin[0] - sl->cullradius;
+               maxs[0] = sl->origin[0] + sl->cullradius;
+               mins[1] = sl->origin[1] - sl->cullradius;
+               maxs[1] = sl->origin[1] + sl->cullradius;
+               mins[2] = sl->origin[2] - sl->cullradius;
+               maxs[2] = sl->origin[2] + sl->cullradius;
+               if (R_CullBox(mins, maxs))
+                       continue;
+               memset(&m, 0, sizeof(m));
+               m.blendfunc1 = GL_ONE;
+               m.blendfunc2 = GL_ONE;
+               R_Mesh_State(&m);
+               GL_Color(0.0 * r_colorscale, 0.0125 * r_colorscale, 0.1 * r_colorscale, 1);
+               if (sl->shadowvolume)
+                       R_DrawWorldLightShadowVolume(sl);
+               else
+               {
+                       ent = &cl_entities[0].render;
+                       R_TestAndDrawShadowVolume(ent, sl->origin, sl->cullradius, true);
+               }
+               /*
+               ent = &cl_entities[0].render;
+               if (ent->model && ent->model->DrawShadowVolume && ent->maxs[0] >= mins[0] && ent->mins[0] <= maxs[0] && ent->maxs[1] >= mins[1] && ent->mins[1] <= maxs[1] && ent->maxs[2] >= mins[2] && ent->mins[2] <= maxs[2])
+               {
+                       Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin);
+                       R_Mesh_Matrix(&ent->matrix);
+                       ent->model->DrawShadowVolume (ent, relativelightorigin, sl->cullradius, true);
+               }
+               */
+               if (r_drawentities.integer)
+               {
+                       for (i = 0;i < r_refdef.numentities;i++)
+                       {
+                               ent = r_refdef.entities[i];
+                               /*
+                               if (ent->mins[0] <= sl->maxs[0]
+                                && ent->maxs[0] >= sl->mins[0]
+                                && ent->mins[1] <= sl->maxs[1]
+                                && ent->maxs[1] >= sl->mins[1]
+                                && ent->mins[2] <= sl->maxs[2]
+                                && ent->maxs[2] >= sl->mins[2])
+                               */
+                                       R_TestAndDrawShadowVolume(ent, sl->origin, sl->cullradius, true);
+                               /*
+                               ent = r_refdef.entities[i];
+                               if (ent->model && ent->model->DrawShadowVolume && ent->maxs[0] >= mins[0] && ent->mins[0] <= maxs[0] && ent->maxs[1] >= mins[1] && ent->mins[1] <= maxs[1] && ent->maxs[2] >= mins[2] && ent->mins[2] <= maxs[2])
+                               {
+                                       Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin);
+                                       R_Mesh_Matrix(&ent->matrix);
+                                       ent->model->DrawShadowVolume (ent, relativelightorigin, sl->cullradius, true);
+                               }
+                               */
+                       }
+               }
+       }
+
+       for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
+       {
+               mins[0] = rd->origin[0] - rd->cullradius;
+               maxs[0] = rd->origin[0] + rd->cullradius;
+               mins[1] = rd->origin[1] - rd->cullradius;
+               maxs[1] = rd->origin[1] + rd->cullradius;
+               mins[2] = rd->origin[2] - rd->cullradius;
+               maxs[2] = rd->origin[2] + rd->cullradius;
+               if (R_CullBox(mins, maxs))
+                       continue;
+               memset(&m, 0, sizeof(m));
+               m.blendfunc1 = GL_ONE;
+               m.blendfunc2 = GL_ONE;
+               R_Mesh_State(&m);
+               GL_Color(0.1 * r_colorscale, 0.0125 * r_colorscale, 0.0 * r_colorscale, 1);
+               ent = &cl_entities[0].render;
+               if (ent != rd->ent)
+                       R_TestAndDrawShadowVolume(ent, rd->origin, rd->cullradius, true);
+               /*
+               ent = &cl_entities[0].render;
+               if (ent != rd->ent && ent->model && ent->model->DrawShadowVolume && ent->maxs[0] >= mins[0] && ent->mins[0] <= maxs[0] && ent->maxs[1] >= mins[1] && ent->mins[1] <= maxs[1] && ent->maxs[2] >= mins[2] && ent->mins[2] <= maxs[2])
+               {
+                       Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
+                       R_Mesh_Matrix(&ent->matrix);
+                       ent->model->DrawShadowVolume (ent, relativelightorigin, rd->cullradius, true);
+               }
+               */
+               if (r_drawentities.integer)
+               {
+                       for (i = 0;i < r_refdef.numentities;i++)
+                       {
+                               ent = r_refdef.entities[i];
+                               if (ent != rd->ent)
+                                       R_TestAndDrawShadowVolume(ent, rd->origin, rd->cullradius, true);
+                               /*
+                               ent = r_refdef.entities[i];
+                               if (ent != rd->ent && ent->model && ent->model->DrawShadowVolume && ent->maxs[0] >= mins[0] && ent->mins[0] <= maxs[0] && ent->maxs[1] >= mins[1] && ent->mins[1] <= maxs[1] && ent->maxs[2] >= mins[2] && ent->mins[2] <= maxs[2])
+                               {
+                                       Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
+                                       R_Mesh_Matrix(&ent->matrix);
+                                       ent->model->DrawShadowVolume (ent, relativelightorigin, rd->cullradius, true);
+                               }
+                               */
+                       }
+               }
+       }
+}
+
 static void R_SetFrustum (void)
 {
        int i;
@@ -718,11 +917,16 @@ void R_RenderView (void)
 
        R_MeshQueue_Render();
        R_MeshQueue_EndScene();
-       if (r_shadows.integer)
+       if (r_shadows.integer == 1)
        {
                R_DrawFakeShadows();
                R_TimeReport("fakeshadows");
        }
+       if (r_shadows.integer == 2)
+       {
+               R_DrawShadowVolumes();
+               R_TimeReport("shadowvolumes");
+       }
        R_Mesh_Finish();
        R_TimeReport("meshfinish");
 }
index 37e048c..b6c8051 100644 (file)
@@ -1830,8 +1830,23 @@ void R_DrawBrushModelNormal (entity_render_t *ent)
        R_DrawBrushModel(ent, false, true);
 }
 
-void R_DrawBrushModelShadowVolumes (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume)
+void R_DrawBrushModelShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume)
 {
+#if 0
+       float projectdistance, temp[3];
+       shadowmesh_t *mesh;
+       VectorSubtract(relativelightorigin, ent->model->shadowmesh_center, temp);
+       projectdistance = lightradius + ent->model->shadowmesh_radius - sqrt(DotProduct(temp, temp));
+       if (projectdistance >= 0.1)
+       {
+               for (mesh = ent->model->shadowmesh;mesh;mesh = mesh->next)
+               {
+                       R_Mesh_ResizeCheck(mesh->numverts * 2);
+                       memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
+                       R_Shadow_Volume(mesh->numverts, mesh->numtriangles, varray_vertex, mesh->elements, mesh->neighbors, relativelightorigin, lightradius, projectdistance, visiblevolume);
+               }
+       }
+#else
        int i, numsurfaces;
        msurface_t *surf;
        float projectdistance, f, temp[3], lightradius2;
@@ -1840,30 +1855,29 @@ void R_DrawBrushModelShadowVolumes (entity_render_t *ent, vec3_t relativelightor
        lightradius2 = lightradius * lightradius;
        for (i = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;i < numsurfaces;i++, surf++)
        {
-               VectorSubtract(relativelightorigin, surf->poly_center, temp);
-               if (DotProduct(temp, temp) < (surf->poly_radius2 + lightradius2))
+               f = PlaneDiff(relativelightorigin, surf->plane);
+               if (surf->flags & SURF_PLANEBACK)
+                       f = -f;
+               // draw shadows only for backfaces
+               projectdistance = lightradius + f;
+               if (projectdistance >= 0.1 && projectdistance < lightradius)
                {
-                       f = PlaneDiff(relativelightorigin, surf->plane);
-                       if (surf->flags & SURF_PLANEBACK)
-                               f = -f;
-                       // draw shadows only for backfaces
-                       if (f < 0)
+                       VectorSubtract(relativelightorigin, surf->poly_center, temp);
+                       if (DotProduct(temp, temp) < (surf->poly_radius2 + lightradius2))
                        {
-                               projectdistance = lightradius + f;
-                               if (projectdistance > 0)
+                               for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                                {
-                                       for (mesh = surf->mesh;mesh;mesh = mesh->chain)
-                                       {
-                                               R_Mesh_ResizeCheck(mesh->numverts * 2);
-                                               memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
-                                               R_Shadow_Volume(mesh->numverts, mesh->numtriangles, varray_vertex, mesh->index, mesh->triangleneighbors, relativelightorigin, projectdistance, visiblevolume);
-                                       }
+                                       R_Mesh_ResizeCheck(mesh->numverts * 2);
+                                       memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
+                                       R_Shadow_Volume(mesh->numverts, mesh->numtriangles, varray_vertex, mesh->index, mesh->triangleneighbors, relativelightorigin, lightradius, projectdistance, visiblevolume);
                                }
                        }
                }
        }
+#endif
 }
 
+/*
 extern cvar_t r_shadows;
 void R_DrawBrushModelFakeShadow (entity_render_t *ent)
 {
@@ -1872,6 +1886,7 @@ void R_DrawBrushModelFakeShadow (entity_render_t *ent)
        rmeshstate_t m;
        mlight_t *sl;
        rdlight_t *rd;
+       svbspmesh_t *mesh;
 
        if (r_shadows.integer < 2)
                return;
@@ -1882,18 +1897,35 @@ void R_DrawBrushModelFakeShadow (entity_render_t *ent)
        R_Mesh_State(&m);
        R_Mesh_Matrix(&ent->matrix);
        GL_Color(0.0125 * r_colorscale, 0.025 * r_colorscale, 0.1 * r_colorscale, 1);
-       for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights;i++, sl++)
-       {
-               if (d_lightstylevalue[sl->style] > 0
-                && ent->maxs[0] >= sl->origin[0] - sl->cullradius
-                && ent->mins[0] <= sl->origin[0] + sl->cullradius
-                && ent->maxs[1] >= sl->origin[1] - sl->cullradius
-                && ent->mins[1] <= sl->origin[1] + sl->cullradius
-                && ent->maxs[2] >= sl->origin[2] - sl->cullradius
-                && ent->mins[2] <= sl->origin[2] + sl->cullradius)
+       if (0)//ent->model == cl.worldmodel)
+       {
+               for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights;i++, sl++)
+               {
+                       if (d_lightstylevalue[sl->style] > 0 && R_NotCulledBox(sl->shadowvolumemins, sl->shadowvolumemaxs))
+                       {
+                               for (mesh = sl->shadowvolume;mesh;mesh = mesh->next)
+                               {
+                                       memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
+                                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->elements);
+                               }
+                       }
+               }
+       }
+       else
+       {
+               for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights;i++, sl++)
                {
-                       Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin);
-                       R_DrawBrushModelShadowVolumes (ent, relativelightorigin, sl->cullradius, true);
+                       if (d_lightstylevalue[sl->style] > 0
+                        && ent->maxs[0] >= sl->origin[0] - sl->cullradius
+                        && ent->mins[0] <= sl->origin[0] + sl->cullradius
+                        && ent->maxs[1] >= sl->origin[1] - sl->cullradius
+                        && ent->mins[1] <= sl->origin[1] + sl->cullradius
+                        && ent->maxs[2] >= sl->origin[2] - sl->cullradius
+                        && ent->mins[2] <= sl->origin[2] + sl->cullradius)
+                       {
+                               Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin);
+                               R_DrawBrushModelShadowVolume (ent, relativelightorigin, sl->cullradius, true);
+                       }
                }
        }
        for (i = 0, rd = r_dlight;i < r_numdlights;i++, rd++)
@@ -1906,10 +1938,11 @@ void R_DrawBrushModelFakeShadow (entity_render_t *ent)
                 && ent->mins[2] <= rd->origin[2] + rd->cullradius)
                {
                        Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
-                       R_DrawBrushModelShadowVolumes (ent, relativelightorigin, rd->cullradius, true);
+                       R_DrawBrushModelShadowVolume (ent, relativelightorigin, rd->cullradius, true);
                }
        }
 }
+*/
 
 static void gl_surf_start(void)
 {
index b848772..bcf3959 100644 (file)
@@ -248,6 +248,7 @@ static int Mod_LoadInternalSkin (char *basename, qbyte *skindata, qbyte *skintem
 
 #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)\n", loadmodel->name, VALUE, MIN, MAX);
 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)\n", loadmodel->name, VALUE, MIN, MAX);
+extern void R_DrawQ1Q2AliasModelShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume);
 void Mod_LoadAliasModel (model_t *mod, void *buffer)
 {
        int                                             i, j, version, numverts, totalposes, totalskins, skinwidth, skinheight, totalverts, groupframes, groupskins;
@@ -530,6 +531,7 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer)
        loadmodel->Draw = R_DrawQ1Q2AliasModel;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawFakeShadow = R_DrawQ1Q2AliasModelFakeShadow;
+       loadmodel->DrawShadowVolume = R_DrawQ1Q2AliasModelShadowVolume;
 
        loadmodel->mdlmd2data_triangleneighbors = Mem_Alloc(loadmodel->mempool, loadmodel->numtris * sizeof(int[3]));
        Mod_BuildTriangleNeighbors(loadmodel->mdlmd2data_triangleneighbors, loadmodel->mdlmd2data_indices, loadmodel->numtris);
index 28347fc..fa85dc6 100644 (file)
@@ -426,6 +426,8 @@ static void Mod_LoadTextures (lump_t *l)
                else
                {
                        tx->flags |= SURF_LIGHTMAP;
+                       if (!tx->fogtexture)
+                               tx->flags |= SURF_CLIPSOLID;
                        tx->shader = &Cshader_wall_lightmap;
                }
 
@@ -662,61 +664,853 @@ void Mod_LoadLightList(void)
        }
 }
 
+
+
+/*
+// svbspmesh_t is in model_brush.h
+
+typedef struct svbsppolygon_s
+{
+       struct svbsppolygon_s *next;
+       int numverts;
+       float *verts;
+       float normal[3], dist;
+}
+svbsppolygon_t;
+
+typedef struct svbspnode_s
+{
+       // true if this is a leaf (has no children), not a node
+       int isleaf;
+       // (shared) parent node
+       struct svbspnode_s *parent;
+       // (leaf) dark or lit leaf
+       int dark;
+       // (leaf) polygons bounding this leaf
+       svbsppolygon_t *polygons;
+       // (node) children
+       struct svbspnode_s *children[2];
+       // (node) splitting plane
+       float normal[3], dist;
+}
+svbspnode_t;
+
+svbspnode_t *Mod_SVBSP_AllocNode(svbspnode_t *parent, svbspnode_t *child0, svbspnode_t *child1, float *normal, float dist)
+{
+       svbspnode_t *node;
+       node = Mem_Alloc(loadmodel->mempool, sizeof(svbspnode_t));
+       node->parent = parent;
+       node->children[0] = child0;
+       node->children[1] = child1;
+       VectorCopy(normal, node->normal);
+       node->dist = dist;
+       return node;
+}
+
+svbspnode_t *Mod_SVBSP_AllocLeaf(svbspnode_t *parent, int dark)
+{
+       svbspnode_t *leaf;
+       leaf = Mem_Alloc(loadmodel->mempool, sizeof(svbspnode_t));
+       leaf->isleaf = true;
+       leaf->parent = parent;
+       leaf->dark = dark;
+       return leaf;
+}
+
+svbspnode_t *Mod_SVBSP_NewTree(void)
+{
+       return Mod_SVBSP_AllocLeaf(NULL, false);
+}
+
+void Mod_SVBSP_FreeTree(svbspnode_t *node)
+{
+       if (!node->isleaf)
+       {
+               Mod_SVBSP_FreeTree(node->children[0]);
+               Mod_SVBSP_FreeTree(node->children[1]);
+       }
+       Mem_Free(node);
+}
+
+void Mod_SVBSP_RecursiveAddPolygon(svbspnode_t *node, int numverts, float *verts, float *normal, float dist, int constructmode)
+{
+       int i, j, numvertsfront, numvertsback, maxverts, counts[3];
+       float *vertsfront, *vertsback, *v, d, temp[3];
+       float dists[4096];
+       qbyte sides[4096];
+       svbsppolygon_t *poly;
+       if (node->isleaf)
+       {
+               if (constructmode == 0)
+               {
+                       // construct tree structure
+                       node->isleaf = false;
+                       node->children[0] = Mod_SVBSP_AllocLeaf(node, false);
+                       node->children[1] = Mod_SVBSP_AllocLeaf(node, false);
+                       VectorCopy(normal, node->normal);
+                       node->dist = dist;
+               }
+               else if (constructmode == 1)
+               {
+                       // mark dark leafs
+                       node->dark = true;
+               }
+               else
+               {
+                       // link polygons into lit leafs only (this is the optimization)
+                       if (!node->dark)
+                       {
+                               poly = Mem_Alloc(loadmodel->mempool, sizeof(svbsppolygon_t) + numverts * sizeof(float[3]));
+                               poly->numverts = numverts;
+                               poly->verts = (float *)(poly + 1);
+                               VectorCopy(normal, poly->normal);
+                               poly->dist = dist;
+                               memcpy(poly->verts, verts, numverts * sizeof(float[3]));
+                               poly->next = node->polygons;
+                               node->polygons = poly;
+                       }
+               }
+       }
+       else
+       {
+               counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
+               for (i = 0, v = verts;i < numverts;i++, v += 3)
+               {
+                       dists[i] = DotProduct(v, node->normal) - node->dist;
+                       if (dists[i] >= 0.1)
+                               sides[i] = SIDE_FRONT;
+                       else if (dists[i] <= -0.1)
+                               sides[i] = SIDE_BACK;
+                       else
+                               sides[i] = SIDE_ON;
+                       counts[sides[i]]++;
+               }
+               if (counts[SIDE_FRONT] && counts[SIDE_BACK])
+               {
+                       // some front, some back...  sliced
+                       numvertsfront = 0;
+                       numvertsback = 0;
+                       // this is excessive, but nice for safety...
+                       maxverts = numverts + 4;
+                       vertsfront = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
+                       vertsback = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
+                       for (i = 0, j = numverts - 1;i < numverts;j = i, i++)
+                       {
+                               if (sides[j] == SIDE_FRONT)
+                               {
+                                       VectorCopy(&verts[j * 3], &vertsfront[numvertsfront * 3]);
+                                       numvertsfront++;
+                                       if (sides[i] == SIDE_BACK)
+                                       {
+                                               d = dists[j] / (dists[j] - dists[i]);
+                                               VectorSubtract(&verts[i * 3], &verts[j * 3], temp);
+                                               VectorMA(&verts[j * 3], d, temp, temp);
+                                               VectorCopy(temp, &vertsfront[numvertsfront * 3]);
+                                               VectorCopy(temp, &vertsback[numvertsback * 3]);
+                                               numvertsfront++;
+                                               numvertsback++;
+                                       }
+                               }
+                               else if (sides[j] == SIDE_BACK)
+                               {
+                                       VectorCopy(&verts[j * 3], &vertsback[numvertsback * 3]);
+                                       numvertsback++;
+                                       if (sides[i] == SIDE_FRONT)
+                                       {
+                                               d = dists[j] / (dists[j] - dists[i]);
+                                               VectorSubtract(&verts[i * 3], &verts[j * 3], temp);
+                                               VectorMA(&verts[j * 3], d, temp, temp);
+                                               VectorCopy(temp, &vertsfront[numvertsfront * 3]);
+                                               VectorCopy(temp, &vertsback[numvertsback * 3]);
+                                               numvertsfront++;
+                                               numvertsback++;
+                                       }
+                               }
+                               else
+                               {
+                                       VectorCopy(&verts[j * 3], &vertsfront[numvertsfront * 3]);
+                                       VectorCopy(&verts[j * 3], &vertsback[numvertsback * 3]);
+                                       numvertsfront++;
+                                       numvertsback++;
+                               }
+                       }
+                       Mod_SVBSP_RecursiveAddPolygon(node->children[1], numvertsfront, vertsfront, normal, dist, constructmode);
+                       Mod_SVBSP_RecursiveAddPolygon(node->children[0], numvertsback, vertsback, normal, dist, constructmode);
+                       Mem_Free(vertsfront);
+                       Mem_Free(vertsback);
+               }
+               else if (counts[SIDE_BACK])
+                       Mod_SVBSP_RecursiveAddPolygon(node->children[0], numverts, verts, normal, dist, constructmode);
+               else if (counts[SIDE_FRONT])
+                       Mod_SVBSP_RecursiveAddPolygon(node->children[1], numverts, verts, normal, dist, constructmode);
+               else
+               {
+                       // mode 0 is constructing tree, don't make unnecessary splits
+                       if (constructmode == 1)
+                       {
+                               // marking dark leafs
+                               // send it down the side it is not facing
+                               Mod_SVBSP_RecursiveAddPolygon(node->children[DotProduct(node->normal, normal) < 0], numverts, verts, normal, dist, constructmode);
+                       }
+                       else if (constructmode == 2)
+                       {
+                               // linking polygons into lit leafs only
+                               // send it down the side it is facing
+                               Mod_SVBSP_RecursiveAddPolygon(node->children[DotProduct(node->normal, normal) >= 0], numverts, verts, normal, dist, constructmode);
+                       }
+               }
+       }
+}
+
+int svbsp_count_nodes;
+int svbsp_count_leafs;
+int svbsp_count_polygons;
+int svbsp_count_darkleafs;
+int svbsp_count_originalpolygons;
+int svbsp_count_meshs;
+int svbsp_count_triangles;
+int svbsp_count_vertices;
+
+void Mod_SVBSP_AddPolygon(svbspnode_t *root, int numverts, float *verts, int constructmode, float *test, int linenumber)
+{
+       int i;
+       float normal[3], dist, dir0[3], dir1[3], *v0, *v1, *v2;
+       svbsp_count_originalpolygons++;
+       for (i = 0, v0 = verts + (numverts - 2) * 3, v1 = verts + (numverts - 1) * 3, v2 = verts;i < numverts;i++, v0 = v1, v1 = v2, v2 += 3)
+       {
+               VectorSubtract(v0, v1, dir0);
+               VectorSubtract(v2, v1, dir1);
+               CrossProduct(dir0, dir1, normal);
+               if (DotProduct(normal, normal) >= 0.1)
+                       break;
+       }
+       if (i == numverts)
+               return;
+       VectorNormalize(normal);
+       dist = DotProduct(verts, normal);
+       if (test && DotProduct(test, normal) > dist + 0.1)
+               Con_Printf("%i %f %f %f %f : %f %f %f %f\n", linenumber, normal[0], normal[1], normal[2], dist, test[0], test[1], test[2], DotProduct(test, normal));
+       Mod_SVBSP_RecursiveAddPolygon(root, numverts, verts, normal, dist, constructmode);
+}
+
+void Mod_SVBSP_RecursiveGatherStats(svbspnode_t *node)
+{
+       svbsppolygon_t *poly;
+       for (poly = node->polygons;poly;poly = poly->next)
+               svbsp_count_polygons++;
+       if (node->isleaf)
+       {
+               svbsp_count_leafs++;
+               if (node->dark)
+                       svbsp_count_darkleafs++;
+       }
+       else
+       {
+               svbsp_count_nodes++;
+               Mod_SVBSP_RecursiveGatherStats(node->children[0]);
+               Mod_SVBSP_RecursiveGatherStats(node->children[1]);
+       }
+}
+
+svbspmesh_t *Mod_SVBSP_AllocMesh(int maxverts)
+{
+       svbspmesh_t *mesh;
+       mesh = Mem_Alloc(loadmodel->mempool, sizeof(svbspmesh_t) + maxverts * sizeof(float[4]) + maxverts * sizeof(int[3]));
+       mesh->maxverts = maxverts;
+       mesh->maxtriangles = maxverts;
+       mesh->numverts = 0;
+       mesh->numtriangles = 0;
+       mesh->verts = (float *)(mesh + 1);
+       mesh->elements = (int *)(mesh->verts + mesh->maxverts * 4);
+       return mesh;
+}
+
+svbspmesh_t *Mod_SVBSP_ReAllocMesh(svbspmesh_t *oldmesh)
+{
+       svbspmesh_t *newmesh;
+       newmesh = Mem_Alloc(loadmodel->mempool, sizeof(svbspmesh_t) + oldmesh->numverts * sizeof(float[4]) + oldmesh->numtriangles * sizeof(int[3]));
+       newmesh->maxverts = newmesh->numverts = oldmesh->numverts;
+       newmesh->maxtriangles = newmesh->numtriangles = oldmesh->numtriangles;
+       newmesh->verts = (float *)(newmesh + 1);
+       newmesh->elements = (int *)(newmesh->verts + newmesh->maxverts * 4);
+       memcpy(newmesh->verts, oldmesh->verts, newmesh->numverts * sizeof(float[4]));
+       memcpy(newmesh->elements, oldmesh->elements, newmesh->numtriangles * sizeof(int[3]));
+       return newmesh;
+}
+
+void Mod_SVBSP_RecursiveBuildTriangleMeshs(svbspmesh_t *firstmesh, svbspnode_t *node)
+{
+       svbsppolygon_t *poly;
+       svbspmesh_t *mesh;
+       int i, j, k;
+       float *v, *m, temp[3];
+       if (node->isleaf)
+       {
+               for (poly = node->polygons;poly;poly = poly->next)
+               {
+                       mesh = firstmesh;
+                       while (poly->numverts + mesh->numverts > mesh->maxverts || (poly->numverts - 2) + mesh->numtriangles > mesh->maxtriangles)
+                       {
+                               if (mesh->next == NULL)
+                                       mesh->next = Mod_SVBSP_AllocMesh(max(1000, poly->numverts));
+                               mesh = mesh->next;
+                       }
+                       for (i = 0, v = poly->verts;i < poly->numverts - 2;i++, v += 3)
+                       {
+                               for (k = 0;k < 3;k++)
+                               {
+                                       if (k == 0)
+                                               v = poly->verts;
+                                       else if (k == 1)
+                                               v = poly->verts + (i + 1) * 3;
+                                       else if (k == 2)
+                                               v = poly->verts + (i + 2) * 3;
+                                       for (j = 0, m = mesh->verts;j < mesh->numverts;j++, m += 4)
+                                       {
+                                               VectorSubtract(v, m, temp);
+                                               if (DotProduct(temp, temp) < 0.1)
+                                                       break;
+                                       }
+                                       if (j == mesh->numverts)
+                                       {
+                                               mesh->numverts++;
+                                               VectorCopy(v, m);
+                                       }
+                                       mesh->elements[mesh->numtriangles * 3 + k] = j;
+                               }
+                               mesh->numtriangles++;
+                       }
+               }
+       }
+       else
+       {
+               Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, node->children[0]);
+               Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, node->children[1]);
+       }
+}
+
+svbspmesh_t *Mod_SVBSP_BuildTriangleMeshs(svbspnode_t *root, vec3_t mins, vec3_t maxs)
+{
+       svbspmesh_t *firstmesh, *mesh, *newmesh, *nextmesh;
+       int i;
+       float *v;
+       firstmesh = Mod_SVBSP_AllocMesh(1000);
+       Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, root);
+       // reallocate meshs to conserve space
+       for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh)
+       {
+               svbsp_count_meshs++;
+               svbsp_count_triangles += mesh->numtriangles;
+               svbsp_count_vertices += mesh->numverts;
+
+               // calculate bbox
+               if (firstmesh == NULL)
+               {
+                       VectorCopy(mesh->verts, mins);
+                       VectorCopy(mesh->verts, maxs);
+               }
+               for (i = 0, v = mesh->verts;i < mesh->numverts;i++, v += 4)
+               {
+                       if (mins[0] > v[0]) mins[0] = v[0];if (maxs[0] < v[0]) maxs[0] = v[0];
+                       if (mins[1] > v[1]) mins[1] = v[1];if (maxs[1] < v[1]) maxs[1] = v[1];
+                       if (mins[2] > v[2]) mins[2] = v[2];if (maxs[2] < v[2]) maxs[2] = v[2];
+               }
+
+               nextmesh = mesh->next;
+               newmesh = Mod_SVBSP_ReAllocMesh(mesh);
+               newmesh->next = firstmesh;
+               firstmesh = newmesh;
+               Mem_Free(mesh);
+       }
+       return firstmesh;
+}
+
+void Mod_SVBSP_FreeTriangleMeshs(svbspmesh_t *mesh)
+{
+       svbspmesh_t *nextmesh;
+       for (;mesh;mesh = nextmesh)
+       {
+               nextmesh = mesh->next;
+               Mem_Free(mesh);
+       }
+}
+*/
+
+typedef struct svpolygon_s
+{
+       struct svpolygon_s *next;
+       int maxverts;
+       int numverts;
+       float *verts;
+       float normal[3], dist;
+}
+svpolygon_t;
+
+typedef struct svbrush_s
+{
+       struct svbrush_s *next;
+       svpolygon_t *polygons;
+       vec3_t mins, maxs;
+}
+svbrush_t;
+
+typedef struct svworld_s
+{
+       svbrush_t *brushs;
+}
+svworld_t;
+
+svworld_t *Mod_ShadowBrush_NewWorld(mempool_t *mempool)
+{
+       return Mem_Alloc(mempool, sizeof(svworld_t));
+}
+
+void Mod_ShadowBrush_FreeWorld(svworld_t *world)
+{
+       svbrush_t *brush, *brushnext;
+       svpolygon_t *poly, *polynext;
+       for (brush = world->brushs;brush;brush = brushnext)
+       {
+               brushnext = brush->next;
+               for (poly = brush->polygons;poly;poly = polynext)
+               {
+                       polynext = poly->next;
+                       Mem_Free(poly);
+               }
+               Mem_Free(brush);
+       }
+       Mem_Free(world);
+}
+
+svbrush_t *Mod_ShadowBrush_BeginBrush(mempool_t *mempool)
+{
+       return Mem_Alloc(mempool, sizeof(svbrush_t));
+}
+
+void Mod_ShadowBrush_AddPolygon(mempool_t *mempool, svbrush_t *brush, int numverts, float *verts)
+{
+       int i;
+       float normal[3], dist, dir0[3], dir1[3], *v0, *v1, *v2;
+       svpolygon_t *poly;
+       for (i = 0, v0 = verts + (numverts - 2) * 3, v1 = verts + (numverts - 1) * 3, v2 = verts;i < numverts;i++, v0 = v1, v1 = v2, v2 += 3)
+       {
+               VectorSubtract(v0, v1, dir0);
+               VectorSubtract(v2, v1, dir1);
+               CrossProduct(dir0, dir1, normal);
+               if (DotProduct(normal, normal) >= 0.1)
+                       break;
+       }
+       if (i == numverts)
+               return;
+       VectorNormalize(normal);
+       dist = DotProduct(verts, normal);
+
+       poly = Mem_Alloc(mempool, sizeof(svpolygon_t) + numverts * sizeof(float[3]));
+       poly->numverts = numverts;
+       poly->verts = (float *)(poly + 1);
+       VectorCopy(normal, poly->normal);
+       poly->dist = dist;
+       poly->next = brush->polygons;
+       brush->polygons = poly;
+       memcpy(poly->verts, verts, numverts * sizeof(float[3]));
+}
+
+void Mod_ShadowBrush_EndBrush(svworld_t *world, svbrush_t *brush)
+{
+       int i;
+       float *v;
+       svpolygon_t *poly;
+       if (!brush->polygons)
+       {
+               Mem_Free(brush);
+               return;
+       }
+       brush->next = world->brushs;
+       world->brushs = brush;
+       VectorCopy(brush->polygons->verts, brush->mins);
+       VectorCopy(brush->polygons->verts, brush->maxs);
+       for (poly = brush->polygons;poly;poly = poly->next)
+       {
+               for (i = 0, v = poly->verts;i < poly->numverts;i++, v += 3)
+               {
+                       if (brush->mins[0] > v[0]) brush->mins[0] = v[0];if (brush->maxs[0] < v[0]) brush->maxs[0] = v[0];
+                       if (brush->mins[1] > v[1]) brush->mins[1] = v[1];if (brush->maxs[1] < v[1]) brush->maxs[1] = v[1];
+                       if (brush->mins[2] > v[2]) brush->mins[2] = v[2];if (brush->maxs[2] < v[2]) brush->maxs[2] = v[2];
+               }
+       }
+}
+
+void Mod_ShadowBrush_ProcessWorld(mempool_t *mempool, svworld_t *world)
+{
+       /*
+       for (clipbrush = world->brushs;clipbrush;clipbrush = clipbrush->next)
+       {
+               for (brush = world->brushs;brush;brush = brush->next)
+               {
+                       if (brush != clipbrush
+                        && brush->mins[0] <= clipbrush->maxs[0]
+                        && brush->maxs[0] >= clipbrush->mins[0]
+                        && brush->mins[1] <= clipbrush->maxs[1]
+                        && brush->maxs[1] >= clipbrush->mins[1]
+                        && brush->mins[2] <= clipbrush->maxs[2]
+                        && brush->maxs[2] >= clipbrush->mins[2])
+                               continue;
+                       for (poly = brush->polygons;poly;poly = poly->next)
+                       {
+
+                       }
+               }
+       }
+       */
+}
+
+shadowmesh_t *Mod_ShadowBrush_BuildMeshs(mempool_t *mempool, svworld_t *world)
+{
+       shadowmesh_t *mesh;
+       svbrush_t *brush;
+       svpolygon_t *poly;
+       mesh = Mod_ShadowMesh_Begin(mempool);
+       for (brush = world->brushs;brush;brush = brush->next)
+               for (poly = brush->polygons;poly;poly = poly->next)
+                       Mod_ShadowMesh_AddPolygon(mempool, mesh, poly->numverts, poly->verts);
+       mesh = Mod_ShadowMesh_Finish(mempool, mesh);
+       return mesh;
+}
+
 void Mod_ProcessLightList(void)
 {
-       int i, j, k, *mark;
+       int j, k, *mark, lnum;
        mlight_t *e;
        msurface_t *surf;
        float dist;
-       mleaf_t *l;
+       mleaf_t *leaf;
        qbyte *pvs;
-       for (i = 0, e = loadmodel->lights;i < loadmodel->numlights;i++, e++)
+       for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++)
        {
                e->cullradius2 = DotProduct(e->light, e->light) * (1.0f / (8192.0f * 8192.0f)) / (e->falloff * e->falloff) + 4096.0f;
                if (e->cullradius2 > 4096.0f * 4096.0f)
                        e->cullradius2 = 4096.0f * 4096.0f;
                e->cullradius = sqrt(e->cullradius2);
-               l = Mod_PointInLeaf(e->origin, loadmodel);
-               if (l->compressed_vis)
-                       pvs = Mod_DecompressVis (l->compressed_vis, loadmodel);
+               leaf = Mod_PointInLeaf(e->origin, loadmodel);
+               if (leaf->compressed_vis)
+                       pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel);
                else
                        pvs = mod_novis;
-               for (j = 0, l = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++)
+               for (j = 0;j < loadmodel->numsurfaces;j++)
+                       loadmodel->surfacevisframes[j] = -1;
+               for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++)
                {
                        if (pvs[j >> 3] & (1 << (j & 7)))
                        {
-                               for (k = 0, mark = l->firstmarksurface;k < l->nummarksurfaces;k++, mark++)
+                               for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++)
                                {
                                        surf = loadmodel->surfaces + *mark;
+                                       if (surf->number != *mark)
+                                               Con_Printf("%d != %d\n", surf->number, *mark);
                                        dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
                                        if (surf->flags & SURF_PLANEBACK)
                                                dist = -dist;
                                        if (dist > 0 && dist < e->cullradius)
-                                               loadmodel->surfacevisframes[j] = i - 1000000;
+                                               loadmodel->surfacevisframes[*mark] = -2;
                                }
                        }
                }
+               // build list of light receiving surfaces
                e->numsurfaces = 0;
-               for (j = 0;j < loadmodel->nummodelsurfaces;j++)
-                       if (loadmodel->surfacevisframes[j] == i - 1000000)
+               for (j = 0;j < loadmodel->numsurfaces;j++)
+                       if (loadmodel->surfacevisframes[j] == -2)
                                e->numsurfaces++;
                e->surfaces = NULL;
                if (e->numsurfaces > 0)
                {
                        e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
                        e->numsurfaces = 0;
-                       for (j = 0;j < loadmodel->nummodelsurfaces;j++)
-                               if (loadmodel->surfacevisframes[j] == i - 1000000)
-                                       e->surfaces[e->numsurfaces++] = loadmodel->surfaces + loadmodel->firstmodelsurface + j;
+                       for (j = 0;j < loadmodel->numsurfaces;j++)
+                               if (loadmodel->surfacevisframes[j] == -2)
+                                       e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j;
                }
+               /*
+               {
+               // find bounding box and sphere of lit surfaces
+               float *v, temp[3], radius2;
+               radius2 = 0;
+               for (j = 0;j < e->numsurfaces;j++)
+               {
+                       surf = e->surfaces[j];
+                       if (j == 0)
+                       {
+                               VectorCopy(surf->poly_verts, e->mins);
+                               VectorCopy(surf->poly_verts, e->maxs);
+                       }
+                       for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
+                       {
+                               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);
+                               dist = DotProduct(temp, temp);
+                               if (radius2 < dist)
+                                       radius2 = dist;
+                       }
+               }
+               if (e->cullradius2 > radius2)
+               {
+                       e->cullradius2 = radius2;
+                       e->cullradius = sqrt(e->cullradius2);
+               }
+               }
+               */
+#if 1
+               // clip shadow volumes against eachother to remove unnecessary
+               // polygons (and sections of polygons)
+               {
+                       svworld_t *svworld;
+                       float f;
+                       float temp[3];
+                       float *verts = NULL;
+                       svbrush_t *svbrush;
+                       float *v0;
+                       float projectdistance;
+                       int maxverts = 0;
+                       float *v1;
+                       svworld = Mod_ShadowBrush_NewWorld(loadmodel->mempool);
+                       for (j = 0, surf = loadmodel->surfaces + loadmodel->firstmodelsurface;j < loadmodel->nummodelsurfaces;j++, surf++)
+                       {
+                               if (!(surf->flags & SURF_CLIPSOLID))
+                                       continue;
+                               f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
+                               if (surf->flags & SURF_PLANEBACK)
+                                       f = -f;
+                               projectdistance = e->cullradius + f;
+                               if (projectdistance < 0.1 || projectdistance > e->cullradius)
+                                       continue;
+                               VectorSubtract(e->origin, surf->poly_center, temp);
+                               if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2))
+                                       continue;
+                               if (maxverts < surf->poly_numverts)
+                               {
+                                       maxverts = surf->poly_numverts;
+                                       if (verts)
+                                               Mem_Free(verts);
+                                       verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
+                               }
+                               svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool);
+                               // copy the original polygon, reversed, for the front cap of the volume
+                               for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
+                                       VectorCopy(v0, v1);
+                               Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, surf->poly_numverts, verts);
+                               // project the original polygon, for the back cap of the volume
+                               for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
+                               {
+                                       VectorSubtract(v0, e->origin, temp);
+                                       VectorNormalize(temp);
+                                       VectorMA(v0, projectdistance, temp, v1);
+                               }
+                               Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, surf->poly_numverts, verts);
+                               // project the shadow volume sides
+                               for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, v1 += 3)
+                               {
+                                       VectorCopy(v0, &verts[0]);
+                                       VectorCopy(v1, &verts[3]);
+                                       VectorCopy(v1, &verts[6]);
+                                       VectorCopy(v0, &verts[9]);
+                                       VectorSubtract(&verts[6], e->origin, temp);
+                                       VectorNormalize(temp);
+                                       VectorMA(&verts[6], projectdistance, temp, &verts[6]);
+                                       VectorSubtract(&verts[9], e->origin, temp);
+                                       VectorNormalize(temp);
+                                       VectorMA(&verts[9], projectdistance, temp, &verts[9]);
+                                       Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
+                               }
+                               Mod_ShadowBrush_EndBrush(svworld, svbrush);
+                       }
+                       e->shadowvolume = Mod_ShadowBrush_BuildMeshs(loadmodel->mempool, svworld);
+                       Mod_ShadowBrush_FreeWorld(svworld);
+               }
+#elif 0
+               // build svbsp (shadow volume bsp)
+               {
+                       int maxverts = 0, constructmode;
+                       float *verts = NULL, projectdistance, *v0, *v1, f, temp[3];
+                       svbspnode_t *svbsproot;
+                       svbsproot = Mod_SVBSP_NewTree();
+                       // we do this in three stages:
+                       // 1. construct the svbsp structure
+                       // 2. mark which leafs are dark (shadow)
+                       // 3. link polygons into only leafs that are not dark
+                       // this results in polygons that are only on the outside of the
+                       // shadow volume, removing polygons that are inside the shadow
+                       // volume (which waste time)
+                       for (constructmode = 0;constructmode < 3;constructmode++)
+                       {
+                               svbsp_count_originalpolygons = 0;
+#if 1
+                               for (j = 0, surf = loadmodel->surfaces + loadmodel->firstmodelsurface;j < loadmodel->nummodelsurfaces;j++, surf++)
+                               {
+                                       if (!(surf->flags & SURF_CLIPSOLID))
+                                               continue;
+                                       /*
+                                       if (surf->poly_maxs[0] < e->mins[0]
+                                        || surf->poly_mins[0] > e->maxs[0]
+                                        || surf->poly_maxs[1] < e->mins[1]
+                                        || surf->poly_mins[1] > e->maxs[1]
+                                        || surf->poly_maxs[2] < e->mins[2]
+                                        || surf->poly_mins[2] > e->maxs[2])
+                                               continue;
+                                       */
+                                       f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
+                                       if (surf->flags & SURF_PLANEBACK)
+                                               f = -f;
+                                       projectdistance = e->cullradius + f;
+                                       if (projectdistance < 0.1 || projectdistance > e->cullradius)
+                                               continue;
+                                       /*
+                                       // find the nearest vertex of the projected volume
+                                       for (k = 0, v0 = surf->poly_verts;k < surf->poly_numverts;k++, v0 += 3)
+                                       {
+                                               VectorSubtract(v0, e->origin, temp);
+                                               VectorNormalize(temp);
+                                               if (maxdist00 > v0[0] - e->origin[0]) maxdist00 = v0[0] - e->origin[0];
+                                               if (maxdist01 < e->origin[0] - v0[0]) maxdist01 = e->origin[0] - v0[0];
+                                               if (maxdist10 > v0[1] - e->origin[1]) maxdist10 = v0[1] - e->origin[1];
+                                               if (maxdist11 < e->origin[1] - v0[1]) maxdist11 = e->origin[1] - v0[1];
+                                               if (maxdist20 > v0[2] - e->origin[2]) maxdist20 = v0[2] - e->origin[2];
+                                               if (maxdist21 < e->origin[2] - v0[2]) maxdist21 = e->origin[2] - v0[2];
+                                               dist =
+
+                                               dist = DotProduct(temp, temp);
+                                               if (bestdist > dist)
+                                               {
+                                                       bestdist = dist;
+                                                       VectorCopy(temp, bestvec);
+                                               }
+                                       }
+                                       projectdistance = e->cullradius - sqrt(bestdist);
+                                       if (projectdistance < 0.1)
+                                               continue;
+                                       for (k = 0, v0 = surf->poly_verts;k < surf->poly_numverts;k++, v0 += 3)
+                                       {
+                                               VectorNormalize(temp);
+                                               if (temp[0] > 0)
+                                               {
+                                                       dist = (e->maxs[0] - e->origin[0]) / temp[0];
+                                                       if (maxdist >
+                                               }
+                                               else if (temp[0] < 0)
+                                                       dist = (e->mins[0] - e->origin[0]) / temp[0];
+                                               dist =
+                                               VectorMA(v0, projectdistance, temp, temp);
+                                               dist = (temp[0]
+                                               VectorSubtract(temp, e->origin,
+                                       }
+                                       */
+                                       VectorSubtract(e->origin, surf->poly_center, temp);
+                                       if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2))
+                                               continue;
+                                       if (maxverts < surf->poly_numverts)
+                                       {
+                                               maxverts = surf->poly_numverts;
+                                               if (verts)
+                                                       Mem_Free(verts);
+                                               verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
+                                       }
+                                       // copy the original polygon, reversed, for the front cap of the volume
+                                       for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
+                                               VectorCopy(v0, v1);
+                                       Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__);
+                                       // project the original polygon, for the back cap of the volume
+                                       for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
+                                       {
+                                               VectorSubtract(v0, e->origin, temp);
+                                               VectorNormalize(temp);
+                                               VectorMA(v0, projectdistance, temp, v1);
+                                       }
+                                       Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__);
+                                       // project the shadow volume sides
+                                       for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, v1 += 3)
+                                       {
+                                               VectorCopy(v0, &verts[0]);
+                                               VectorCopy(v1, &verts[3]);
+                                               VectorCopy(v1, &verts[6]);
+                                               VectorCopy(v0, &verts[9]);
+                                               VectorSubtract(&verts[6], e->origin, temp);
+                                               VectorNormalize(temp);
+                                               VectorMA(&verts[6], projectdistance, temp, &verts[6]);
+                                               VectorSubtract(&verts[9], e->origin, temp);
+                                               VectorNormalize(temp);
+                                               VectorMA(&verts[9], projectdistance, temp, &verts[9]);
+                                               Mod_SVBSP_AddPolygon(svbsproot, 4, verts, constructmode, surf->poly_center, __LINE__);
+                                       }
+                               }
+#else
+                               for (j = 0;j < e->numsurfaces;j++)
+                               {
+                                       surf = e->surfaces[j];
+                                       if (!(surf->flags & SURF_CLIPSOLID))
+                                               continue;
+                                       f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
+                                       if (surf->flags & SURF_PLANEBACK)
+                                               f = -f;
+                                       projectdistance = e->cullradius - f;
+                                       if (projectdistance < 0.1 || projectdistance > e->cullradius)
+                                               continue;
+                                       VectorSubtract(e->origin, surf->poly_center, temp);
+                                       if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2))
+                                               continue;
+                                       if (maxverts < surf->poly_numverts)
+                                       {
+                                               maxverts = surf->poly_numverts;
+                                               if (verts)
+                                                       Mem_Free(verts);
+                                               verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
+                                       }
+                                       // copy the original polygon, for the front cap of the volume
+                                       for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
+                                               VectorCopy(v0, v1);
+                                       Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__);
+                                       // project the original polygon, reversed, for the back cap of the volume
+                                       for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
+                                       {
+                                               VectorSubtract(v0, e->origin, temp);
+                                               VectorNormalize(temp);
+                                               VectorMA(v0, projectdistance, temp, v1);
+                                       }
+                                       Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__);
+                                       // project the shadow volume sides
+                                       for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, v1 += 3)
+                                       {
+                                               VectorCopy(v1, &verts[0]);
+                                               VectorCopy(v0, &verts[3]);
+                                               VectorCopy(v0, &verts[6]);
+                                               VectorCopy(v1, &verts[9]);
+                                               VectorSubtract(&verts[6], e->origin, temp);
+                                               VectorNormalize(temp);
+                                               VectorMA(&verts[6], projectdistance, temp, &verts[6]);
+                                               VectorSubtract(&verts[9], e->origin, temp);
+                                               VectorNormalize(temp);
+                                               VectorMA(&verts[9], projectdistance, temp, &verts[9]);
+                                               Mod_SVBSP_AddPolygon(svbsproot, 4, verts, constructmode, surf->poly_center, __LINE__);
+                                       }
+                               }
+#endif
+                       }
+                       if (verts)
+                               Mem_Free(verts);
+
+                       svbsp_count_nodes = 0;
+                       svbsp_count_leafs = 0;
+                       svbsp_count_polygons = 0;
+                       svbsp_count_darkleafs = 0;
+                       svbsp_count_meshs = 0;
+                       svbsp_count_triangles = 0;
+                       svbsp_count_vertices = 0;
+                       e->shadowvolume = Mod_SVBSP_BuildTriangleMeshs(svbsproot, e->shadowvolumemins, e->shadowvolumemaxs);
+                       Mod_SVBSP_RecursiveGatherStats(svbsproot);
+                       Mod_SVBSP_FreeTree(svbsproot);
+                       Con_Printf("light %d (radius %d) has %d surfaces, svbsp contains %d nodes, %d leafs, %d are dark (%d%%), %d original polygons, %d polygons stored (%d%%), %d meshs %d vertices %d triangles\n", lnum, (int)e->cullradius, e->numsurfaces, svbsp_count_nodes, svbsp_count_leafs, svbsp_count_darkleafs, svbsp_count_leafs ? (100 * svbsp_count_darkleafs / svbsp_count_leafs) : 0, svbsp_count_originalpolygons, svbsp_count_polygons, svbsp_count_originalpolygons ? (100 * svbsp_count_polygons / svbsp_count_originalpolygons) : 0, svbsp_count_meshs, svbsp_count_triangles, svbsp_count_vertices);
+               }
+#endif
        }
-       // construct shadow volumes for each light
-       /*
-       for (i = 0, e = loadmodel->lights;i < loadmodel->numlights;i++, e++)
-       {
-               FIXME FINISH THIS CODE!
-       }
-       */
 }
 
 
@@ -1168,7 +1962,7 @@ void Mod_GenerateWarpMesh (msurface_t *surf)
 
 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
 {
-       int i, iu, iv, *index, *n, smax, tmax;
+       int i, iu, iv, *index, smax, tmax;
        float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
        surfmesh_t *mesh;
 
@@ -1215,16 +2009,13 @@ void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
        mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3);
 
        index = mesh->index;
-       n = mesh->triangleneighbors;
        for (i = 0;i < mesh->numtriangles;i++)
        {
                *index++ = 0;
                *index++ = i + 1;
                *index++ = i + 2;
-               *n++ = i - 1;
-               *n++ = -1;
-               *n++ = i + 1;
        }
+       Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
 
        VectorCopy(surf->plane->normal, normal);
        if (surf->flags & SURF_PLANEBACK)
@@ -1261,7 +2052,7 @@ void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
 
 void Mod_GenerateVertexMesh (msurface_t *surf)
 {
-       int i, *index, *n;
+       int i, *index;
        float *in, s, t, normal[3];
        surfmesh_t *mesh;
 
@@ -1279,16 +2070,13 @@ void Mod_GenerateVertexMesh (msurface_t *surf)
        mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3);
 
        index = mesh->index;
-       n = mesh->triangleneighbors;
        for (i = 0;i < mesh->numtriangles;i++)
        {
                *index++ = 0;
                *index++ = i + 1;
                *index++ = i + 2;
-               *n++ = -1;
-               *n++ = -1;
-               *n++ = i + 1;
        }
+       Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
 
        VectorCopy(surf->plane->normal, normal);
        if (surf->flags & SURF_PLANEBACK)
@@ -2431,7 +3219,7 @@ static void Mod_MakePortals(void)
 Mod_LoadBrushModel
 =================
 */
-extern void R_DrawBrushModelFakeShadow (entity_render_t *ent);
+extern void R_DrawBrushModelShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume);
 void Mod_LoadBrushModel (model_t *mod, void *buffer)
 {
        int                     i, j;
@@ -2521,45 +3309,56 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
                mod->nummodelsurfaces = bm->numfaces;
 
                mod->DrawSky = NULL;
-               // LordHavoc: calculate bmodel bounding box rather than trusting what it says
-               for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
+               if (mod->nummodelsurfaces)
                {
-                       // we only need to have a drawsky function if it is used (usually only on world model)
-                       if (surf->texinfo->texture->shader == &Cshader_sky)
-                               mod->DrawSky = R_DrawBrushModelSky;
-                       for (k = 0;k < surf->numedges;k++)
+                       // LordHavoc: calculate bmodel bounding box rather than trusting what it says
+                       for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
                        {
-                               l = mod->surfedges[k + surf->firstedge];
-                               if (l > 0)
-                                       vec = mod->vertexes[mod->edges[l].v[0]].position;
-                               else
-                                       vec = mod->vertexes[mod->edges[-l].v[1]].position;
-                               if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
-                               if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
-                               if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
-                               if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
-                               if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
-                               if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
-                               dist = vec[0]*vec[0]+vec[1]*vec[1];
-                               if (modelyawradius < dist)
-                                       modelyawradius = dist;
-                               dist += vec[2]*vec[2];
-                               if (modelradius < dist)
-                                       modelradius = dist;
+                               // we only need to have a drawsky function if it is used (usually only on world model)
+                               if (surf->texinfo->texture->shader == &Cshader_sky)
+                                       mod->DrawSky = R_DrawBrushModelSky;
+                               for (k = 0;k < surf->numedges;k++)
+                               {
+                                       l = mod->surfedges[k + surf->firstedge];
+                                       if (l > 0)
+                                               vec = mod->vertexes[mod->edges[l].v[0]].position;
+                                       else
+                                               vec = mod->vertexes[mod->edges[-l].v[1]].position;
+                                       if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
+                                       if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
+                                       if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
+                                       if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
+                                       if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
+                                       if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
+                                       dist = vec[0]*vec[0]+vec[1]*vec[1];
+                                       if (modelyawradius < dist)
+                                               modelyawradius = dist;
+                                       dist += vec[2]*vec[2];
+                                       if (modelradius < dist)
+                                               modelradius = dist;
+                               }
                        }
+                       modelyawradius = sqrt(modelyawradius);
+                       modelradius = sqrt(modelradius);
+                       mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
+                       mod->yawmins[2] = mod->normalmins[2];
+                       mod->yawmaxs[2] = mod->normalmaxs[2];
+                       mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
+                       mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
+                       mod->radius = modelradius;
+                       mod->radius2 = modelradius * modelradius;
+                       // LordHavoc: build triangle meshs for entire model's geometry
+                       // (only used for shadow volumes)
+                       mod->shadowmesh = Mod_ShadowMesh_Begin(originalloadmodel->mempool);
+                       for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
+                               if (surf->flags & SURF_CLIPSOLID)
+                                       Mod_ShadowMesh_AddPolygon(originalloadmodel->mempool, mod->shadowmesh, surf->poly_numverts, surf->poly_verts);
+                       mod->shadowmesh = Mod_ShadowMesh_Finish(originalloadmodel->mempool, mod->shadowmesh);
+                       Mod_ShadowMesh_CalcBBox(mod->shadowmesh, mod->shadowmesh_mins, mod->shadowmesh_maxs, mod->shadowmesh_center, &mod->shadowmesh_radius);
                }
-               modelyawradius = sqrt(modelyawradius);
-               modelradius = sqrt(modelradius);
-               mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
-               mod->yawmins[2] = mod->normalmins[2];
-               mod->yawmaxs[2] = mod->normalmaxs[2];
-               mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
-               mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
-               mod->radius = modelradius;
-               mod->radius2 = modelradius * modelradius;
-               // LordHavoc: check for empty submodels (lacrima.bsp has such a glitch)
-               if (mod->normalmins[0] > mod->normalmaxs[0] || mod->normalmins[1] > mod->normalmaxs[1] || mod->normalmins[2] > mod->normalmaxs[2])
+               else
                {
+                       // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
                        Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
                        VectorClear(mod->normalmins);
                        VectorClear(mod->normalmaxs);
@@ -2569,12 +3368,14 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
                        VectorClear(mod->rotatedmaxs);
                        mod->radius = 0;
                        mod->radius2 = 0;
+                       mod->shadowmesh = NULL;
                }
 
                mod->numleafs = bm->visleafs;
 
                mod->Draw = R_DrawBrushModelNormal;
-               mod->DrawFakeShadow = R_DrawBrushModelFakeShadow;
+               mod->DrawFakeShadow = NULL;
+               mod->DrawShadowVolume = R_DrawBrushModelShadowVolume;
 
                // LordHavoc: only register submodels if it is the world
                // (prevents bsp models from replacing world submodels)
index 8424b53..7a8e1d0 100644 (file)
@@ -301,14 +301,15 @@ typedef struct mportal_s
 }
 mportal_t;
 
-typedef struct mlightshadowvolumemesh_s
+typedef struct svbspmesh_s
 {
-       struct mlightshadowvolumemesh_s *next;
-       int numverts;
-       int numtris;
-       float *vertex;
+       struct svbspmesh_s *next;
+       int numverts, maxverts;
+       int numtriangles, maxtriangles;
+       float *verts;
+       int *elements;
 }
-mlightshadowvolumemesh_t;
+svbspmesh_t;
 
 typedef struct mlight_s
 {
@@ -334,10 +335,12 @@ typedef struct mlight_s
        // surfaces this shines on
        int numsurfaces;
        msurface_t **surfaces;
+       // lit area
+       //vec3_t mins, maxs;
        // precomputed shadow volume meshs
-       mlightshadowvolumemesh_t *shadowvolumemeshs;
-       // used only for loading calculations, number of leafs this shines on
-       //int numleafs;
+       //svbspmesh_t *shadowvolume;
+       //vec3_t shadowvolumemins, shadowvolumemaxs;
+       shadowmesh_t *shadowvolume;
 }
 mlight_t;
 
index a2ac48e..8506945 100644 (file)
@@ -408,3 +408,153 @@ void Mod_BuildTriangleNeighbors(int *neighbors, int *elements, int numtriangles)
                n[2] = Mod_FindTriangleWithEdge(elements, numtriangles, e[0], e[2]);
        }
 }
+
+shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts)
+{
+       shadowmesh_t *mesh;
+       mesh = Mem_Alloc(mempool, sizeof(shadowmesh_t) + maxverts * sizeof(float[4]) + maxverts * sizeof(int[3]) + maxverts * sizeof(int[3]));
+       mesh->maxverts = maxverts;
+       mesh->maxtriangles = maxverts;
+       mesh->numverts = 0;
+       mesh->numtriangles = 0;
+       mesh->verts = (float *)(mesh + 1);
+       mesh->elements = (int *)(mesh->verts + mesh->maxverts * 4);
+       mesh->neighbors = (int *)(mesh->elements + mesh->maxtriangles * 3);
+       return mesh;
+}
+
+shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh)
+{
+       shadowmesh_t *newmesh;
+       newmesh = Mem_Alloc(mempool, sizeof(shadowmesh_t) + oldmesh->numverts * sizeof(float[4]) + oldmesh->numtriangles * sizeof(int[3]) + oldmesh->numtriangles * sizeof(int[3]));
+       newmesh->maxverts = newmesh->numverts = oldmesh->numverts;
+       newmesh->maxtriangles = newmesh->numtriangles = oldmesh->numtriangles;
+       newmesh->verts = (float *)(newmesh + 1);
+       newmesh->elements = (int *)(newmesh->verts + newmesh->maxverts * 4);
+       newmesh->neighbors = (int *)(newmesh->elements + newmesh->maxtriangles * 3);
+       memcpy(newmesh->verts, oldmesh->verts, newmesh->numverts * sizeof(float[4]));
+       memcpy(newmesh->elements, oldmesh->elements, newmesh->numtriangles * sizeof(int[3]));
+       memcpy(newmesh->neighbors, oldmesh->neighbors, newmesh->numtriangles * sizeof(int[3]));
+       return newmesh;
+}
+
+int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *v)
+{
+       int j;
+       float *m, temp[3];
+       for (j = 0, m = mesh->verts;j < mesh->numverts;j++, m += 4)
+       {
+               VectorSubtract(v, m, temp);
+               if (DotProduct(temp, temp) < 0.1)
+                       return j;
+       }
+       mesh->numverts++;
+       VectorCopy(v, m);
+       return j;
+}
+
+void Mod_ShadowMesh_AddPolygon(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts)
+{
+       int i, i1, i2, i3;
+       float *v;
+       while (numverts + mesh->numverts > mesh->maxverts || (numverts - 2) + mesh->numtriangles > mesh->maxtriangles)
+       {
+               if (mesh->next == NULL)
+                       mesh->next = Mod_ShadowMesh_Alloc(mempool, max(1000, numverts));
+               mesh = mesh->next;
+       }
+       i1 = Mod_ShadowMesh_AddVertex(mesh, verts);
+       i2 = 0;
+       i3 = Mod_ShadowMesh_AddVertex(mesh, verts + 3);
+       for (i = 0, v = verts + 6;i < numverts - 2;i++, v += 3)
+       {
+               i2 = i3;
+               i3 = Mod_ShadowMesh_AddVertex(mesh, v);
+               mesh->elements[mesh->numtriangles * 3 + 0] = i1;
+               mesh->elements[mesh->numtriangles * 3 + 1] = i2;
+               mesh->elements[mesh->numtriangles * 3 + 2] = i3;
+               mesh->numtriangles++;
+       }
+}
+
+shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool)
+{
+       return Mod_ShadowMesh_Alloc(mempool, 1000);
+}
+
+shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh)
+{
+       int i;
+       shadowmesh_t *mesh, *newmesh, *nextmesh;
+       // reallocate meshs to conserve space
+       for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh)
+       {
+               nextmesh = mesh->next;
+               newmesh = Mod_ShadowMesh_ReAlloc(mempool, mesh);
+               newmesh->next = firstmesh;
+               firstmesh = newmesh;
+               Mem_Free(mesh);
+               Con_Printf("mesh\n");
+               for (i = 0;i < newmesh->numtriangles;i++)
+                       Con_Printf("tri %d %d %d\n", newmesh->elements[i * 3 + 0], newmesh->elements[i * 3 + 1], newmesh->elements[i * 3 + 2]);
+               Mod_BuildTriangleNeighbors(newmesh->neighbors, newmesh->elements, newmesh->numtriangles);
+       }
+       return firstmesh;
+}
+
+void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius)
+{
+       int i;
+       shadowmesh_t *mesh;
+       vec3_t nmins, nmaxs, ncenter, temp;
+       float nradius2, dist2, *v;
+       // calculate bbox
+       for (mesh = firstmesh;mesh;mesh = mesh->next)
+       {
+               if (mesh == firstmesh)
+               {
+                       VectorCopy(mesh->verts, nmins);
+                       VectorCopy(mesh->verts, nmaxs);
+               }
+               for (i = 0, v = mesh->verts;i < mesh->numverts;i++, v += 4)
+               {
+                       if (nmins[0] > v[0]) nmins[0] = v[0];if (nmaxs[0] < v[0]) nmaxs[0] = v[0];
+                       if (nmins[1] > v[1]) nmins[1] = v[1];if (nmaxs[1] < v[1]) nmaxs[1] = v[1];
+                       if (nmins[2] > v[2]) nmins[2] = v[2];if (nmaxs[2] < v[2]) nmaxs[2] = v[2];
+               }
+       }
+       // calculate center and radius
+       ncenter[0] = (nmins[0] + nmaxs[0]) * 0.5f;
+       ncenter[1] = (nmins[1] + nmaxs[1]) * 0.5f;
+       ncenter[2] = (nmins[2] + nmaxs[2]) * 0.5f;
+       nradius2 = 0;
+       for (mesh = firstmesh;mesh;mesh = mesh->next)
+       {
+               for (i = 0, v = mesh->verts;i < mesh->numverts;i++, v += 4)
+               {
+                       VectorSubtract(v, ncenter, temp);
+                       dist2 = DotProduct(temp, temp);
+                       if (nradius2 < dist2)
+                               nradius2 = dist2;
+               }
+       }
+       // return data
+       if (mins)
+               VectorCopy(nmins, mins);
+       if (maxs)
+               VectorCopy(nmaxs, maxs);
+       if (center)
+               VectorCopy(ncenter, center);
+       if (radius)
+               *radius = sqrt(nradius2);
+}
+
+void Mod_ShadowMesh_Free(shadowmesh_t *mesh)
+{
+       shadowmesh_t *nextmesh;
+       for (;mesh;mesh = nextmesh)
+       {
+               nextmesh = mesh->next;
+               Mem_Free(mesh);
+       }
+}
index c58b238..998e028 100644 (file)
@@ -58,6 +58,17 @@ skinframe_t;
 
 #define MAX_SKINS 256
 
+typedef struct shadowmesh_s
+{
+       struct shadowmesh_s *next;
+       int numverts, maxverts;
+       int numtriangles, maxtriangles;
+       float *verts;
+       int *elements;
+       int *neighbors;
+}
+shadowmesh_t;
+
 
 #include "model_brush.h"
 #include "model_sprite.h"
@@ -176,6 +187,11 @@ typedef struct model_s
        int                             numlights;
        mlight_t                *lights;
 
+       // used only for casting dynamic shadow volumes
+       shadowmesh_t    *shadowmesh;
+       vec3_t                  shadowmesh_mins, shadowmesh_maxs, shadowmesh_center;
+       float                   shadowmesh_radius;
+
        // skin animation info
        animscene_t             *skinscenes; // [numskins]
        // skin frame info
@@ -202,6 +218,8 @@ typedef struct model_s
        void(*DrawSky)(struct entity_render_s *ent);
        // draw a fake shadow for the model
        void(*DrawFakeShadow)(struct entity_render_s *ent);
+       // draw a shadow volume for the model based on light source
+       void(*DrawShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume);
 
        // memory pool for allocations
        mempool_t               *mempool;
@@ -241,5 +259,14 @@ extern char loadname[32];  // for hunk tags
 int Mod_FindTriangleWithEdge(int *elements, int numtriangles, int start, int end);
 void Mod_BuildTriangleNeighbors(int *neighbors, int *elements, int numtriangles);
 
+shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts);
+shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh);
+int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *v);
+void Mod_ShadowMesh_AddPolygon(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts);
+shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool);
+shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh);
+void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius);
+void Mod_ShadowMesh_Free(shadowmesh_t *mesh);
+
 #endif // __MODEL__
 
index 1026075..28ddbd3 100644 (file)
@@ -247,6 +247,7 @@ void Mod_LoadSpriteModel (model_t *mod, void *buffer)
        loadmodel->Draw = R_DrawSpriteModel;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawFakeShadow = NULL;
+       loadmodel->DrawShadowVolume = NULL;
 
        version = LittleLong(((dsprite_t *)buffer)->version);
        if (version == SPRITE_VERSION || SPRITE32_VERSION)
index b06f3cb..3424cdd 100644 (file)
--- a/r_light.c
+++ b/r_light.c
@@ -667,7 +667,7 @@ void R_ModelLightPoint (const entity_render_t *ent, vec3_t color, const vec3_t p
                RecursiveLightPoint (color, cl.worldmodel->nodes, p[0], p[1], p[2], p[2] - 65536);
 }
 
-void R_LightModel(const entity_render_t *ent, int numverts, float colorr, float colorg, float colorb, int worldcoords)
+void R_LightModel(const entity_render_t *ent, int numverts, float *vertices, float *normals, float *colors, float colorr, float colorg, float colorb, int worldcoords)
 {
        int i, j, nearlights = 0, maxnearlights = r_modellights.integer;
        float color[3], basecolor[3], v[3], t, *av, *avn, *avc, a, f, dist2, mscale, dot, stylescale, intensity, ambientcolor[3];
@@ -825,11 +825,11 @@ void R_LightModel(const entity_render_t *ent, int numverts, float colorr, float
        basecolor[0] *= colorr;
        basecolor[1] *= colorg;
        basecolor[2] *= colorb;
-       avc = aliasvertcolor;
+       avc = colors;
        if (nearlights)
        {
-               av = aliasvert;
-               avn = aliasvertnorm;
+               av = vertices;
+               avn = normals;
                for (i = 0;i < numverts;i++)
                {
                        VectorCopy(basecolor, color);
index 0a3b5d8..c09e26f 100644 (file)
--- a/r_light.h
+++ b/r_light.h
@@ -21,7 +21,7 @@ void R_AnimateLight(void);
 void R_MarkLights(entity_render_t *ent);
 void R_DrawCoronas(void);
 void R_CompleteLightPoint(vec3_t color, const vec3_t p, int dynamic, const mleaf_t *leaf);
-void R_LightModel(const entity_render_t *ent, int numverts, float colorr, float colorg, float colorb, int worldcoords);
+void R_LightModel(const entity_render_t *ent, int numverts, float *vertices, float *normals, float *colors, float colorr, float colorg, float colorb, int worldcoords);
 void R_UpdateEntLights(entity_render_t *ent);
 
 #endif
index aebace1..ee32a61 100644 (file)
@@ -36,10 +36,15 @@ void R_Shadow_Init(void)
        R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
 }
 
-void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float projectdistance, int visiblevolume)
+void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance, int visiblevolume)
 {
        int i, *e, *n, *out, tris;
        float *v0, *v1, *v2, temp[3], f;
+       if (projectdistance < 0.1)
+       {
+               Con_Printf("R_Shadow_Volume: projectdistance %f\n");
+               return;
+       }
 // terminology:
 //
 // frontface:
@@ -84,8 +89,15 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in
        for (i = 0, v0 = vertex, v1 = vertex + numverts * 4;i < numverts;i++, v0 += 4, v1 += 4)
        {
                VectorSubtract(v0, relativelightorigin, temp);
+#if 0
+               f = lightradius / sqrt(DotProduct(temp,temp));
+               if (f < 1)
+                       f = 1;
+               VectorMA(relativelightorigin, f, temp, v1);
+#else
                f = projectdistance / sqrt(DotProduct(temp,temp));
                VectorMA(v0, f, temp, v1);
+#endif
        }
 
        // check which triangles are facing the light
@@ -113,7 +125,7 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in
 #else
                // readable version
                {
-               float dir0[3], dir1[3],
+               float dir0[3], dir1[3];
 
                // calculate two mostly perpendicular edge directions
                VectorSubtract(v0, v1, dir0);
@@ -133,7 +145,6 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in
                // the normal is not normalized because it is used on both sides of
                // the comparison, so it's magnitude does not matter
                trianglefacinglight[i] = DotProduct(relativelightorigin, temp) >= DotProduct(v0, temp);
-               }
 #endif
        }
 
@@ -150,6 +161,7 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in
                {
                        // triangle is backface and therefore casts shadow,
                        // output front and back caps for shadow volume
+#if 1
                        // front cap (with flipped winding order)
                        out[0] = e[0];
                        out[1] = e[2];
@@ -160,6 +172,14 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in
                        out[5] = e[2] + numverts;
                        out += 6;
                        tris += 2;
+#else
+                       // rear cap
+                       out[0] = e[0] + numverts;
+                       out[1] = e[1] + numverts;
+                       out[2] = e[2] + numverts;
+                       out += 3;
+                       tris += 1;
+#endif
                        // check the edges
                        if (n[0] < 0 || trianglefacinglight[n[0]])
                        {
@@ -199,14 +219,16 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in
        // draw the volume
        if (visiblevolume)
        {
-               qglDisable(GL_CULL_FACE);
+               //qglDisable(GL_CULL_FACE);
                R_Mesh_Draw(numverts * 2, tris, shadowelements);
-               qglEnable(GL_CULL_FACE);
+               //qglEnable(GL_CULL_FACE);
        }
        else
        {
                qglColorMask(0,0,0,0);
+               qglDepthMask(0);
                qglEnable(GL_STENCIL_TEST);
+
                // increment stencil if backface is behind depthbuffer
                qglCullFace(GL_BACK); // quake is backwards, this culls front faces
                qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
@@ -215,9 +237,11 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in
                qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
                qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
                R_Mesh_Draw(numverts * 2, tris, shadowelements);
+
                // restore to normal quake rendering
                qglDisable(GL_STENCIL_TEST);
                qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+               qglDepthMask(1);
                qglColorMask(1,1,1,1);
        }
 }
index cef3d81..bd3669d 100644 (file)
@@ -3,7 +3,7 @@
 #define R_SHADOW_H
 
 void R_Shadow_Init(void);
-void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float projectdistance, int visiblevolume);
+void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance, int visiblevolume);
 void R_Shadow_VertexLight(int numverts, float *vertex, float *normals, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor);
 void R_Shadow_RenderLightThroughStencil(int numverts, int numtris, int *elements, vec3_t relativelightorigin, float *normals);
 void R_Shadow_ClearStencil(void);