]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rsurf.c
varray_element is gone, instead you pass your own element array to R_Mesh_Draw
[xonotic/darkplaces.git] / gl_rsurf.c
index 5f23baaa0776a6683e418fc1837d67c119eb1934..9cdd6cf64068f2eac009bc191dbba720ac585888 100644 (file)
@@ -31,12 +31,11 @@ static qbyte templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
 cvar_t r_ambient = {0, "r_ambient", "0"};
 cvar_t r_vertexsurfaces = {0, "r_vertexsurfaces", "0"};
 cvar_t r_dlightmap = {CVAR_SAVE, "r_dlightmap", "1"};
-//cvar_t r_drawportals = {0, "r_drawportals", "0"};
+cvar_t r_drawportals = {0, "r_drawportals", "0"};
 cvar_t r_testvis = {0, "r_testvis", "0"};
 cvar_t r_floatbuildlightmap = {0, "r_floatbuildlightmap", "0"};
 cvar_t r_detailtextures = {CVAR_SAVE, "r_detailtextures", "1"};
 cvar_t r_surfaceworldnode = {0, "r_surfaceworldnode", "0"};
-cvar_t r_cullsurface = {0, "r_cullsurface", "0"};
 
 static int dlightdivtable[32768];
 
@@ -44,7 +43,6 @@ static int dlightdivtable[32768];
 int r_pvsframecount = 0;
 mleaf_t *r_pvsviewleaf = NULL;
 int r_pvsviewleafnovis = 0;
-msurface_t *r_pvsfirstsurface = NULL;
 
 static int R_IntAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surf)
 {
@@ -823,14 +821,13 @@ static void RSurfShader_Sky(const entity_render_t *ent, const texture_t *texture
        {
                for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                {
-                       R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-                       memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+                       R_Mesh_ResizeCheck(mesh->numverts);
                        memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                        if (skyrendermasked)
                                memset(varray_color, 0, mesh->numverts * sizeof(float[4]));
                        else
                                R_FillColors(varray_color, mesh->numverts, fogcolor[0] * mesh_colorscale, fogcolor[1] * mesh_colorscale, fogcolor[2] * mesh_colorscale, 1);
-                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
                }
        }
 }
@@ -869,8 +866,7 @@ static void RSurfShader_Water_Callback(const void *calldata1, int calldata2)
        R_Mesh_State(&m);
        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
        {
-               R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-               memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+               R_Mesh_ResizeCheck(mesh->numverts);
                memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                f = surf->flags & SURF_DRAWFULLBRIGHT ? 1.0f : ((surf->flags & SURF_LIGHTMAP) ? 0 : 0.5f);
@@ -883,7 +879,7 @@ static void RSurfShader_Water_Callback(const void *calldata1, int calldata2)
                                RSurf_AddLightmapToVertexColors(mesh->lightmapoffsets, varray_color, mesh->numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
                }
                RSurf_FogColors(varray_vertex, varray_color, mesh_colorscale, mesh->numverts, modelorg);
-               R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+               R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
        }
 
        if (fogenabled)
@@ -896,13 +892,12 @@ static void RSurfShader_Water_Callback(const void *calldata1, int calldata2)
                R_Mesh_State(&m);
                for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                {
-                       R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-                       memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+                       R_Mesh_ResizeCheck(mesh->numverts);
                        memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                        if (m.tex[0])
                                memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                        RSurf_FogPassColors(varray_vertex, varray_color, fogcolor[0], fogcolor[1], fogcolor[2], alpha, mesh_colorscale, mesh->numverts, modelorg);
-                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
                }
        }
 }
@@ -953,8 +948,7 @@ static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const m
        R_Mesh_State(&m);
        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
        {
-               R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-               memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+               R_Mesh_ResizeCheck(mesh->numverts);
                memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                R_FillColors(varray_color, mesh->numverts, base, base, base, ent->alpha);
@@ -966,7 +960,7 @@ static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const m
                                RSurf_AddLightmapToVertexColors(mesh->lightmapoffsets, varray_color, mesh->numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
                }
                RSurf_FogColors(varray_vertex, varray_color, mesh_colorscale, mesh->numverts, modelorg);
-               R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+               R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
        }
 }
 
@@ -997,12 +991,11 @@ static void RSurfShader_Wall_Pass_BaseFullbright(const entity_render_t *ent, con
        R_Mesh_State(&m);
        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
        {
-               R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-               memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+               R_Mesh_ResizeCheck(mesh->numverts);
                memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                RSurf_FoggedColors(varray_vertex, varray_color, 1, 1, 1, ent->alpha, mesh_colorscale, mesh->numverts, modelorg);
-               R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+               R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
        }
 }
 
@@ -1020,12 +1013,11 @@ static void RSurfShader_Wall_Pass_Glow(const entity_render_t *ent, const msurfac
        R_Mesh_State(&m);
        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
        {
-               R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-               memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+               R_Mesh_ResizeCheck(mesh->numverts);
                memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                RSurf_FoggedColors(varray_vertex, varray_color, 1, 1, 1, ent->alpha, mesh_colorscale, mesh->numverts, modelorg);
-               R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+               R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
        }
 }
 
@@ -1043,13 +1035,12 @@ static void RSurfShader_Wall_Pass_Fog(const entity_render_t *ent, const msurface
        R_Mesh_State(&m);
        for (mesh = surf->mesh;mesh;mesh = mesh->chain)
        {
-               R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-               memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+               R_Mesh_ResizeCheck(mesh->numverts);
                memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                if (m.tex[0])
                        memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                RSurf_FogPassColors(varray_vertex, varray_color, fogcolor[0], fogcolor[1], fogcolor[2], ent->alpha, mesh_colorscale, mesh->numverts, modelorg);
-               R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+               R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
        }
 }
 
@@ -1081,15 +1072,14 @@ static void RSurfShader_OpaqueWall_Pass_BaseTripleTexCombine(const entity_render
                }
                for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                {
-                       R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-                       memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+                       R_Mesh_ResizeCheck(mesh->numverts);
                        memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                        memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                        memcpy(varray_texcoord[1], mesh->uv, mesh->numverts * sizeof(float[2]));
                        memcpy(varray_texcoord[2], mesh->ab, mesh->numverts * sizeof(float[2]));
                        cl = (float) (1 << lightscalebit) * mesh_colorscale;
                        R_FillColors(varray_color, mesh->numverts, cl, cl, cl, 1);
-                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
                }
        }
 }
@@ -1118,14 +1108,13 @@ static void RSurfShader_OpaqueWall_Pass_BaseDoubleTex(const entity_render_t *ent
                }
                for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                {
-                       R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-                       memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+                       R_Mesh_ResizeCheck(mesh->numverts);
                        memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                        memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                        memcpy(varray_texcoord[1], mesh->uv, mesh->numverts * sizeof(float[2]));
                        cl = (float) (1 << lightscalebit) * mesh_colorscale;
                        R_FillColors(varray_color, mesh->numverts, cl, cl, cl, 1);
-                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
                }
        }
 }
@@ -1145,12 +1134,11 @@ static void RSurfShader_OpaqueWall_Pass_BaseTexture(const entity_render_t *ent,
        {
                for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                {
-                       R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-                       memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+                       R_Mesh_ResizeCheck(mesh->numverts);
                        memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                        memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                        R_FillColors(varray_color, mesh->numverts, 1, 1, 1, 1);
-                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
                }
        }
 }
@@ -1178,13 +1166,12 @@ static void RSurfShader_OpaqueWall_Pass_BaseLightmap(const entity_render_t *ent,
                }
                for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                {
-                       R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-                       memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+                       R_Mesh_ResizeCheck(mesh->numverts);
                        memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                        memcpy(varray_texcoord[0], mesh->uv, mesh->numverts * sizeof(float[2]));
                        cl = (float) (1 << lightscalebit) * mesh_colorscale;
                        R_FillColors(varray_color, mesh->numverts, cl, cl, cl, 1);
-                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
                }
        }
 }
@@ -1209,14 +1196,13 @@ static void RSurfShader_OpaqueWall_Pass_Light(const entity_render_t *ent, const
                        {
                                if (RSurf_LightCheck(&ent->inversematrix, surf->dlightbits, mesh))
                                {
-                                       R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-                                       memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+                                       R_Mesh_ResizeCheck(mesh->numverts);
                                        memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                                        memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                                        R_FillColors(varray_color, mesh->numverts, 0, 0, 0, 1);
                                        RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, mesh->numverts, varray_vertex, varray_color);
                                        RSurf_ScaleColors(varray_color, mesh_colorscale, mesh->numverts);
-                                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+                                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
                                }
                        }
                }
@@ -1240,13 +1226,12 @@ static void RSurfShader_OpaqueWall_Pass_Fog(const entity_render_t *ent, const te
        {
                for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                {
-                       R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-                       memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+                       R_Mesh_ResizeCheck(mesh->numverts);
                        memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                        if (m.tex[0])
                                memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                        RSurf_FogPassColors(varray_vertex, varray_color, fogcolor[0], fogcolor[1], fogcolor[2], 1, mesh_colorscale, mesh->numverts, modelorg);
-                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
                }
        }
 }
@@ -1266,12 +1251,11 @@ static void RSurfShader_OpaqueWall_Pass_BaseDetail(const entity_render_t *ent, c
        {
                for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                {
-                       R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-                       memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+                       R_Mesh_ResizeCheck(mesh->numverts);
                        memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                        memcpy(varray_texcoord[0], mesh->ab, mesh->numverts * sizeof(float[2]));
                        R_FillColors(varray_color, mesh->numverts, 1, 1, 1, 1);
-                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
                }
        }
 }
@@ -1291,12 +1275,11 @@ static void RSurfShader_OpaqueWall_Pass_Glow(const entity_render_t *ent, const t
        {
                for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                {
-                       R_Mesh_ResizeCheck(mesh->numverts, mesh->numtriangles);
-                       memcpy(varray_element, mesh->index, mesh->numtriangles * sizeof(int[3]));
+                       R_Mesh_ResizeCheck(mesh->numverts);
                        memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
                        memcpy(varray_texcoord[0], mesh->st, mesh->numverts * sizeof(float[2]));
                        R_FillColors(varray_color, mesh->numverts, mesh_colorscale, mesh_colorscale, mesh_colorscale, 1);
-                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles);
+                       R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
                }
        }
 }
@@ -1421,7 +1404,7 @@ Cshader_t *Cshaders[4] =
 
 void R_DrawSurfaces(entity_render_t *ent, int sky, int normal)
 {
-       int i, alttextures, texframe, framecount, numtextures, numsurfaces;
+       int i, alttextures, texframe, framecount, numtextures, numsurfaces, *surfacevisframes;
        texture_t *t, *textures;
        model_t *model;
        msurface_t *surf, *surfaces;
@@ -1430,6 +1413,10 @@ void R_DrawSurfaces(entity_render_t *ent, int sky, int normal)
        if (!ent->model)
                return;
 
+       // mark the surfaces touched by dynamic lights
+       if (normal && r_dynamic.integer)
+               R_MarkLights(ent);
+
        R_Mesh_Matrix(&ent->matrix);
 
        model = ent->model;
@@ -1438,79 +1425,59 @@ void R_DrawSurfaces(entity_render_t *ent, int sky, int normal)
 
        Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
 
-       textures = model->textures;
        numtextures = model->numtextures;
-       surfaces = model->surfaces + model->firstmodelsurface;
+       textures = model->textures;
        numsurfaces = model->nummodelsurfaces;
+       surfaces = model->surfaces + model->firstmodelsurface;
+       surfacevisframes = model->surfacevisframes + model->firstmodelsurface;
 
        for (i = 0;i < numtextures;i++)
                textures[i].surfacechain = NULL;
 
        for (i = 0, surf = surfaces;i < numsurfaces;i++, surf++)
        {
-               if (surf->visframe == r_framecount)
+               if (surfacevisframes[i] == r_framecount)
                {
+#if !WORLDNODECULLBACKFACES
                        // mark any backface surfaces as not visible
                        if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
                        {
                                if (!(surf->flags & SURF_PLANEBACK))
-                                       surf->visframe = -1;
+                                       surfacevisframes[i] = -1;
                        }
                        else
                        {
-                               if (surf->flags & SURF_PLANEBACK)
-                                       surf->visframe = -1;
+                               if ((surf->flags & SURF_PLANEBACK))
+                                       surfacevisframes[i] = -1;
                        }
-                       if (surf->visframe == r_framecount)
+                       if (surfacevisframes[i] == r_framecount)
+#endif
                        {
-                               if (r_cullsurface.integer && R_CullBox (surf->poly_mins, surf->poly_maxs))
-                                       surf->visframe = -1;
-                               else
+                               c_faces++;
+                               t = surf->texinfo->texture;
+                               if (t->animated)
                                {
-                                       c_faces++;
-                                       t = surf->texinfo->texture;
-                                       if (t->animated)
-                                       {
-                                               framecount = t->anim_total[alttextures];
-                                               if (framecount >= 2)
-                                                       t = t->anim_frames[alttextures][texframe % framecount];
-                                               else
-                                                       t = t->anim_frames[alttextures][0];
-                                       }
-                                       surf->currenttexture = t;
-                                       surf->texturechain = t->surfacechain;
-                                       t->surfacechain = surf;
+                                       framecount = t->anim_total[alttextures];
+                                       if (framecount >= 2)
+                                               t = t->anim_frames[alttextures][texframe % framecount];
+                                       else
+                                               t = t->anim_frames[alttextures][0];
                                }
-                       }
-               }
-       }
-
-       if (sky)
-               for (i = 0, t = textures;i < numtextures;i++, t++)
-                       if (t->surfacechain && t->shader->shaderfunc[SHADERSTAGE_SKY])
-                               t->shader->shaderfunc[SHADERSTAGE_SKY](ent, t);
-
-       if (normal)
-       {
-               if (r_dynamic.integer)
-                       R_MarkLights(ent);
-
-               if (!r_vertexsurfaces.integer)
-               {
-                       for (i = 0, surf = surfaces;i < numsurfaces;i++, surf++)
-                       {
-                               if (surf->visframe == r_framecount && surf->lightmaptexture != NULL)
+                               surf->currenttexture = t;
+                               surf->texturechain = t->surfacechain;
+                               t->surfacechain = surf;
+                               if (!r_vertexsurfaces.integer && surf->lightmaptexture != NULL)
                                {
                                        if (surf->cached_dlight
-                                        || surf->cached_ambient != r_ambient.value
-                                        || surf->cached_lightscalebit != lightscalebit)
+                                       || surf->cached_ambient != r_ambient.value
+                                       || surf->cached_lightscalebit != lightscalebit)
                                                R_BuildLightMap(ent, surf, false); // base lighting changed
                                        else if (r_dynamic.integer)
                                        {
                                                if  (surf->styles[0] != 255 && (d_lightstylevalue[surf->styles[0]] != surf->cached_light[0]
-                                                || (surf->styles[1] != 255 && (d_lightstylevalue[surf->styles[1]] != surf->cached_light[1]
-                                                || (surf->styles[2] != 255 && (d_lightstylevalue[surf->styles[2]] != surf->cached_light[2]
-                                                || (surf->styles[3] != 255 && (d_lightstylevalue[surf->styles[3]] != surf->cached_light[3]))))))))
+                                               || (surf->styles[1] != 255 && (d_lightstylevalue[surf->styles[1]] != surf->cached_light[1]
+                                               || (surf->styles[2] != 255 && (d_lightstylevalue[surf->styles[2]] != surf->cached_light[2]
+                                               || (surf->styles[3] != 255 && (d_lightstylevalue[surf->styles[3]] != surf->cached_light[3]))))))))
                                                        R_BuildLightMap(ent, surf, false); // base lighting changed
                                                else if (surf->dlightframe == r_framecount && r_dlightmap.integer)
                                                        R_BuildLightMap(ent, surf, true); // only dlights
@@ -1518,14 +1485,19 @@ void R_DrawSurfaces(entity_render_t *ent, int sky, int normal)
                                }
                        }
                }
+       }
 
+       if (sky)
+               for (i = 0, t = textures;i < numtextures;i++, t++)
+                       if (t->surfacechain && t->shader->shaderfunc[SHADERSTAGE_SKY])
+                               t->shader->shaderfunc[SHADERSTAGE_SKY](ent, t);
+
+       if (normal)
                for (i = 0, t = textures;i < numtextures;i++, t++)
                        if (t->surfacechain && t->shader->shaderfunc[SHADERSTAGE_NORMAL])
                                t->shader->shaderfunc[SHADERSTAGE_NORMAL](ent, t);
-       }
 }
 
-/*
 static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
 {
        int i;
@@ -1536,18 +1508,12 @@ static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
        memset(&m, 0, sizeof(m));
        m.blendfunc1 = GL_SRC_ALPHA;
        m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
-       m.wantoverbright = false;
+       //m.wantoverbright = false;
        R_Mesh_Matrix(&ent->matrix);
        R_Mesh_State(&m);
-       R_Mesh_ResizeCheck(portal->numpoints, portal->numpoints - 2);
-       for (i = 0;i < mesh->numtriangles;i++)
-       {
-               varray_element[i * 3 + 0] = 0;
-               varray_element[i * 3 + 1] = i + 1;
-               varray_element[i * 3 + 2] = i + 2;
-       }
+       R_Mesh_ResizeCheck(portal->numpoints);
        i = portal - ent->model->portals;
-       R_FillColors(varray_color, mesh->numverts,
+       R_FillColors(varray_color, portal->numpoints,
                ((i & 0x0007) >> 0) * (1.0f / 7.0f) * mesh_colorscale,
                ((i & 0x0038) >> 3) * (1.0f / 7.0f) * mesh_colorscale,
                ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * mesh_colorscale,
@@ -1560,7 +1526,7 @@ static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
        else
                for (i = 0, v = varray_vertex;i < portal->numpoints;i++, v += 4)
                        VectorCopy(portal->points[i].position, v);
-       R_Mesh_Draw(portal->numpoints, portal->numpoints - 2);
+       R_Mesh_Draw(portal->numpoints, portal->numpoints - 2, polygonelements);
 }
 
 static void R_DrawPortals(entity_render_t *ent)
@@ -1574,48 +1540,105 @@ static void R_DrawPortals(entity_render_t *ent)
 
        for (portal = ent->model->portals, endportal = portal + ent->model->numportals;portal < endportal;portal++)
        {
-               if (portal->here->visframe == r_framecount || portal->past->visframe == r_framecount)
+               if (portal->here->pvsframe == r_pvsframecount || portal->past->pvsframe == r_pvsframecount)
                {
-                       VectorClear(temp);
-                       for (i = 0;i < portal->numpoints;i++)
-                               VectorAdd(temp, portal->points[i].position, temp);
-                       f = ixtable[portal->numpoints];
-                       VectorScale(temp, f, temp);
-                       Matrix4x4_Transform(&ent->matrix, temp, center);
-                       R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, ent, portal - ent->model->portals);
+                       if (portal->numpoints <= POLYGONELEMENTS_MAXPOINTS)
+                       {
+                               VectorClear(temp);
+                               for (i = 0;i < portal->numpoints;i++)
+                                       VectorAdd(temp, portal->points[i].position, temp);
+                               f = ixtable[portal->numpoints];
+                               VectorScale(temp, f, temp);
+                               Matrix4x4_Transform(&ent->matrix, temp, center);
+                               R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, ent, portal - ent->model->portals);
+                       }
                }
        }
 }
-*/
 
 void R_DrawBrushModel(entity_render_t *ent, int sky, int normal)
 {
-       int i;
+       int i, numsurfaces, *surfacevisframes, *surfacepvsframes;
        msurface_t *surf;
        model_t *model;
+#if WORLDNODECULLBACKFACES
        vec3_t modelorg;
+#endif
 
        // because bmodels can be reused, we have to decide which things to render
        // from scratch every time
        model = ent->model;
+#if WORLDNODECULLBACKFACES
        Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
-       for (i = 0;i < model->nummodelsurfaces;i++)
+#endif
+       numsurfaces = model->nummodelsurfaces;
+       surf = model->surfaces + model->firstmodelsurface;
+       surfacevisframes = model->surfacevisframes + model->firstmodelsurface;
+       surfacepvsframes = model->surfacepvsframes + model->firstmodelsurface;
+       for (i = 0;i < numsurfaces;i++, surf++)
        {
-               surf = model->surfaces + model->firstmodelsurface + i;
-               surf->visframe = r_framecount;
-               surf->pvsframe = -1;
-               surf->worldnodeframe = -1;
-               surf->lightframe = -1;
+#if WORLDNODECULLBACKFACES
+               // mark any backface surfaces as not visible
+               if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
+               {
+                       if ((surf->flags & SURF_PLANEBACK))
+                       {
+                               surfacevisframes[i] = r_framecount;
+                               surfacepvsframes[i] = r_pvsframecount;
+                       }
+               }
+               else
+               {
+                       if (!(surf->flags & SURF_PLANEBACK))
+                       {
+                               surfacevisframes[i] = r_framecount;
+                               surfacepvsframes[i] = r_pvsframecount;
+                       }
+               }
+#else
+               surfacevisframes[i] = r_framecount;
+               surfacepvsframes[i] = r_pvsframecount;
+#endif
                surf->dlightframe = -1;
        }
        R_DrawSurfaces(ent, sky, normal);
 }
 
-void R_SurfaceWorldNode (void)
+void R_SurfaceWorldNode (entity_render_t *ent)
 {
-       msurface_t *surf;
-       for (surf = r_pvsfirstsurface;surf;surf = surf->pvschain)
-               surf->visframe = r_framecount;
+       int i, numsurfaces, *surfacevisframes, *surfacepvsframes;
+       msurface_t *surfaces, *surf;
+       model_t *model;
+       vec3_t modelorg;
+
+       model = ent->model;
+       numsurfaces = model->nummodelsurfaces;
+       surfaces = model->surfaces + model->firstmodelsurface;
+       surfacevisframes = model->surfacevisframes + model->firstmodelsurface;
+       surfacepvsframes = model->surfacepvsframes + model->firstmodelsurface;
+       Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
+
+       for (i = 0, surf = surfaces;i < numsurfaces;i++, surf++)
+       {
+               if (surfacepvsframes[i] == r_pvsframecount)
+               {
+#if WORLDNODECULLBACKFACES
+                       if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
+                       {
+                               if ((surf->flags & SURF_PLANEBACK) && R_NotCulledBox (surf->poly_mins, surf->poly_maxs))
+                                       surfacevisframes[i] = r_framecount;
+                       }
+                       else
+                       {
+                               if (!(surf->flags & SURF_PLANEBACK) && R_NotCulledBox (surf->poly_mins, surf->poly_maxs))
+                                       surfacevisframes[i] = r_framecount;
+                       }
+#else
+                       if (R_NotCulledBox (surf->poly_mins, surf->poly_maxs))
+                               surfacevisframes[i] = r_framecount;
+#endif
+               }
+       }
 }
 
 /*
@@ -1681,15 +1704,21 @@ loc1:
 
 static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf)
 {
-       int c, leafstackpos;
+       int c, leafstackpos, *mark, *surfacevisframes;
+#if WORLDNODECULLBACKFACES
+       int n;
+       msurface_t *surf;
+#endif
        mleaf_t *leaf, *leafstack[8192];
        mportal_t *p;
-       msurface_t **mark;
        vec3_t modelorg;
+       msurface_t *surfaces;
        // LordHavoc: portal-passage worldnode with PVS;
        // follows portals leading outward from viewleaf, does not venture
        // offscreen or into leafs that are not visible, faster than Quake's
        // RecursiveWorldNode
+       surfaces = ent->model->surfaces;
+       surfacevisframes = ent->model->surfacevisframes;
        Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
        viewleaf->worldnodeframe = r_framecount;
        leafstack[0] = viewleaf;
@@ -1698,36 +1727,59 @@ static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf)
        {
                c_leafs++;
                leaf = leafstack[--leafstackpos];
-               // only useful for drawing portals
-               //leaf->visframe = r_framecount;
                // draw any surfaces bounding this leaf
                if (leaf->nummarksurfaces)
+               {
                        for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--)
-                               (*mark++)->visframe = r_framecount;
+                       {
+#if WORLDNODECULLBACKFACES
+                               n = *mark++;
+                               if (surfacevisframes[n] != r_framecount)
+                               {
+                                       surf = surfaces + n;
+                                       if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
+                                       {
+                                               if ((surf->flags & SURF_PLANEBACK))
+                                                       surfacevisframes[n] = r_framecount;
+                                       }
+                                       else
+                                       {
+                                               if (!(surf->flags & SURF_PLANEBACK))
+                                                       surfacevisframes[n] = r_framecount;
+                                       }
+                               }
+#else
+                               surfacevisframes[*mark++] = r_framecount;
+#endif
+                       }
+               }
                // follow portals into other leafs
                for (p = leaf->portals;p;p = p->next)
                {
-                       leaf = p->past;
-                       if (leaf->worldnodeframe != r_framecount)
+                       // LordHavoc: this DotProduct hurts less than a cache miss
+                       // (which is more likely to happen if backflowing through leafs)
+                       if (DotProduct(modelorg, p->plane.normal) < (p->plane.dist + 1))
                        {
-                               leaf->worldnodeframe = r_framecount;
-                               // FIXME: R_NotCulledBox is absolute, should be done relative
-                               if (leaf->pvsframe == r_pvsframecount && R_NotCulledBox(leaf->mins, leaf->maxs))
-                                       leafstack[leafstackpos++] = leaf;
+                               leaf = p->past;
+                               if (leaf->worldnodeframe != r_framecount)
+                               {
+                                       leaf->worldnodeframe = r_framecount;
+                                       // FIXME: R_NotCulledBox is absolute, should be done relative
+                                       if (leaf->pvsframe == r_pvsframecount && R_NotCulledBox(leaf->mins, leaf->maxs))
+                                               leafstack[leafstackpos++] = leaf;
+                               }
                        }
                }
        }
-       //if (r_drawportals.integer)
-       //      R_DrawPortals(ent);
+       if (r_drawportals.integer)
+               R_DrawPortals(ent);
 }
 
-
 void R_PVSUpdate (mleaf_t *viewleaf)
 {
-       int i, j, l, c, bits;
+       int i, j, l, c, bits, *surfacepvsframes, *mark;
        mleaf_t *leaf;
        qbyte *vis;
-       msurface_t **mark, *surf;
 
        if (r_pvsviewleaf == viewleaf && r_pvsviewleafnovis == r_novis.integer)
                return;
@@ -1738,6 +1790,7 @@ void R_PVSUpdate (mleaf_t *viewleaf)
 
        if (viewleaf)
        {
+               surfacepvsframes = cl.worldmodel->surfacepvsframes;
                vis = Mod_LeafPVS (viewleaf, cl.worldmodel);
                for (j = 0;j < cl.worldmodel->numleafs;j += 8)
                {
@@ -1755,23 +1808,11 @@ void R_PVSUpdate (mleaf_t *viewleaf)
                                                leaf->pvsframe = r_pvsframecount;
                                                // mark surfaces bounding this leaf as visible
                                                for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--)
-                                                       (*mark++)->pvsframe = r_pvsframecount;
+                                                       surfacepvsframes[*mark++] = r_pvsframecount;
                                        }
                                }
                        }
                }
-               // build pvs surfacechain
-               r_pvsfirstsurface = NULL;
-               mark = &r_pvsfirstsurface;
-               for (c = cl.worldmodel->nummodelsurfaces, surf = cl.worldmodel->surfaces + cl.worldmodel->firstmodelsurface;c;c--, surf++)
-               {
-                       if (surf->pvsframe == r_pvsframecount)
-                       {
-                               *mark = surf;
-                               mark = &surf->pvschain;
-                       }
-               }
-               *mark = NULL;
        }
 }
 
@@ -1788,7 +1829,7 @@ void R_DrawWorld (entity_render_t *ent)
        if (!viewleaf)
                return;
        if (r_surfaceworldnode.integer || viewleaf->contents == CONTENTS_SOLID)
-               R_SurfaceWorldNode ();
+               R_SurfaceWorldNode (ent);
        else
                R_PortalWorldNode (ent, viewleaf);
        R_DrawSurfaces(ent, true, true);
@@ -1824,7 +1865,6 @@ static void gl_surf_newmap(void)
        r_pvsframecount = 1;
        r_pvsviewleaf = NULL;
        r_pvsviewleafnovis = false;
-       r_pvsfirstsurface = NULL;
 }
 
 void GL_Surf_Init(void)
@@ -1837,12 +1877,11 @@ void GL_Surf_Init(void)
        Cvar_RegisterVariable(&r_ambient);
        Cvar_RegisterVariable(&r_vertexsurfaces);
        Cvar_RegisterVariable(&r_dlightmap);
-       //Cvar_RegisterVariable(&r_drawportals);
+       Cvar_RegisterVariable(&r_drawportals);
        Cvar_RegisterVariable(&r_testvis);
        Cvar_RegisterVariable(&r_floatbuildlightmap);
        Cvar_RegisterVariable(&r_detailtextures);
        Cvar_RegisterVariable(&r_surfaceworldnode);
-       Cvar_RegisterVariable(&r_cullsurface);
 
        R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
 }