Unfortunately we can't just bump the value of MAX_DLIGHTS because which dynamic lights hit a surface is stored in a 32-bit integer, so we need something more.
First thing, let's find the #define of MAX_DLIGHTS and move it to the top of quakedef.h - we do this because we're going to be referencing it in a number of header files so it's handier to have it here. While we're at it, let's also increase the number; I picked 128 for this example but you can pick something else if you want (I recommend a multiple of 32).
Code: Select all
#define MAX_DLIGHTS 128
Code: Select all
int dlightbits[(MAX_DLIGHTS + 31) >> 5];
There's also a dlightbits member of entity_t (in render.h), but that's not used in either GLQuake or software Quake. Delete it if you want, it might save you some confusion later on (and save you 4 bytes of memory per entity if you're into that kind of thing).
OK, so we've changed how we store dynamic lights, now we need to change how we mark them. Find the definition of R_PushDlights in render.h and change it to:
Code: Select all
void R_PushDlights (struct mnode_s *headnode);
Next, here's the new R_PushDlights (gl_light.c):
Code: Select all
void R_PushDlights (mnode_t *headnode)
{
int i;
dlight_t *l = cl_dlights;
for (i = 0; i < MAX_DLIGHTS; i++, l++)
{
if (l->die < cl.time || (l->radius <= 0))
continue;
R_MarkLights (l, i, headnode);
}
}
Code: Select all
void R_MarkLights (dlight_t *light, int num, mnode_t *node)
{
mplane_t *splitplane;
float dist;
msurface_t *surf;
int i;
if (node->contents < 0)
return;
splitplane = node->plane;
dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
if (dist > light->radius)
{
R_MarkLights (light, num, node->children[0]);
return;
}
if (dist < -light->radius)
{
R_MarkLights (light, num, node->children[1]);
return;
}
// mark the polygons
surf = cl.worldmodel->surfaces + node->firstsurface;
for (i = 0; i < node->numsurfaces; i++, surf++)
{
if (surf->dlightframe != r_framecount)
{
memset (surf->dlightbits, 0, sizeof (surf->dlightbits));
surf->dlightframe = r_framecount;
}
surf->dlightbits[num >> 5] |= 1 << (num & 31);
}
R_MarkLights (light, num, node->children[0]);
R_MarkLights (light, num, node->children[1]);
}
Code: Select all
R_PushDlights (cl.worldmodel->nodes);
Moving on to brush models, look for R_DrawBrushModel (also in gl_rsurf.c) and change this mess:
Code: Select all
if (clmodel->firstmodelsurface != 0)
{
for (k = 0; k < MAX_DLIGHTS; k++)
{
if ((cl_dlights[k].die < cl.time) || (!cl_dlights[k].radius))
continue;
R_MarkLights (&cl_dlights[k], 1 << k, clmodel->nodes + clmodel->hulls[0].firstclipnode);
}
}
Code: Select all
if (clmodel->firstmodelsurface != 0) R_PushDlights (clmodel->nodes + clmodel->hulls[0].firstclipnode);
So, all that's left is to change how we actually update the lightmaps for each surface, so still in gl_rsurf.c look for R_AddDynamicLights and change this:
Code: Select all
if (!(surf->dlightbits & (1 << lnum))) continue;
Code: Select all
if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31)))) continue;