#define MAX_LIGHTMAP_SIZE 256
-cvar_t r_ambient = {0, "r_ambient", "0"};
-cvar_t r_drawportals = {0, "r_drawportals", "0"};
-cvar_t r_lockpvs = {0, "r_lockpvs", "0"};
-cvar_t r_lockvisibility = {0, "r_lockvisibility", "0"};
-cvar_t r_useportalculling = {0, "r_useportalculling", "1"};
-cvar_t r_drawcollisionbrushes_polygonfactor = {0, "r_drawcollisionbrushes_polygonfactor", "-1"};
-cvar_t r_drawcollisionbrushes_polygonoffset = {0, "r_drawcollisionbrushes_polygonoffset", "0"};
-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
-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];
+cvar_t r_ambient = {0, "r_ambient", "0", "brighter world cheat (not allowed in multiplayer), value is 0-128"};
+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"};
/*
===============
*/
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;
+ int smax, tmax, i, size, size3, maps, l;
+ int *bl, scale;
unsigned char *lightmap, *out, *stain;
- static unsigned int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
+ model_t *model = ent->model;
+ static int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
static unsigned char templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
// update cached lighting info
// set to full bright if no light data
bl = intblocklights;
- if (!ent->model->brushq1.lightdata)
+ if (!model->brushq1.lightdata)
{
for (i = 0;i < size3;i++)
bl[i] = 255*256;
else
{
// clear to no light
- memset(bl, 0, size*3*sizeof(unsigned int));
+ memset(bl, 0, size3*sizeof(*bl));
// add all the lightmaps
if (lightmap)
- {
- bl = intblocklights;
for (maps = 0;maps < MAXLIGHTMAPS && surface->lightmapinfo->styles[maps] != 255;maps++, lightmap += size3)
for (scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[maps]], i = 0;i < size3;i++)
bl[i] += lightmap[i] * scale;
- }
}
stain = surface->lightmapinfo->stainsamples;
// scaling, and remaps the 0-65536 (2x overbright) to 0-256, it will
// be doubled during rendering to achieve 2x overbright
// (0 = 0.0, 128 = 1.0, 256 = 2.0)
- if (ent->model->brushq1.lightmaprgba)
+ if (model->brushq1.lightmaprgba)
{
- stride = (surface->lightmapinfo->lightmaptexturestride - smax) * 4;
- for (i = 0;i < tmax;i++, out += stride)
+ for (i = 0;i < size;i++)
{
- for (j = 0;j < smax;j++)
- {
- l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
- l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
- l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
- *out++ = 255;
- }
+ l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
+ l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
+ l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
+ *out++ = 255;
}
}
else
{
- stride = (surface->lightmapinfo->lightmaptexturestride - smax) * 3;
- for (i = 0;i < tmax;i++, out += stride)
+ for (i = 0;i < size;i++)
+ {
+ l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
+ l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
+ l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
+ }
+ }
+
+ R_UpdateTexture(surface->lightmaptexture, templight, surface->lightmapinfo->lightmaporigin[0], surface->lightmapinfo->lightmaporigin[1], smax, tmax);
+
+ // update the surface's deluxemap if it has one
+ if (surface->deluxemaptexture != r_texture_blanknormalmap)
+ {
+ vec3_t n;
+ unsigned char *normalmap = surface->lightmapinfo->nmapsamples;
+ lightmap = surface->lightmapinfo->samples;
+ // clear to no normalmap
+ bl = intblocklights;
+ memset(bl, 0, size3*sizeof(*bl));
+ // add all the normalmaps
+ if (lightmap && normalmap)
+ {
+ for (maps = 0;maps < MAXLIGHTMAPS && surface->lightmapinfo->styles[maps] != 255;maps++, lightmap += size3, normalmap += size3)
+ {
+ for (scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[maps]], i = 0;i < size;i++)
+ {
+ // add the normalmap with weighting proportional to the style's lightmap intensity
+ l = (int)(VectorLength(lightmap + i*3) * scale);
+ bl[i*3+0] += ((int)normalmap[i*3+0] - 128) * l;
+ bl[i*3+1] += ((int)normalmap[i*3+1] - 128) * l;
+ bl[i*3+2] += ((int)normalmap[i*3+2] - 128) * l;
+ }
+ }
+ }
+ bl = intblocklights;
+ out = templight;
+ // we simply renormalize the weighted normals to get a valid deluxemap
+ if (model->brushq1.lightmaprgba)
{
- for (j = 0;j < smax;j++)
+ for (i = 0;i < size;i++, bl += 3)
{
- l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
- l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
- l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
+ VectorCopy(bl, n);
+ VectorNormalize(n);
+ l = (int)(n[0] * 128 + 128);*out++ = bound(0, l, 255);
+ l = (int)(n[1] * 128 + 128);*out++ = bound(0, l, 255);
+ l = (int)(n[2] * 128 + 128);*out++ = bound(0, l, 255);
+ *out++ = 255;
}
}
+ else
+ {
+ for (i = 0;i < size;i++, bl += 3)
+ {
+ VectorCopy(bl, n);
+ VectorNormalize(n);
+ l = (int)(n[0] * 128 + 128);*out++ = bound(0, l, 255);
+ l = (int)(n[1] * 128 + 128);*out++ = bound(0, l, 255);
+ l = (int)(n[2] * 128 + 128);*out++ = bound(0, l, 255);
+ }
+ }
+ R_UpdateTexture(surface->deluxemaptexture, templight, surface->lightmapinfo->lightmaporigin[0], surface->lightmapinfo->lightmaporigin[1], smax, tmax);
}
-
- R_UpdateTexture(surface->lightmaptexture, templight);
}
void R_StainNode (mnode_t *node, model_t *model, const vec3_t origin, float radius, const float fcolor[8])
smax = (surface->lightmapinfo->extents[0] >> 4) + 1;
tmax = (surface->lightmapinfo->extents[1] >> 4) + 1;
- impacts = DotProduct (impact, surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3] - surface->lightmapinfo->texturemins[0];
- impactt = DotProduct (impact, surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3] - surface->lightmapinfo->texturemins[1];
+ impacts = (int)(DotProduct (impact, surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3] - surface->lightmapinfo->texturemins[0]);
+ impactt = (int)(DotProduct (impact, surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3] - surface->lightmapinfo->texturemins[1]);
s = bound(0, impacts, smax * 16) - impacts;
t = bound(0, impactt, tmax * 16) - impactt;
- i = s * s + t * t + dist2;
+ i = (int)(s * s + t * t + dist2);
if (i > maxdist)
continue;
R_StainNode(r_refdef.worldmodel->brush.data_nodes + r_refdef.worldmodel->brushq1.hulls[0].firstclipnode, r_refdef.worldmodel, origin, radius, fcolor);
// look for embedded bmodels
- for (n = 0;n < cl_num_brushmodel_entities;n++)
+ for (n = 0;n < cl.num_brushmodel_entities;n++)
{
- ent = &cl_entities[cl_brushmodel_entities[n]].render;
+ ent = &cl.entities[cl.brushmodel_entities[n]].render;
model = ent->model;
if (model && model->name[0] == '*')
{
=============================================================
*/
-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;
+ int i, numpoints;
float *v;
- rmeshstate_t m;
+ float vertex3f[POLYGONELEMENTS_MAXPOINTS*3];
+ CHECKGLERROR
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_DepthMask(false);
GL_DepthTest(true);
- R_Mesh_Matrix(&r_identitymatrix);
+ GL_CullFace(GL_NONE);
+ R_Mesh_Matrix(&identitymatrix);
- memset(&m, 0, sizeof(m));
- m.pointer_vertex = varray_vertex3f;
- R_Mesh_State(&m);
+ numpoints = min(portal->numpoints, POLYGONELEMENTS_MAXPOINTS);
- 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),
+ 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,
0.125f);
- if (PlaneDiff(r_vieworigin, (&portal->plane)) < 0)
- {
- for (i = portal->numpoints - 1, v = varray_vertex3f;i >= 0;i--, v += 3)
- VectorCopy(portal->points[i].position, v);
- }
- else
- for (i = 0, v = varray_vertex3f;i < portal->numpoints;i++, v += 3)
- VectorCopy(portal->points[i].position, v);
- GL_LockArrays(0, portal->numpoints);
- R_Mesh_Draw(0, portal->numpoints, portal->numpoints - 2, polygonelements);
- GL_LockArrays(0, 0);
+ for (i = 0, v = vertex3f;i < numpoints;i++, v += 3)
+ VectorCopy(portal->points[i].position, v);
+ R_Mesh_Draw(0, numpoints, numpoints - 2, polygonelements);
}
// 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)
}
}
-static void R_DrawCollisionBrush(colbrushf_t *brush)
-{
- int i;
- rmeshstate_t m;
- memset(&m, 0, sizeof(m));
- m.pointer_vertex = brush->points->v;
- R_Mesh_State(&m);
- i = (int)(((size_t)brush) / sizeof(colbrushf_t));
- GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
- GL_LockArrays(0, brush->numpoints);
- R_Mesh_Draw(0, brush->numpoints, brush->numtriangles, brush->elements);
- GL_LockArrays(0, 0);
-}
-
-static void R_DrawCollisionSurface(entity_render_t *ent, msurface_t *surface)
-{
- int i;
- rmeshstate_t m;
- if (!surface->num_collisiontriangles)
- return;
- memset(&m, 0, sizeof(m));
- m.pointer_vertex = surface->data_collisionvertex3f;
- R_Mesh_State(&m);
- i = (int)(((size_t)surface) / sizeof(msurface_t));
- GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
- GL_LockArrays(0, surface->num_collisionvertices);
- R_Mesh_Draw(0, surface->num_collisionvertices, surface->num_collisiontriangles, surface->data_collisionelement3i);
- GL_LockArrays(0, 0);
-}
-
-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_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_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_viewcache.world_leafvisible[p->past - model->brush.data_leafs]
+ && CHECKPVSBIT(r_viewcache.world_pvsbits, p->past->clusterindex)
+ && !R_CullBox(p->mins, p->maxs)
+ && leafstackpos < (int)(sizeof(leafstack) / sizeof(leafstack[0])))
leafstack[leafstackpos++] = p->past;
}
}
}
}
-
- if (r_drawportals.integer)
- R_DrawPortals();
}
void R_Q1BSP_DrawSky(entity_render_t *ent)
{
if (ent->model == NULL)
return;
- if (r_drawcollisionbrushes.integer < 2)
- R_DrawSurfaces(ent, true);
+ R_DrawSurfaces(ent, true);
}
void R_Q1BSP_Draw(entity_render_t *ent)
model_t *model = ent->model;
if (model == NULL)
return;
- if (r_drawcollisionbrushes.integer < 2)
- R_DrawSurfaces(ent, false);
- if (r_drawcollisionbrushes.integer >= 1 && model->brush.num_brushes)
- {
- int i;
- msurface_t *surface;
- q3mbrush_t *brush;
- R_Mesh_Matrix(&ent->matrix);
- GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
- GL_DepthMask(false);
- GL_DepthTest(true);
- qglPolygonOffset(r_drawcollisionbrushes_polygonfactor.value, r_drawcollisionbrushes_polygonoffset.value);
- for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
- if (brush->colbrushf && brush->colbrushf->numtriangles)
- R_DrawCollisionBrush(brush->colbrushf);
- for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
- if (surface->num_collisiontriangles)
- R_DrawCollisionSurface(ent, surface);
- qglPolygonOffset(0, 0);
- }
+ R_DrawSurfaces(ent, false);
}
typedef struct r_q1bsp_getlightinfo_s
int outnumleafs;
int *outsurfacelist;
unsigned char *outsurfacepvs;
+ unsigned char *tempsurfacepvs;
int outnumsurfaces;
vec3_t outmins;
vec3_t outmaxs;
vec3_t lightmins;
vec3_t lightmaxs;
const unsigned char *pvs;
+ qboolean svbsp_active;
+ qboolean svbsp_insertoccluder;
}
r_q1bsp_getlightinfo_t;
sides = BoxOnPlaneSide(info->lightmins, info->lightmaxs, plane);
if (sides == 3)
{
- R_Q1BSP_RecursiveGetLightInfo(info, node->children[0]);
- node = node->children[1];
+ // recurse front side first because the svbsp building prefers it
+ if (PlaneDist(info->relativelightorigin, plane) > 0)
+ {
+ R_Q1BSP_RecursiveGetLightInfo(info, node->children[0]);
+ node = node->children[1];
+ }
+ else
+ {
+ R_Q1BSP_RecursiveGetLightInfo(info, node->children[1]);
+ node = node->children[0];
+ }
}
+ else if (sides == 0)
+ return; // ERROR: NAN bounding box!
else
node = node->children[sides - 1];
}
leaf = (mleaf_t *)node;
- if (info->pvs == NULL || CHECKPVSBIT(info->pvs, leaf->clusterindex))
+ if (info->svbsp_active)
+ {
+ int i;
+ mportal_t *portal;
+ double points[128][3];
+ for (portal = leaf->portals;portal;portal = portal->next)
+ {
+ for (i = 0;i < portal->numpoints;i++)
+ VectorCopy(portal->points[i].position, points[i]);
+ if (SVBSP_AddPolygon(&r_svbsp, portal->numpoints, points[0], false, NULL, NULL, 0) & 2)
+ break;
+ }
+ if (portal == NULL)
+ return; // no portals of this leaf visible
+ }
+ else
+ {
+ if (r_shadow_frontsidecasting.integer && info->pvs != NULL && !CHECKPVSBIT(info->pvs, leaf->clusterindex))
+ return;
+ }
+ // inserting occluders does not alter the leaf info
+ if (!info->svbsp_insertoccluder)
{
info->outmins[0] = min(info->outmins[0], leaf->mins[0]);
info->outmins[1] = min(info->outmins[1], leaf->mins[1]);
info->outleaflist[info->outnumleafs++] = leafindex;
}
}
- if (info->outsurfacepvs)
+ }
+ if (info->outsurfacepvs)
+ {
+ int leafsurfaceindex;
+ int surfaceindex;
+ int triangleindex, t;
+ msurface_t *surface;
+ const int *e;
+ const vec_t *v[3];
+ double v2[3][3];
+ for (leafsurfaceindex = 0;leafsurfaceindex < leaf->numleafsurfaces;leafsurfaceindex++)
{
- int leafsurfaceindex;
- for (leafsurfaceindex = 0;leafsurfaceindex < leaf->numleafsurfaces;leafsurfaceindex++)
+ surfaceindex = leaf->firstleafsurface[leafsurfaceindex];
+ if (!CHECKPVSBIT(info->outsurfacepvs, surfaceindex))
{
- int surfaceindex = leaf->firstleafsurface[leafsurfaceindex];
- if (!CHECKPVSBIT(info->outsurfacepvs, surfaceindex))
+ surface = info->model->data_surfaces + surfaceindex;
+ if (BoxesOverlap(info->lightmins, info->lightmaxs, surface->mins, surface->maxs)
+ && (!info->svbsp_insertoccluder || !(surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOSHADOW)))
{
- msurface_t *surface = info->model->data_surfaces + surfaceindex;
- if (BoxesOverlap(info->lightmins, info->lightmaxs, surface->mins, surface->maxs))
+ for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = info->model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->num_triangles;triangleindex++, t++, e += 3)
{
- int triangleindex, t;
- const int *e;
- const vec_t *v[3];
- for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = info->model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->num_triangles;triangleindex++, t++, e += 3)
+ v[0] = info->model->brush.shadowmesh->vertex3f + e[0] * 3;
+ v[1] = info->model->brush.shadowmesh->vertex3f + e[1] * 3;
+ v[2] = info->model->brush.shadowmesh->vertex3f + e[2] * 3;
+ if ((!r_shadow_frontsidecasting.integer || PointInfrontOfTriangle(info->relativelightorigin, v[0], v[1], v[2]))
+ && info->lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
+ && info->lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
+ && info->lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
+ && info->lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
+ && info->lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
+ && info->lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
{
- v[0] = info->model->brush.shadowmesh->vertex3f + e[0] * 3;
- v[1] = info->model->brush.shadowmesh->vertex3f + e[1] * 3;
- v[2] = info->model->brush.shadowmesh->vertex3f + e[2] * 3;
- if (PointInfrontOfTriangle(info->relativelightorigin, v[0], v[1], v[2]) && info->lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && info->lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && info->lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && info->lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && info->lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && info->lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
+ if (info->svbsp_active)
{
- SETPVSBIT(info->outsurfacepvs, surfaceindex);
- info->outsurfacelist[info->outnumsurfaces++] = surfaceindex;
- break;
+ VectorCopy(v[0], v2[0]);
+ VectorCopy(v[1], v2[1]);
+ VectorCopy(v[2], v2[2]);
+ if (!(SVBSP_AddPolygon(&r_svbsp, 3, v2[0], info->svbsp_insertoccluder, NULL, NULL, 0) & 2))
+ continue;
}
+ SETPVSBIT(info->outsurfacepvs, surfaceindex);
+ info->outsurfacelist[info->outnumsurfaces++] = surfaceindex;
+ if (info->svbsp_insertoccluder)
+ continue;
+ else
+ break;
}
}
}
}
}
+void R_Q1BSP_CallRecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, qboolean use_svbsp)
+{
+ if (use_svbsp)
+ {
+ double origin[3];
+ VectorCopy(info->relativelightorigin, origin);
+ if (!r_svbsp.nodes)
+ {
+ r_svbsp.maxnodes = max(r_svbsp.maxnodes, 1<<18);
+ r_svbsp.nodes = Mem_Alloc(r_main_mempool, r_svbsp.maxnodes * sizeof(svbsp_node_t));
+ }
+ info->svbsp_active = true;
+ info->svbsp_insertoccluder = true;
+ for (;;)
+ {
+ SVBSP_Init(&r_svbsp, origin, r_svbsp.maxnodes, r_svbsp.nodes);
+ R_Q1BSP_RecursiveGetLightInfo(info, info->model->brush.data_nodes);
+ // if that failed, retry with more nodes
+ if (r_svbsp.ranoutofnodes)
+ {
+ // an upper limit is imposed
+ if (r_svbsp.maxnodes >= 2<<22)
+ break;
+ Mem_Free(r_svbsp.nodes);
+ r_svbsp.maxnodes *= 2;
+ r_svbsp.nodes = Mem_Alloc(tempmempool, r_svbsp.maxnodes * sizeof(svbsp_node_t));
+ }
+ else
+ break;
+ }
+ // now clear the surfacepvs array because we need to redo it
+ memset(info->outsurfacepvs, 0, (info->model->nummodelsurfaces + 7) >> 3);
+ info->outnumsurfaces = 0;
+ }
+ else
+ info->svbsp_active = false;
+
+ // we HAVE to mark the leaf the light is in as lit, because portals are
+ // irrelevant to a leaf that the light source is inside of
+ // (and they are all facing away, too)
+ {
+ mnode_t *node = info->model->brush.data_nodes;
+ mleaf_t *leaf;
+ while (node->plane)
+ node = node->children[(node->plane->type < 3 ? info->relativelightorigin[node->plane->type] : DotProduct(info->relativelightorigin,node->plane->normal)) < node->plane->dist];
+ leaf = (mleaf_t *)node;
+ info->outmins[0] = min(info->outmins[0], leaf->mins[0]);
+ info->outmins[1] = min(info->outmins[1], leaf->mins[1]);
+ info->outmins[2] = min(info->outmins[2], leaf->mins[2]);
+ info->outmaxs[0] = max(info->outmaxs[0], leaf->maxs[0]);
+ info->outmaxs[1] = max(info->outmaxs[1], leaf->maxs[1]);
+ info->outmaxs[2] = max(info->outmaxs[2], leaf->maxs[2]);
+ if (info->outleafpvs)
+ {
+ int leafindex = leaf - info->model->brush.data_leafs;
+ if (!CHECKPVSBIT(info->outleafpvs, leafindex))
+ {
+ SETPVSBIT(info->outleafpvs, leafindex);
+ info->outleaflist[info->outnumleafs++] = leafindex;
+ }
+ }
+ }
+
+ info->svbsp_insertoccluder = false;
+ R_Q1BSP_RecursiveGetLightInfo(info, info->model->brush.data_nodes);
+ if (developer.integer >= 100 && use_svbsp)
+ {
+ Con_Printf("GetLightInfo: svbsp built with %i nodes, polygon stats:\n", r_svbsp.numnodes);
+ Con_Printf("occluders: %i accepted, %i rejected, %i fragments accepted, %i fragments rejected.\n", r_svbsp.stat_occluders_accepted, r_svbsp.stat_occluders_rejected, r_svbsp.stat_occluders_fragments_accepted, r_svbsp.stat_occluders_fragments_rejected);
+ Con_Printf("queries : %i accepted, %i rejected, %i fragments accepted, %i fragments rejected.\n", r_svbsp.stat_queries_accepted, r_svbsp.stat_queries_rejected, r_svbsp.stat_queries_fragments_accepted, r_svbsp.stat_queries_fragments_rejected);
+ }
+}
+
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(info.relativelightorigin, info.outmaxs);
memset(outleafpvs, 0, (info.model->brush.num_leafs + 7) >> 3);
memset(outsurfacepvs, 0, (info.model->nummodelsurfaces + 7) >> 3);
- if (info.model->brush.GetPVS)
+ if (info.model->brush.GetPVS && r_shadow_frontsidecasting.integer)
info.pvs = info.model->brush.GetPVS(info.model, info.relativelightorigin);
else
info.pvs = NULL;
R_UpdateAllTextureInfo(ent);
- if (r_shadow_compilingrtlight)
+
+ if (r_shadow_frontsidecasting.integer && r_shadow_compilingrtlight && r_shadow_realtime_world_compileportalculling.integer)
{
// use portal recursion for exact light volume culling, and exact surface checking
Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, true, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs);
}
- else if (r_shadow_realtime_dlight_portalculling.integer)
+ else if (r_shadow_frontsidecasting.integer && r_shadow_realtime_dlight_portalculling.integer)
{
// use portal recursion for exact light volume culling, but not the expensive exact surface checking
Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, r_shadow_realtime_dlight_portalculling.integer >= 2, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs);
}
else
{
- // use BSP recursion as lights are often small
- R_Q1BSP_RecursiveGetLightInfo(&info, info.model->brush.data_nodes);
+ // recurse the bsp tree, checking leafs and surfaces for visibility
+ // optionally using svbsp for exact culling of compiled lights
+ // (or if the user enables dlight svbsp culling, which is mostly for
+ // debugging not actual use)
+ R_Q1BSP_CallRecursiveGetLightInfo(&info, r_shadow_compilingrtlight ? r_shadow_realtime_world_compilesvbsp.integer : r_shadow_realtime_dlight_svbspculling.integer);
}
// limit combined leaf box to light boundaries
*outnumsurfacespointer = info.outnumsurfaces;
}
-void R_Q1BSP_CompileShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist)
+void R_Q1BSP_CompileShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, 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);
+ float projectdistance = relativelightdirection ? lightradius : lightradius + model->radius*2 + r_shadow_projectdistance.value;
+ r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_main_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))
+ if (surface->texture->currentframe->basematerialflags & MATERIALFLAG_NOSHADOW)
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_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, 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);
+ R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist);
+ r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, false, false);
}
-extern float *rsurface_vertex3f;
-extern float *rsurface_svector3f;
-extern float *rsurface_tvector3f;
-extern float *rsurface_normal3f;
-extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg);
-
-void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs)
+void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int modelnumsurfaces, const int *modelsurfacelist, const vec3_t lightmins, const vec3_t lightmaxs)
{
model_t *model = ent->model;
msurface_t *surface;
- int surfacelistindex;
- float projectdistance = lightradius + model->radius*2 + r_shadow_projectdistance.value;
- vec3_t modelorg;
- texture_t *texture;
+ int modelsurfacelistindex;
+ float projectdistance = relativelightdirection ? lightradius : lightradius + model->radius*2 + r_shadow_projectdistance.value;
// check the box in modelspace, it was already checked in worldspace
- if (!BoxesOverlap(ent->model->normalmins, ent->model->normalmaxs, lightmins, lightmaxs))
- return;
- if (r_drawcollisionbrushes.integer >= 2)
+ if (!BoxesOverlap(model->normalmins, model->normalmaxs, lightmins, lightmaxs))
return;
R_UpdateAllTextureInfo(ent);
if (model->brush.shadowmesh)
{
R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles);
- for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+ for (modelsurfacelistindex = 0;modelsurfacelistindex < modelnumsurfaces;modelsurfacelistindex++)
{
- 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))
+ surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex];
+ if (surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOSHADOW)
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_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, 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);
+ R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist);
}
else
{
- projectdistance = lightradius + ent->model->radius*2;
- Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
- for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+ projectdistance = lightradius + model->radius*2;
+ 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++)
{
- surface = model->data_surfaces + surfacelist[surfacelistindex];
- // FIXME: get current skin
- texture = surface->texture;//R_FetchAliasSkin(ent, surface->groupmesh);
- if (texture->currentmaterialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT) || !surface->num_triangles)
+ surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex];
+ rsurface_texture = surface->texture->currentframe;
+ if (rsurface_texture->currentmaterialflags & MATERIALFLAG_NOSHADOW)
continue;
- RSurf_SetVertexPointer(ent, texture, surface, modelorg);
- // identify lit faces within the bounding box
- R_Shadow_PrepareShadowMark(surface->groupmesh->num_triangles);
- R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs);
- R_Shadow_VolumeFromList(surface->groupmesh->num_vertices, surface->groupmesh->num_triangles, rsurface_vertex3f, surface->groupmesh->data_element3i, surface->groupmesh->data_neighbor3i, relativelightorigin, projectdistance, numshadowmark, shadowmarklist);
+ RSurf_PrepareVerticesForBatch(false, false, 1, &surface);
+ R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface_vertex3f, rsurface_model->surfmesh.data_element3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs);
}
+ R_Shadow_VolumeFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface_vertex3f, model->surfmesh.data_element3i, model->surfmesh.data_neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist);
}
}
-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;
- texture_t *texture = surface->texture;
- R_UpdateTextureInfo(ent, texture);
- texture = texture->currentframe;
+ int i, j, batchnumsurfaces, endsurface;
+ texture_t *t;
+ msurface_t *surface;
+ msurface_t *batchsurfaces[BATCHSIZE];
+ // note: in practice this never actually batches, oh well
R_Shadow_RenderMode_Begin();
R_Shadow_RenderMode_ActiveLight((rtlight_t *)rtlight);
R_Shadow_RenderMode_Lighting(false, true);
R_Shadow_SetupEntityLight(ent);
- R_Shadow_RenderSurfacesLighting(ent, texture, 1, &surface);
+ for (i = 0;i < numsurfaces;i = j)
+ {
+ j = i + 1;
+ surface = rsurface_model->data_surfaces + surfacelist[i];
+ t = surface->texture;
+ R_UpdateTextureInfo(ent, t);
+ rsurface_texture = t->currentframe;
+ endsurface = min(j + BATCHSIZE, numsurfaces);
+ batchnumsurfaces = 0;
+ batchsurfaces[batchnumsurfaces++] = surface;
+ for (;j < endsurface;j++)
+ {
+ surface = rsurface_model->data_surfaces + surfacelist[j];
+ if (t != surface->texture)
+ continue;
+ batchsurfaces[batchnumsurfaces++] = surface;
+ }
+ R_Shadow_RenderSurfacesLighting(batchnumsurfaces, batchsurfaces);
+ }
R_Shadow_RenderMode_End();
}
+static void R_Q1BSP_DrawLight_TransparentBatch(int batchnumsurfaces, msurface_t **batchsurfacelist)
+{
+ int batchsurfaceindex;
+ msurface_t *batchsurface;
+ vec3_t tempcenter, center;
+ for (batchsurfaceindex = 0;batchsurfaceindex < batchnumsurfaces;batchsurfaceindex++)
+ {
+ batchsurface = batchsurfacelist[batchsurfaceindex];
+ tempcenter[0] = (batchsurface->mins[0] + batchsurface->maxs[0]) * 0.5f;
+ 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_view.origin : center, R_Q1BSP_DrawLight_TransparentCallback, rsurface_entity, batchsurface - rsurface_model->data_surfaces, r_shadow_rtlight);
+ }
+}
+
#define RSURF_MAX_BATCHSURFACES 1024
void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surfacelist)
{
model_t *model = ent->model;
msurface_t *surface;
- texture_t *texture;
- int surfacelistindex, batchnumsurfaces;
+ int i, j, k, l, endsurface, batchnumsurfaces;
msurface_t *batchsurfacelist[RSURF_MAX_BATCHSURFACES];
- vec3_t modelorg;
texture_t *tex;
- qboolean skip;
- if (r_drawcollisionbrushes.integer >= 2)
- return;
+ CHECKGLERROR
+ RSurf_ActiveEntity(ent, true, true);
R_UpdateAllTextureInfo(ent);
- Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
- tex = NULL;
- texture = NULL;
- skip = false;
- batchnumsurfaces = 0;
- for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+ CHECKGLERROR
+ // this is a double loop because non-visible surface skipping has to be
+ // fast, and even if this is not the world model (and hence no visibility
+ // checking) the input surface list and batch buffer are different formats
+ // so some processing is necessary. (luckily models have few surfaces)
+ for (i = 0;i < numsurfaces;i = j)
{
- if ((ent == r_refdef.worldentity && !r_worldsurfacevisible[surfacelist[surfacelistindex]]))
+ batchnumsurfaces = 0;
+ endsurface = min(i + RSURF_MAX_BATCHSURFACES, numsurfaces);
+ if (ent == r_refdef.worldentity)
+ {
+ for (j = i;j < endsurface;j++)
+ if (r_viewcache.world_surfacevisible[surfacelist[j]])
+ batchsurfacelist[batchnumsurfaces++] = model->data_surfaces + surfacelist[j];
+ }
+ else
+ {
+ for (j = i;j < endsurface;j++)
+ batchsurfacelist[batchnumsurfaces++] = model->data_surfaces + surfacelist[j];
+ }
+ if (!batchnumsurfaces)
continue;
- surface = model->data_surfaces + surfacelist[surfacelistindex];
- renderstats.lights_lighttriangles += surface->num_triangles;
- if (tex != surface->texture)
+ for (k = 0;k < batchnumsurfaces;k = l)
{
- if (batchnumsurfaces > 0)
+ l = k + 1;
+ surface = batchsurfacelist[k];
+ tex = surface->texture;
+ rsurface_texture = tex->currentframe;
+ for (;l < batchnumsurfaces && tex == batchsurfacelist[k]->texture;l++);
+ if (rsurface_texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_WATER))
{
- if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
- {
- int batchsurfaceindex;
- for (batchsurfaceindex = 0;batchsurfaceindex < batchnumsurfaces;batchsurfaceindex++)
- {
- msurface_t *batchsurface = batchsurfacelist[batchsurfaceindex];
- vec3_t tempcenter, center;
- tempcenter[0] = (batchsurface->mins[0] + batchsurface->maxs[0]) * 0.5f;
- tempcenter[1] = (batchsurface->mins[1] + batchsurface->maxs[1]) * 0.5f;
- tempcenter[2] = (batchsurface->mins[2] + batchsurface->maxs[2]) * 0.5f;
- Matrix4x4_Transform(&ent->matrix, tempcenter, center);
- R_MeshQueue_AddTransparent(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_vieworigin : center, R_Q1BSP_DrawLight_TransparentCallback, ent, batchsurface - ent->model->data_surfaces, r_shadow_rtlight);
- }
- }
+ if (rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED)
+ R_Q1BSP_DrawLight_TransparentBatch(l - k, batchsurfacelist + k);
else
- R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist);
- batchnumsurfaces = 0;
+ R_Shadow_RenderSurfacesLighting(l - k, batchsurfacelist + k);
}
- tex = surface->texture;
- texture = surface->texture->currentframe;
- skip = (texture->currentmaterialflags & MATERIALFLAG_SKY) != 0;
- if (skip)
- continue;
}
- if (!skip && surface->num_triangles)
+ }
+}
+
+//Made by [515]
+void R_ReplaceWorldTexture (void)
+{
+ model_t *m;
+ texture_t *t;
+ int i;
+ const char *r, *newt;
+ m = r_refdef.worldmodel;
+
+ if(Cmd_Argc() < 2)
+ {
+ Con_Print("r_replacemaptexture <texname> <newtexname> - replaces texture\n");
+ Con_Print("r_replacemaptexture <texname> - switch back to default texture\n");
+ return;
+ }
+ if(!cl.islocalgame || !cl.worldmodel)
+ {
+ Con_Print("This command works only in singleplayer\n");
+ return;
+ }
+ r = Cmd_Argv(1);
+ newt = Cmd_Argv(2);
+ if(!newt[0])
+ newt = r;
+ for(i=0,t=m->data_textures;i<m->num_textures;i++,t++)
+ {
+ if(t->width && !strcasecmp(t->name, r))
{
- if (batchnumsurfaces == RSURF_MAX_BATCHSURFACES)
+ if(Mod_LoadSkinFrame(&t->skinframes[0], (char*)newt, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, r_fullbrights.integer))
{
- if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
- {
- int batchsurfaceindex;
- for (batchsurfaceindex = 0;batchsurfaceindex < batchnumsurfaces;batchsurfaceindex++)
- {
- msurface_t *batchsurface = batchsurfacelist[batchsurfaceindex];
- vec3_t tempcenter, center;
- tempcenter[0] = (batchsurface->mins[0] + batchsurface->maxs[0]) * 0.5f;
- tempcenter[1] = (batchsurface->mins[1] + batchsurface->maxs[1]) * 0.5f;
- tempcenter[2] = (batchsurface->mins[2] + batchsurface->maxs[2]) * 0.5f;
- Matrix4x4_Transform(&ent->matrix, tempcenter, center);
- R_MeshQueue_AddTransparent(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_vieworigin : center, R_Q1BSP_DrawLight_TransparentCallback, ent, batchsurface - ent->model->data_surfaces, r_shadow_rtlight);
- }
- }
- else
- R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist);
- batchnumsurfaces = 0;
+ Con_Printf("%s replaced with %s\n", r, newt);
+ return;
+ }
+ else
+ {
+ Con_Printf("%s was not found\n", newt);
+ Mod_LoadSkinFrame(&t->skinframes[0], (char*)r, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, r_fullbrights.integer);//back to default
+ return;
}
- batchsurfacelist[batchnumsurfaces++] = surface;
}
}
- if (batchnumsurfaces > 0)
- {
- R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist);
- batchnumsurfaces = 0;
- }
- qglEnable(GL_CULL_FACE);
+}
+
+//Made by [515]
+void R_ListWorldTextures (void)
+{
+ model_t *m;
+ texture_t *t;
+ int i;
+ m = r_refdef.worldmodel;
+
+ Con_Print("Worldmodel textures :\n");
+ for(i=0,t=m->data_textures;i<m->num_textures;i++,t++)
+ if (t->numskinframes)
+ Con_Printf("%s\n", t->name);
}
#if 0
{
Cvar_RegisterVariable(&r_ambient);
- Cvar_RegisterVariable(&r_drawportals);
Cvar_RegisterVariable(&r_lockpvs);
Cvar_RegisterVariable(&r_lockvisibility);
Cvar_RegisterVariable(&r_useportalculling);
- Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonfactor);
- Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonoffset);
Cvar_RegisterVariable(&r_q3bsp_renderskydepth);
+ Cmd_AddCommand ("r_replacemaptexture", R_ReplaceWorldTexture, "override a map texture for testing purposes"); // By [515]
+ Cmd_AddCommand ("r_listmaptextures", R_ListWorldTextures, "list all textures used by the current map"); // By [515]
+
//R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
}