]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rsurf.c
eliminated qbyte type, now uses unsigned char throughout the engine for this purpose
[xonotic/darkplaces.git] / gl_rsurf.c
index f739601c0f88b5763bc1a47dfa5b76eb4eb532af..68ac13e4c83afa44bc6a76da7cad7f5b0f1cfc0c 100644 (file)
@@ -28,7 +28,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 cvar_t r_ambient = {0, "r_ambient", "0"};
 cvar_t r_drawportals = {0, "r_drawportals", "0"};
 cvar_t r_testvis = {0, "r_testvis", "0"};
-cvar_t r_detailtextures = {CVAR_SAVE, "r_detailtextures", "1"};
 cvar_t r_surfaceworldnode = {0, "r_surfaceworldnode", "0"};
 cvar_t r_drawcollisionbrushes_polygonfactor = {0, "r_drawcollisionbrushes_polygonfactor", "-1"};
 cvar_t r_drawcollisionbrushes_polygonoffset = {0, "r_drawcollisionbrushes_polygonoffset", "0"};
@@ -37,11 +36,11 @@ cvar_t r_q3bsp_renderskydepth = {0, "r_q3bsp_renderskydepth", "0"};
 // flag arrays used for visibility checking on world model
 // (all other entities have no per-surface/per-leaf visibility checks)
 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_clusters
-qbyte r_pvsbits[(32768+7)>>3];
+unsigned char r_pvsbits[(32768+7)>>3];
 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_leafs
-qbyte r_worldleafvisible[32768];
+unsigned char r_worldleafvisible[32768];
 // TODO: dynamic resize according to r_refdef.worldmodel->num_surfaces
-qbyte r_worldsurfacevisible[262144];
+unsigned char r_worldsurfacevisible[262144];
 
 /*
 ===============
@@ -54,9 +53,9 @@ void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface)
 {
        int smax, tmax, i, j, size, size3, maps, stride, l;
        unsigned int *bl, scale;
-       qbyte *lightmap, *out, *stain;
+       unsigned char *lightmap, *out, *stain;
        static unsigned int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
-       static qbyte templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
+       static unsigned char templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
 
        // update cached lighting info
        surface->cached_dlight = 0;
@@ -84,7 +83,7 @@ void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface)
                {
                        bl = intblocklights;
                        for (maps = 0;maps < MAXLIGHTMAPS && surface->lightmapinfo->styles[maps] != 255;maps++, lightmap += size3)
-                               for (scale = d_lightstylevalue[surface->lightmapinfo->styles[maps]], i = 0;i < size3;i++)
+                               for (scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[maps]], i = 0;i < size3;i++)
                                        bl[i] += lightmap[i] * scale;
                }
        }
@@ -132,7 +131,7 @@ void R_StainNode (mnode_t *node, model_t *model, const vec3_t origin, float radi
        float ndist, a, ratio, maxdist, maxdist2, maxdist3, invradius, sdtable[256], td, dist2;
        msurface_t *surface, *endsurface;
        int i, s, t, smax, tmax, smax3, impacts, impactt, stained;
-       qbyte *bl;
+       unsigned char *bl;
        vec3_t impact;
 
        maxdist = radius * radius;
@@ -210,9 +209,9 @@ loc0:
                                                        {
                                                                if (a > 1)
                                                                        a = 1;
-                                                               bl[0] = (qbyte) ((float) bl[0] + a * ((fcolor[0] + ratio * fcolor[4]) - (float) bl[0]));
-                                                               bl[1] = (qbyte) ((float) bl[1] + a * ((fcolor[1] + ratio * fcolor[5]) - (float) bl[1]));
-                                                               bl[2] = (qbyte) ((float) bl[2] + a * ((fcolor[2] + ratio * fcolor[6]) - (float) bl[2]));
+                                                               bl[0] = (unsigned char) ((float) bl[0] + a * ((fcolor[0] + ratio * fcolor[4]) - (float) bl[0]));
+                                                               bl[1] = (unsigned char) ((float) bl[1] + a * ((fcolor[1] + ratio * fcolor[5]) - (float) bl[1]));
+                                                               bl[2] = (unsigned char) ((float) bl[2] + a * ((fcolor[2] + ratio * fcolor[6]) - (float) bl[2]));
                                                                stained = true;
                                                        }
                                                }
@@ -276,7 +275,6 @@ void R_Stain (const vec3_t origin, float radius, int cr1, int cg1, int cb1, int
                model = ent->model;
                if (model && model->name[0] == '*')
                {
-                       Mod_CheckLoaded(model);
                        if (model->brush.data_nodes)
                        {
                                Matrix4x4_Transform(&ent->inversematrix, origin, org);
@@ -300,7 +298,7 @@ static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
        int i;
        float *v;
        rmeshstate_t m;
-       const mportal_t *portal = calldata1;
+       const mportal_t *portal = (mportal_t *)calldata1;
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        GL_DepthMask(false);
        GL_DepthTest(true);
@@ -422,7 +420,7 @@ void R_WorldVisibility(void)
                        // if leaf is in current pvs and on the screen, mark its surfaces
                        if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs))
                        {
-                               c_leafs++;
+                               renderstats.world_leafs++;
                                r_worldleafvisible[j] = true;
                                if (leaf->numleafsurfaces)
                                        for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
@@ -444,7 +442,7 @@ void R_WorldVisibility(void)
                leafstackpos = 1;
                while (leafstackpos)
                {
-                       c_leafs++;
+                       renderstats.world_leafs++;
                        leaf = leafstack[--leafstackpos];
                        r_worldleafvisible[leaf - model->brush.data_leafs] = true;
                        // mark any surfaces bounding this leaf
@@ -459,8 +457,11 @@ void R_WorldVisibility(void)
                        // and the leaf is visible in the pvs
                        // (the first two checks won't cause as many cache misses as the leaf checks)
                        for (p = leaf->portals;p;p = p->next)
+                       {
+                               renderstats.world_portals++;
                                if (DotProduct(r_vieworigin, p->plane.normal) < (p->plane.dist + 1) && !R_CullBox(p->mins, p->maxs) && !r_worldleafvisible[p->past - model->brush.data_leafs] && CHECKPVSBIT(r_pvsbits, p->past->clusterindex))
                                        leafstack[leafstackpos++] = p->past;
+                       }
                }
        }
 
@@ -478,17 +479,17 @@ void R_Q1BSP_DrawSky(entity_render_t *ent)
 
 void R_Q1BSP_Draw(entity_render_t *ent)
 {
-       if (ent->model == NULL)
+       model_t *model = ent->model;
+       if (model == NULL)
                return;
-       c_bmodels++;
        if (r_drawcollisionbrushes.integer < 2)
                R_DrawSurfaces(ent, false);
-       if (r_drawcollisionbrushes.integer >= 1 && ent->model->brush.num_brushes)
+       if (r_drawcollisionbrushes.integer >= 1 && model->brush.num_brushes)
        {
                int i;
-               model_t *model = ent->model;
                msurface_t *surface;
                q3mbrush_t *brush;
+               R_Mesh_Matrix(&ent->matrix);
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
                GL_DepthMask(false);
                GL_DepthTest(true);
@@ -509,16 +510,16 @@ typedef struct r_q1bsp_getlightinfo_s
        vec3_t relativelightorigin;
        float lightradius;
        int *outleaflist;
-       qbyte *outleafpvs;
+       unsigned char *outleafpvs;
        int outnumleafs;
        int *outsurfacelist;
-       qbyte *outsurfacepvs;
+       unsigned char *outsurfacepvs;
        int outnumsurfaces;
        vec3_t outmins;
        vec3_t outmaxs;
        vec3_t lightmins;
        vec3_t lightmaxs;
-       const qbyte *pvs;
+       const unsigned char *pvs;
 }
 r_q1bsp_getlightinfo_t;
 
@@ -528,18 +529,22 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node)
        mleaf_t *leaf;
        for (;;)
        {
-               if (!BoxesOverlap(info->lightmins, info->lightmaxs, node->mins, node->maxs))
-                       return;
-               if (!node->plane)
+               mplane_t *plane = node->plane;
+               //if (!BoxesOverlap(info->lightmins, info->lightmaxs, node->mins, node->maxs))
+               //      return;
+               if (!plane)
                        break;
-               sides = BoxOnPlaneSide(info->lightmins, info->lightmaxs, node->plane) - 1;
-               if (sides == 2)
+               if (plane->type < 3)
+                       sides = ((info->lightmaxs[plane->type] >= plane->dist) | ((info->lightmins[plane->type] < plane->dist) << 1));
+               else
+                       sides = BoxOnPlaneSide(info->lightmins, info->lightmaxs, plane);
+               if (sides == 3)
                {
                        R_Q1BSP_RecursiveGetLightInfo(info, node->children[0]);
                        node = node->children[1];
                }
                else
-                       node = node->children[sides];
+                       node = node->children[sides - 1];
        }
        leaf = (mleaf_t *)node;
        if (info->pvs == NULL || CHECKPVSBIT(info->pvs, leaf->clusterindex))
@@ -593,7 +598,7 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node)
        }
 }
 
-void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, qbyte *outleafpvs, int *outnumleafspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer)
+void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer)
 {
        r_q1bsp_getlightinfo_t info;
        VectorCopy(relativelightorigin, info.relativelightorigin);
@@ -656,6 +661,29 @@ void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, floa
        *outnumsurfacespointer = info.outnumsurfaces;
 }
 
+void R_Q1BSP_CompileShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist)
+{
+       model_t *model = ent->model;
+       msurface_t *surface;
+       int surfacelistindex;
+       float projectdistance = lightradius + model->radius*2 + r_shadow_projectdistance.value;
+       texture_t *texture;
+       r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
+       R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles);
+       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+       {
+               surface = model->data_surfaces + surfacelist[surfacelistindex];
+               texture = surface->texture;
+               if ((texture->basematerialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_WALL)) != MATERIALFLAG_WALL)
+                       continue;
+               if (texture->textureflags & (Q3TEXTUREFLAG_TWOSIDED | Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
+                       continue;
+               R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, r_shadow_compilingrtlight->cullmins, r_shadow_compilingrtlight->cullmaxs, surface->mins, surface->maxs);
+       }
+       R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, lightradius + model->radius + projectdistance, numshadowmark, shadowmarklist);
+       r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, false, false);
+}
+
 extern float *rsurface_vertex3f;
 extern float *rsurface_svector3f;
 extern float *rsurface_tvector3f;
@@ -667,7 +695,7 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin,
        model_t *model = ent->model;
        msurface_t *surface;
        int surfacelistindex;
-       float projectdistance = lightradius + model->radius + r_shadow_projectdistance.value;
+       float projectdistance = lightradius + model->radius*2 + r_shadow_projectdistance.value;
        vec3_t modelorg;
        texture_t *texture;
        // check the box in modelspace, it was already checked in worldspace
@@ -675,42 +703,25 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin,
                return;
        if (r_drawcollisionbrushes.integer >= 2)
                return;
-       if (!r_shadow_compilingrtlight)
-               R_UpdateAllTextureInfo(ent);
+       R_UpdateAllTextureInfo(ent);
        if (model->brush.shadowmesh)
        {
                R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles);
-               if (r_shadow_compilingrtlight)
-               {
-                       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
-                       {
-                               surface = model->data_surfaces + surfacelist[surfacelistindex];
-                               texture = surface->texture;
-                               if ((texture->basematerialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_WALL)) != MATERIALFLAG_WALL)
-                                       continue;
-                               if (texture->textureflags & (Q3TEXTUREFLAG_TWOSIDED | Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
-                                       continue;
-                               R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs);
-                       }
-               }
-               else
+               for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
                {
-                       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
-                       {
-                               surface = model->data_surfaces + surfacelist[surfacelistindex];
-                               texture = surface->texture->currentframe;
-                               if ((texture->currentmaterialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_WALL)) != MATERIALFLAG_WALL)
-                                       continue;
-                               if (texture->textureflags & (Q3TEXTUREFLAG_TWOSIDED | Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
-                                       continue;
-                               R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs);
-                       }
+                       surface = model->data_surfaces + surfacelist[surfacelistindex];
+                       texture = surface->texture->currentframe;
+                       if ((texture->currentmaterialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_WALL)) != MATERIALFLAG_WALL)
+                               continue;
+                       if (texture->textureflags & (Q3TEXTUREFLAG_TWOSIDED | Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
+                               continue;
+                       R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs);
                }
                R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, lightradius + model->radius + projectdistance, numshadowmark, shadowmarklist);
        }
        else
        {
-               projectdistance = lightradius + ent->model->radius;
+               projectdistance = lightradius + ent->model->radius*2;
                Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
                for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
                {
@@ -728,97 +739,92 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin,
        }
 }
 
-void R_Q1BSP_DrawLight(entity_render_t *ent, float *lightcolor, int numsurfaces, const int *surfacelist)
+#define RSURF_MAX_BATCHSURFACES 1024
+
+void R_Q1BSP_DrawLight(entity_render_t *ent, float *lightcolorbase, float *lightcolorpants, float *lightcolorshirt, int numsurfaces, const int *surfacelist)
 {
        model_t *model = ent->model;
        msurface_t *surface;
        texture_t *texture;
-       int surfacelistindex;
+       int surfacelistindex, batchnumsurfaces;
+       msurface_t *batchsurfacelist[RSURF_MAX_BATCHSURFACES];
        vec3_t modelorg;
+       texture_t *tex;
+       rtexture_t *basetexture = NULL;
+       rtexture_t *glosstexture = NULL;
+       float specularscale = 0;
+       qboolean skip;
        if (r_drawcollisionbrushes.integer >= 2)
                return;
-       if (r_shadow_compilingrtlight)
+       if (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt) < 0.0001)
+               return;
+       R_UpdateAllTextureInfo(ent);
+       Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
+       tex = NULL;
+       texture = NULL;
+       skip = false;
+       batchnumsurfaces = 0;
+       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
-               // if compiling an rtlight, capture the meshes
-               int tri;
-               int *e;
-               float *lightmins, *lightmaxs, *v[3], *vertex3f;
-               for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+               if ((ent == r_refdef.worldentity && !r_worldsurfacevisible[surfacelist[surfacelistindex]]))
+                       continue;
+               surface = model->data_surfaces + surfacelist[surfacelistindex];
+               renderstats.lights_lighttriangles += surface->num_triangles;
+               if (tex != surface->texture)
                {
-                       surface = model->data_surfaces + surfacelist[surfacelistindex];
-                       texture = surface->texture;
-                       if ((texture->basematerialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) != MATERIALFLAG_WALL || !surface->num_triangles)
-                               continue;
-                       e = surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle;
-                       vertex3f = surface->groupmesh->data_vertex3f;
-                       lightmins = r_shadow_compilingrtlight->cullmins;
-                       lightmaxs = r_shadow_compilingrtlight->cullmaxs;
-                       for (tri = 0;tri < surface->num_triangles;tri++, e += 3)
+                       if (batchnumsurfaces > 0)
                        {
-                               v[0] = vertex3f + e[0] * 3;
-                               v[1] = vertex3f + e[1] * 3;
-                               v[2] = vertex3f + e[2] * 3;
-                               if (PointInfrontOfTriangle(r_shadow_compilingrtlight->shadoworigin, v[0], v[1], v[2]) && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
-                                       Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_light, surface->texture->skin.base, surface->texture->skin.gloss, surface->texture->skin.nmap, surface->groupmesh->data_vertex3f, surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, surface->groupmesh->data_texcoordtexture2f, 1, e);
+                               R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
+                               batchnumsurfaces = 0;
                        }
-               }
-       }
-       else
-       {
-               R_UpdateAllTextureInfo(ent);
-               Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
-               for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
-               {
-                       if (ent == r_refdef.worldentity && !r_worldsurfacevisible[surfacelist[surfacelistindex]])
-                               continue;
-                       surface = model->data_surfaces + surfacelist[surfacelistindex];
+                       tex = surface->texture;
                        texture = surface->texture->currentframe;
                        // FIXME: transparent surfaces need to be lit later
-                       if ((texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) != MATERIALFLAG_WALL || !surface->num_triangles)
+                       skip = (texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) != MATERIALFLAG_WALL;
+                       if (skip)
                                continue;
                        if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
                                qglDisable(GL_CULL_FACE);
-                       RSurf_SetVertexPointer(ent, texture, surface, modelorg);
-                       if (!rsurface_svector3f)
-                       {
-                               rsurface_svector3f = varray_svector3f;
-                               rsurface_tvector3f = varray_tvector3f;
-                               rsurface_normal3f = varray_normal3f;
-                               Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f);
-                       }
-                       if (ent->colormap >= 0)
+                       else
+                               qglEnable(GL_CULL_FACE);
+                       glosstexture = r_texture_black;
+                       specularscale = 0;
+                       if (texture->skin.gloss)
                        {
-                               vec3_t lightcolorpants, lightcolorshirt;
-                               // 128-224 are backwards ranges
-                               int b = (ent->colormap & 0xF) << 4;b += (b >= 128 && b < 224) ? 4 : 12;
-                               if (texture->skin.pants && b >= 224)
+                               if (r_shadow_gloss.integer >= 1 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
                                {
-                                       qbyte *bcolor = (qbyte *) (&palette_complete[b]);
-                                       lightcolorpants[0] = lightcolor[0] * bcolor[0] * (1.0f / 255.0f);
-                                       lightcolorpants[1] = lightcolor[1] * bcolor[1] * (1.0f / 255.0f);
-                                       lightcolorpants[2] = lightcolor[2] * bcolor[2] * (1.0f / 255.0f);
+                                       glosstexture = texture->skin.gloss;
+                                       specularscale = r_shadow_rtlight->specularscale * r_shadow_glossintensity.value;
                                }
-                               else
-                                       VectorClear(lightcolorpants);
-                               // 128-224 are backwards ranges
-                               b = (ent->colormap & 0xF0);b += (b >= 128 && b < 224) ? 4 : 12;
-                               if (texture->skin.shirt && b >= 224)
+                       }
+                       else
+                       {
+                               if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0 && r_shadow_glossintensity.value > 0 && r_shadow_rtlight->specularscale > 0)
                                {
-                                       qbyte *bcolor = (qbyte *) (&palette_complete[b]);
-                                       lightcolorshirt[0] = lightcolor[0] * bcolor[0] * (1.0f / 255.0f);
-                                       lightcolorshirt[1] = lightcolor[1] * bcolor[1] * (1.0f / 255.0f);
-                                       lightcolorshirt[2] = lightcolor[2] * bcolor[2] * (1.0f / 255.0f);
+                                       glosstexture = r_texture_white;
+                                       specularscale = r_shadow_rtlight->specularscale * r_shadow_gloss2intensity.value;
                                }
-                               else
-                                       VectorClear(lightcolorshirt);
-                               R_Shadow_RenderLighting(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle), rsurface_vertex3f, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, surface->groupmesh->data_texcoordtexture2f, lightcolor, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->skin.gloss);
                        }
-                       else
-                               R_Shadow_RenderLighting(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle), rsurface_vertex3f, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, surface->groupmesh->data_texcoordtexture2f, lightcolor, vec3_origin, vec3_origin, texture->skin.merged ? texture->skin.merged : texture->skin.base, NULL, NULL, texture->skin.nmap, texture->skin.gloss);
-                       if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
-                               qglEnable(GL_CULL_FACE);
+                       basetexture = (ent->colormap < 0 && texture->skin.merged) ? texture->skin.merged : texture->skin.base;
+                       if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * (VectorLength2(lightcolorbase) + VectorLength2(lightcolorpants) + VectorLength2(lightcolorshirt)) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
+                               skip = true;
                }
+               if (!skip && surface->num_triangles)
+               {
+                       if (batchnumsurfaces == RSURF_MAX_BATCHSURFACES)
+                       {
+                               R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
+                               batchnumsurfaces = 0;
+                       }
+                       batchsurfacelist[batchnumsurfaces++] = surface;
+               }
+       }
+       if (batchnumsurfaces > 0)
+       {
+               R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, glosstexture, specularscale, modelorg);
+               batchnumsurfaces = 0;
        }
+       qglEnable(GL_CULL_FACE);
 }
 
 #if 0
@@ -841,7 +847,6 @@ void GL_Surf_Init(void)
        Cvar_RegisterVariable(&r_ambient);
        Cvar_RegisterVariable(&r_drawportals);
        Cvar_RegisterVariable(&r_testvis);
-       Cvar_RegisterVariable(&r_detailtextures);
        Cvar_RegisterVariable(&r_surfaceworldnode);
        Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonfactor);
        Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonoffset);