#define MAX_LIGHTMAP_SIZE 256
cvar_t r_ambient = {0, "r_ambient", "0", "brighter world cheat (not allowed in multiplayer), value is 0-128"};
-cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
cvar_t r_lockpvs = {0, "r_lockpvs", "0", "disables pvs switching, allows you to walk around and inspect what is visible from a given location in the map (anything not visible from your current location will not be drawn)"};
cvar_t r_lockvisibility = {0, "r_lockvisibility", "0", "disables visibility updates, allows you to walk around and inspect what is visible from a given viewpoint in the map (anything offscreen at the moment this is enabled will not be drawn)"};
cvar_t r_useportalculling = {0, "r_useportalculling", "1", "use advanced portal culling visibility method to improve performance over just Potentially Visible Set, provides an even more significant speed improvement in unvised maps"};
cvar_t r_q3bsp_renderskydepth = {0, "r_q3bsp_renderskydepth", "0", "draws sky depth masking in q3 maps (as in q1 maps), this means for example that sky polygons can hide other things"};
-// 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
-unsigned char r_pvsbits[(32768+7)>>3];
-// TODO: dynamic resize according to r_refdef.worldmodel->brush.num_leafs
-unsigned char r_worldleafvisible[32768];
-// TODO: dynamic resize according to r_refdef.worldmodel->num_surfaces
-unsigned char r_worldsurfacevisible[262144];
-// if true, the view is currently in a leaf without pvs data
-qboolean r_worldnovis;
-
/*
===============
R_BuildLightMap
=============================================================
*/
-static void R_DrawPortal_Callback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+static void R_DrawPortal_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
+ // due to the hacky nature of this function's parameters, this is never
+ // called with a batch, so numsurfaces is always 1, and the surfacelist
+ // contains only a leaf number for coloring purposes
const mportal_t *portal = (mportal_t *)ent;
int i, numpoints;
float *v;
float vertex3f[POLYGONELEMENTS_MAXPOINTS*3];
+ CHECKGLERROR
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_DepthMask(false);
GL_DepthTest(true);
- qglDisable(GL_CULL_FACE);
+ qglDisable(GL_CULL_FACE);CHECKGLERROR
R_Mesh_Matrix(&identitymatrix);
numpoints = min(portal->numpoints, POLYGONELEMENTS_MAXPOINTS);
R_Mesh_ColorPointer(NULL);
R_Mesh_ResetTextureState();
- i = surfacenumber;
- GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f),
- ((i & 0x0038) >> 3) * (1.0f / 7.0f),
- ((i & 0x01C0) >> 6) * (1.0f / 7.0f),
+ 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,
0.125f);
for (i = 0, v = vertex3f;i < numpoints;i++, v += 3)
VectorCopy(portal->points[i].position, v);
R_Mesh_Draw(0, numpoints, numpoints - 2, polygonelements);
- qglEnable(GL_CULL_FACE);
+ qglEnable(GL_CULL_FACE);CHECKGLERROR
}
// LordHavoc: this is just a nice debugging tool, very slow
-static void R_DrawPortals(void)
+void R_DrawPortals(void)
{
int i, leafnum;
mportal_t *portal;
return;
for (leafnum = 0;leafnum < r_refdef.worldmodel->brush.num_leafs;leafnum++)
{
- if (r_worldleafvisible[leafnum])
+ if (r_viewcache.world_leafvisible[leafnum])
{
//for (portalnum = 0, portal = model->brush.data_portals;portalnum < model->brush.num_portals;portalnum++, portal++)
for (portal = r_refdef.worldmodel->brush.data_leafs[leafnum].portals;portal;portal = portal->next)
}
}
-void R_WorldVisibility(void)
+void R_View_WorldVisibility(void)
{
int i, j, *mark;
mleaf_t *leaf;
return;
// if possible find the leaf the view origin is in
- viewleaf = model->brush.PointInLeaf ? model->brush.PointInLeaf(model, r_vieworigin) : NULL;
+ viewleaf = model->brush.PointInLeaf ? model->brush.PointInLeaf(model, r_view.origin) : NULL;
// if possible fetch the visible cluster bits
if (!r_lockpvs.integer && model->brush.FatPVS)
- model->brush.FatPVS(model, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
+ model->brush.FatPVS(model, r_view.origin, 2, r_viewcache.world_pvsbits, sizeof(r_viewcache.world_pvsbits));
if (!r_lockvisibility.integer)
{
// clear the visible surface and leaf flags arrays
- memset(r_worldsurfacevisible, 0, model->num_surfaces);
- memset(r_worldleafvisible, 0, model->brush.num_leafs);
+ memset(r_viewcache.world_surfacevisible, 0, model->num_surfaces);
+ memset(r_viewcache.world_leafvisible, 0, model->brush.num_leafs);
- r_worldnovis = false;
+ r_viewcache.world_novis = false;
// if floating around in the void (no pvs data available, and no
// portals available), simply use all on-screen leafs.
// no visibility method: (used when floating around in the void)
// simply cull each leaf to the frustum (view pyramid)
// similar to quake's RecursiveWorldNode but without cache misses
- r_worldnovis = true;
+ r_viewcache.world_novis = true;
for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++)
{
// if leaf is in current pvs and on the screen, mark its surfaces
if (!R_CullBox(leaf->mins, leaf->maxs))
{
- renderstats.world_leafs++;
- r_worldleafvisible[j] = true;
+ r_refdef.stats.world_leafs++;
+ r_viewcache.world_leafvisible[j] = true;
if (leaf->numleafsurfaces)
for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
- r_worldsurfacevisible[*mark] = true;
+ r_viewcache.world_surfacevisible[*mark] = true;
}
}
}
for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++)
{
// 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))
+ if (CHECKPVSBIT(r_viewcache.world_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs))
{
- renderstats.world_leafs++;
- r_worldleafvisible[j] = true;
+ r_refdef.stats.world_leafs++;
+ r_viewcache.world_leafvisible[j] = true;
if (leaf->numleafsurfaces)
for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
- r_worldsurfacevisible[*mark] = true;
+ r_viewcache.world_surfacevisible[*mark] = true;
}
}
}
leafstackpos = 1;
while (leafstackpos)
{
- renderstats.world_leafs++;
+ r_refdef.stats.world_leafs++;
leaf = leafstack[--leafstackpos];
- r_worldleafvisible[leaf - model->brush.data_leafs] = true;
+ r_viewcache.world_leafvisible[leaf - model->brush.data_leafs] = true;
// mark any surfaces bounding this leaf
if (leaf->numleafsurfaces)
for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
- r_worldsurfacevisible[*mark] = true;
+ r_viewcache.world_surfacevisible[*mark] = true;
// follow portals into other leafs
// the checks are:
// if viewer is behind portal (portal faces outward into the scene)
// (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))
+ r_refdef.stats.world_portals++;
+ if (DotProduct(r_view.origin, p->plane.normal) < (p->plane.dist + 1) && !R_CullBox(p->mins, p->maxs) && !r_viewcache.world_leafvisible[p->past - model->brush.data_leafs] && CHECKPVSBIT(r_viewcache.world_pvsbits, p->past->clusterindex))
leafstack[leafstackpos++] = p->past;
}
}
}
}
-
- if (r_drawportals.integer)
- R_DrawPortals();
}
void R_Q1BSP_DrawSky(entity_render_t *ent)
else
{
projectdistance = lightradius + model->radius*2;
- RSurf_ActiveEntity(ent);
+ RSurf_ActiveEntity(ent, false, false);
R_Shadow_PrepareShadowMark(model->surfmesh.num_triangles);
// identify lit faces within the bounding box
for (modelsurfacelistindex = 0;modelsurfacelistindex < modelnumsurfaces;modelsurfacelistindex++)
}
}
-static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+#define BATCHSIZE 256
+
+static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
- msurface_t *surface = ent->model->data_surfaces + surfacenumber;
- R_UpdateTextureInfo(ent, surface->texture);
+ int surfacelistindex, batchcount;
+ texture_t *t;
+ msurface_t *batchsurfaces[BATCHSIZE];
+ // note: in practice this never actualy batches, oh well
R_Shadow_RenderMode_Begin();
R_Shadow_RenderMode_ActiveLight((rtlight_t *)rtlight);
R_Shadow_RenderMode_Lighting(false, true);
R_Shadow_SetupEntityLight(ent);
- rsurface_texture = surface->texture->currentframe;
- R_Shadow_RenderSurfacesLighting(1, &surface);
+ t = NULL;
+ batchcount = 0;
+ for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+ {
+ msurface_t *surface = ent->model->data_surfaces + surfacelist[surfacelistindex];
+ if (t != surface->texture)
+ {
+ if (batchcount > 0)
+ R_Shadow_RenderSurfacesLighting(batchcount, batchsurfaces);
+ batchcount = 0;
+ t = surface->texture;
+ R_UpdateTextureInfo(ent, t);
+ rsurface_texture = t->currentframe;
+ }
+ batchsurfaces[batchcount++] = surface;
+ }
+ if (batchcount > 0)
+ R_Shadow_RenderSurfacesLighting(batchcount, batchsurfaces);
R_Shadow_RenderMode_End();
}
tempcenter[1] = (batchsurface->mins[1] + batchsurface->maxs[1]) * 0.5f;
tempcenter[2] = (batchsurface->mins[2] + batchsurface->maxs[2]) * 0.5f;
Matrix4x4_Transform(&rsurface_entity->matrix, tempcenter, center);
- R_MeshQueue_AddTransparent(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_vieworigin : center, R_Q1BSP_DrawLight_TransparentCallback, rsurface_entity, batchsurface - rsurface_model->data_surfaces, r_shadow_rtlight);
+ R_MeshQueue_AddTransparent(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_view.origin : center, R_Q1BSP_DrawLight_TransparentCallback, rsurface_entity, batchsurface - rsurface_model->data_surfaces, r_shadow_rtlight);
}
}
msurface_t *batchsurfacelist[RSURF_MAX_BATCHSURFACES];
texture_t *tex;
qboolean skip;
- RSurf_ActiveEntity(ent);
+ CHECKGLERROR
+ RSurf_ActiveEntity(ent, true, true);
R_UpdateAllTextureInfo(ent);
tex = NULL;
rsurface_texture = NULL;
skip = false;
batchnumsurfaces = 0;
+ CHECKGLERROR
for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
{
- if ((ent == r_refdef.worldentity && !r_worldsurfacevisible[surfacelist[surfacelistindex]]))
+ if ((ent == r_refdef.worldentity && !r_viewcache.world_surfacevisible[surfacelist[surfacelistindex]]))
continue;
surface = model->data_surfaces + surfacelist[surfacelistindex];
- renderstats.lights_lighttriangles += surface->num_triangles;
+ r_refdef.stats.lights_lighttriangles += surface->num_triangles;
if (tex != surface->texture)
{
if (batchnumsurfaces > 0)
R_Shadow_RenderSurfacesLighting(batchnumsurfaces, batchsurfacelist);
batchnumsurfaces = 0;
}
- qglEnable(GL_CULL_FACE);
+ qglEnable(GL_CULL_FACE);CHECKGLERROR
}
//Made by [515]
{
Cvar_RegisterVariable(&r_ambient);
- Cvar_RegisterVariable(&r_drawportals);
Cvar_RegisterVariable(&r_lockpvs);
Cvar_RegisterVariable(&r_lockvisibility);
Cvar_RegisterVariable(&r_useportalculling);