cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"};
-cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"}; // used for testing renderer code changes, otherwise does nothing
+cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"};
typedef struct r_glsl_bloomshader_s
{
r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
- Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed\n");
+ Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
FOG_registercvars(); // FIXME: move this fog stuff to client?
Cvar_RegisterVariable(&r_nearclip);
Cvar_RegisterVariable(&r_showsurfaces);
return false;
}
+int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
+{
+ int i;
+ const mplane_t *p;
+ for (i = 0;i < numplanes;i++)
+ {
+ p = planes + i;
+ switch(p->signbits)
+ {
+ default:
+ case 0:
+ if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
+ return true;
+ break;
+ case 1:
+ if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
+ return true;
+ break;
+ case 2:
+ if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
+ return true;
+ break;
+ case 3:
+ if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
+ return true;
+ break;
+ case 4:
+ if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
+ return true;
+ break;
+ case 5:
+ if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
+ return true;
+ break;
+ case 6:
+ if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
+ return true;
+ break;
+ case 7:
+ if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
+ return true;
+ break;
+ }
+ }
+ return false;
+}
+
//==================================================================================
static void R_UpdateEntityLighting(entity_render_t *ent)
static void R_View_SetFrustum(void)
{
+ double slopex, slopey;
+
// break apart the view matrix into vectors for various purposes
Matrix4x4_ToVectors(&r_view.matrix, r_view.forward, r_view.left, r_view.up, r_view.origin);
VectorNegate(r_view.left, r_view.right);
- VectorMAM(1, r_view.forward, 1.0 / -r_view.frustum_x, r_view.left, r_view.frustum[0].normal);
- VectorMAM(1, r_view.forward, 1.0 / r_view.frustum_x, r_view.left, r_view.frustum[1].normal);
- VectorMAM(1, r_view.forward, 1.0 / -r_view.frustum_y, r_view.up, r_view.frustum[2].normal);
- VectorMAM(1, r_view.forward, 1.0 / r_view.frustum_y, r_view.up, r_view.frustum[3].normal);
+ slopex = 1.0 / r_view.frustum_x;
+ slopey = 1.0 / r_view.frustum_y;
+ VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
+ VectorMA(r_view.forward, slopex, r_view.left, r_view.frustum[1].normal);
+ VectorMA(r_view.forward, -slopey, r_view.up , r_view.frustum[2].normal);
+ VectorMA(r_view.forward, slopey, r_view.up , r_view.frustum[3].normal);
VectorCopy(r_view.forward, r_view.frustum[4].normal);
VectorNormalize(r_view.frustum[0].normal);
VectorNormalize(r_view.frustum[1].normal);
PlaneClassify(&r_view.frustum[3]);
PlaneClassify(&r_view.frustum[4]);
+ // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
+ VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
+ VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
+ VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[2]);
+ VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[3]);
+
// LordHavoc: note to all quake engine coders, Quake had a special case
// for 90 degrees which assumed a square view (wrong), so I removed it,
// Quake2 has it disabled as well.
extern void R_DrawLightningBeams (void);
extern void VM_CL_AddPolygonsToMeshQueue (void);
extern void R_DrawPortals (void);
+extern cvar_t cl_locs_show;
+static void R_DrawLocs(void);
void R_RenderScene(void)
{
// don't let sound skip if going slow
}
VM_CL_AddPolygonsToMeshQueue();
+ if (cl_locs_show.integer)
+ {
+ R_DrawLocs();
+ if (r_timereport_active)
+ R_TimeReport("showlocs");
+ }
+
if (r_drawportals.integer)
{
R_DrawPortals();
GL_DepthMask(true);
}
GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
- GL_CullFace((ent->flags & RENDER_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+ GL_CullFace((ent->effects & EF_DOUBLESIDED) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
R_Mesh_VertexPointer(nomodelvertex3f);
if (r_refdef.fogenabled)
{
t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
else if (t->currentalpha < 1)
t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
- if (ent->flags & RENDER_NOCULLFACE)
- t->currentmaterialflags |= MATERIALFLAG_NOSHADOW;
+ if (ent->effects & EF_DOUBLESIDED)
+ t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
if (ent->effects & EF_NODEPTHTEST)
t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_NOSHADOW;
if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0)
rsurface_texture = NULL;
}
-void RSurf_ActiveEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
+void RSurf_ActiveWorldEntity(void)
+{
+ RSurf_CleanUp();
+ rsurface_entity = r_refdef.worldentity;
+ rsurface_model = r_refdef.worldmodel;
+ if (rsurface_array_size < rsurface_model->surfmesh.num_vertices)
+ R_Mesh_ResizeArrays(rsurface_model->surfmesh.num_vertices);
+ R_Mesh_Matrix(&identitymatrix);
+ VectorCopy(r_view.origin, rsurface_modelorg);
+ rsurface_modelvertex3f = rsurface_model->surfmesh.data_vertex3f;
+ rsurface_modelsvector3f = rsurface_model->surfmesh.data_svector3f;
+ rsurface_modeltvector3f = rsurface_model->surfmesh.data_tvector3f;
+ rsurface_modelnormal3f = rsurface_model->surfmesh.data_normal3f;
+ rsurface_generatedvertex = false;
+ rsurface_vertex3f = rsurface_modelvertex3f;
+ rsurface_svector3f = rsurface_modelsvector3f;
+ rsurface_tvector3f = rsurface_modeltvector3f;
+ rsurface_normal3f = rsurface_modelnormal3f;
+}
+
+void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
{
RSurf_CleanUp();
- Matrix4x4_Transform(&ent->inversematrix, r_view.origin, rsurface_modelorg);
rsurface_entity = ent;
rsurface_model = ent->model;
if (rsurface_array_size < rsurface_model->surfmesh.num_vertices)
static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
{
GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
- GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+ GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
if (rsurface_mode != RSURFMODE_SHOWSURFACES)
{
rsurface_mode = RSURFMODE_SHOWSURFACES;
R_Mesh_Matrix(&rsurface_entity->matrix);
}
GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
- GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+ GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
GL_DepthMask(true);
// LordHavoc: HalfLife maps have freaky skypolys so don't use
// skymasking on them, and Quake3 never did sky masking (unlike
else if (rsurface_texture->currentnumlayers)
{
GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
- GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+ GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
GL_BlendFunc(rsurface_texture->currentlayers[0].blendfunc1, rsurface_texture->currentlayers[0].blendfunc2);
GL_DepthMask(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED));
GL_Color(rsurface_entity->colormod[0], rsurface_entity->colormod[1], rsurface_entity->colormod[2], rsurface_texture->currentalpha);
// if the model is static it doesn't matter what value we give for
// wantnormals and wanttangents, so this logic uses only rules applicable
// to a model, knowing that they are meaningless otherwise
- if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
- RSurf_ActiveEntity(ent, false, false);
+ if (ent == r_refdef.worldentity)
+ RSurf_ActiveWorldEntity();
+ else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
+ RSurf_ActiveModelEntity(ent, false, false);
else
- RSurf_ActiveEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
+ RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
for (i = 0;i < numsurfaces;i = j)
{
RSurf_CleanUp();
}
-void R_QueueSurfaceList(int numsurfaces, msurface_t **surfacelist)
+void R_QueueSurfaceList(int numsurfaces, msurface_t **surfacelist, int flagsmask)
{
int i, j;
vec3_t tempcenter, center;
texture = surfacelist[i]->texture;
rsurface_texture = texture->currentframe;
rsurface_uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
+ if (!(rsurface_texture->currentmaterialflags & flagsmask))
+ {
+ // if this texture is not the kind we want, skip ahead to the next one
+ for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
+ ;
+ continue;
+ }
if (rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED)
{
// transparent surfaces get pushed off into the transparent queue
}
else
{
- // simply scan ahead until we find a different texture
- for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface_uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++);
+ // simply scan ahead until we find a different texture or lightmap state
+ for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface_uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
+ ;
// render the range of surfaces
R_DrawTextureSurfaceList(j - i, surfacelist + i);
}
}
}
+float locboxvertex3f[6*4*3] =
+{
+ 1,0,1, 1,0,0, 1,1,0, 1,1,1,
+ 0,1,1, 0,1,0, 0,0,0, 0,0,1,
+ 1,1,1, 1,1,0, 0,1,0, 0,1,1,
+ 0,0,1, 0,0,0, 1,0,0, 1,0,1,
+ 0,0,1, 1,0,1, 1,1,1, 0,1,1,
+ 1,0,0, 0,0,0, 0,1,0, 1,1,0
+};
+
+int locboxelement3i[6*2*3] =
+{
+ 0, 1, 2, 0, 2, 3,
+ 4, 5, 6, 4, 6, 7,
+ 8, 9,10, 8,10,11,
+ 12,13,14, 12,14,15,
+ 16,17,18, 16,18,19,
+ 20,21,22, 20,22,23
+};
+
+void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+{
+ int i, j;
+ cl_locnode_t *loc = (cl_locnode_t *)ent;
+ vec3_t mins, size;
+ float vertex3f[6*4*3];
+ CHECKGLERROR
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_DepthMask(false);
+ GL_DepthTest(true);
+ GL_CullFace(GL_NONE);
+ R_Mesh_Matrix(&identitymatrix);
+
+ R_Mesh_VertexPointer(vertex3f);
+ R_Mesh_ColorPointer(NULL);
+ R_Mesh_ResetTextureState();
+
+ i = surfacelist[0];
+ GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_view.colorscale,
+ ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_view.colorscale,
+ ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_view.colorscale,
+ surfacelist[0] < 0 ? 0.5f : 0.125f);
+
+ if (VectorCompare(loc->mins, loc->maxs))
+ {
+ VectorSet(size, 2, 2, 2);
+ VectorMA(loc->mins, -0.5f, size, mins);
+ }
+ else
+ {
+ VectorCopy(loc->mins, mins);
+ VectorSubtract(loc->maxs, loc->mins, size);
+ }
+
+ for (i = 0;i < 6*4*3;)
+ for (j = 0;j < 3;j++, i++)
+ vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
+
+ R_Mesh_Draw(0, 6*4, 6*2, locboxelement3i);
+}
+
+void R_DrawLocs(void)
+{
+ int index;
+ cl_locnode_t *loc, *nearestloc;
+ vec3_t center;
+ nearestloc = CL_Locs_FindNearest(cl.movement_origin);
+ for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
+ {
+ VectorLerp(loc->mins, 0.5f, loc->maxs, center);
+ R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
+ }
+}
+
void R_DrawCollisionBrushes(entity_render_t *ent)
{
int i;
}
extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
-void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
+void R_DrawWorldSurfaces(qboolean skysurfaces)
{
- int i, j, k, l, endj, f, flagsmask;
+ int i, j, endj, f, flagsmask;
int counttriangles = 0;
- msurface_t *surface, *endsurface, **surfacechain;
+ msurface_t *surface, **surfacechain;
texture_t *t;
- q3mbrush_t *brush;
- model_t *model = ent->model;
- const int *elements;
+ model_t *model = r_refdef.worldmodel;
const int maxsurfacelist = 1024;
int numsurfacelist = 0;
msurface_t *surfacelist[1024];
- vec3_t v;
if (model == NULL)
return;
- // if the model is static it doesn't matter what value we give for
- // wantnormals and wanttangents, so this logic uses only rules applicable
- // to a model, knowing that they are meaningless otherwise
- if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
- RSurf_ActiveEntity(ent, false, false);
- else
- RSurf_ActiveEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
+ RSurf_ActiveWorldEntity();
// update light styles
if (!skysurfaces && model->brushq1.light_styleupdatechains)
}
}
- R_UpdateAllTextureInfo(ent);
+ R_UpdateAllTextureInfo(r_refdef.worldentity);
flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
f = 0;
t = NULL;
rsurface_uselightmaptexture = false;
rsurface_texture = NULL;
numsurfacelist = 0;
- if (ent == r_refdef.worldentity)
+ j = model->firstmodelsurface;
+ endj = j + model->nummodelsurfaces;
+ while (j < endj)
{
- j = model->firstmodelsurface;
- endj = j + model->nummodelsurfaces;
- while (j < endj)
- {
- // quickly skip over non-visible surfaces
- for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
- ;
- // quickly iterate over visible surfaces
- for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
- {
- // process this surface
- surface = model->data_surfaces + j;
- // if this surface fits the criteria, add it to the list
- if (surface->texture->basematerialflags & flagsmask && surface->num_triangles)
- {
- // if lightmap parameters changed, rebuild lightmap texture
- if (surface->cached_dlight)
- R_BuildLightMap(ent, surface);
- // add face to draw list
- surfacelist[numsurfacelist++] = surface;
- counttriangles += surface->num_triangles;
- if (numsurfacelist >= maxsurfacelist)
- {
- R_QueueSurfaceList(numsurfacelist, surfacelist);
- numsurfacelist = 0;
- }
- }
- }
- }
- }
- else
- {
- surface = model->data_surfaces + model->firstmodelsurface;
- endsurface = surface + model->nummodelsurfaces;
- for (;surface < endsurface;surface++)
+ // quickly skip over non-visible surfaces
+ for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
+ ;
+ // quickly iterate over visible surfaces
+ for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
{
+ // process this surface
+ surface = model->data_surfaces + j;
// if this surface fits the criteria, add it to the list
- if (surface->texture->basematerialflags & flagsmask && surface->num_triangles)
+ if (surface->num_triangles)
{
// if lightmap parameters changed, rebuild lightmap texture
if (surface->cached_dlight)
- R_BuildLightMap(ent, surface);
+ R_BuildLightMap(r_refdef.worldentity, surface);
// add face to draw list
surfacelist[numsurfacelist++] = surface;
counttriangles += surface->num_triangles;
if (numsurfacelist >= maxsurfacelist)
{
- R_QueueSurfaceList(numsurfacelist, surfacelist);
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
numsurfacelist = 0;
}
}
}
}
if (numsurfacelist)
- R_QueueSurfaceList(numsurfacelist, surfacelist);
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
+ r_refdef.stats.entities_triangles += counttriangles;
+ RSurf_CleanUp();
+
+ if (r_showcollisionbrushes.integer && !skysurfaces)
+ R_DrawCollisionBrushes(r_refdef.worldentity);
+
+ if (r_showtris.integer || r_shownormals.integer)
+ R_DrawTrianglesAndNormals(r_refdef.worldentity, r_showtris.integer, r_shownormals.integer, flagsmask);
+}
+
+void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces)
+{
+ int i, f, flagsmask;
+ int counttriangles = 0;
+ msurface_t *surface, *endsurface, **surfacechain;
+ texture_t *t;
+ model_t *model = ent->model;
+ const int maxsurfacelist = 1024;
+ int numsurfacelist = 0;
+ msurface_t *surfacelist[1024];
+ if (model == NULL)
+ return;
+
+ // if the model is static it doesn't matter what value we give for
+ // wantnormals and wanttangents, so this logic uses only rules applicable
+ // to a model, knowing that they are meaningless otherwise
+ if (ent == r_refdef.worldentity)
+ RSurf_ActiveWorldEntity();
+ else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
+ RSurf_ActiveModelEntity(ent, false, false);
+ else
+ RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
+
+ // update light styles
+ if (!skysurfaces && model->brushq1.light_styleupdatechains)
+ {
+ for (i = 0;i < model->brushq1.light_styles;i++)
+ {
+ if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
+ {
+ model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
+ if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
+ for (;(surface = *surfacechain);surfacechain++)
+ surface->cached_dlight = true;
+ }
+ }
+ }
+
+ R_UpdateAllTextureInfo(ent);
+ flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
+ f = 0;
+ t = NULL;
+ rsurface_uselightmaptexture = false;
+ rsurface_texture = NULL;
+ numsurfacelist = 0;
+ surface = model->data_surfaces + model->firstmodelsurface;
+ endsurface = surface + model->nummodelsurfaces;
+ for (;surface < endsurface;surface++)
+ {
+ // if this surface fits the criteria, add it to the list
+ if (surface->num_triangles)
+ {
+ // if lightmap parameters changed, rebuild lightmap texture
+ if (surface->cached_dlight)
+ R_BuildLightMap(ent, surface);
+ // add face to draw list
+ surfacelist[numsurfacelist++] = surface;
+ counttriangles += surface->num_triangles;
+ if (numsurfacelist >= maxsurfacelist)
+ {
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
+ numsurfacelist = 0;
+ }
+ }
+ }
+ if (numsurfacelist)
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
r_refdef.stats.entities_triangles += counttriangles;
RSurf_CleanUp();