Forum

Extending the number of dynamic lights

Post tutorials on how to do certain tasks within game or engine code here.

Moderator: InsideQC Admins

Extending the number of dynamic lights

Postby mh » Mon Aug 22, 2011 3:38 pm

Stock ID Quake caps the max number of dynamic lights to 32, but let's face it, lots of dynamic lights make the world a much more interesting place. So let's increase it.

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

Now find the dlightbits member of the msurface_t struct; for GLQuake it should be in gl_model.h (this also works with software Quake although some of the names are different, and should be even easily adaptable to Quake II), and change it to:
Code: Select all
int         dlightbits[(MAX_DLIGHTS + 31) >> 5];

I do it this way so that if I ever change the value of MAX_DLIGHTS I don't need to go hunting through multiple locations for anything that depends on it.

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);

This is just a convenience so that we can use the same function for brush models as we use for the world.

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);
   }
}

And the new R_MarkLights (also gl_light.c):
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]);
}

Now, this R_PushDlights function is called from a pretty stupid place - view.c - so let's move it to R_DrawWorld in gl_rsurf.c instead; pop it just before the call to R_RecursiveWorldNode like so:
Code: Select all
R_PushDlights (cl.worldmodel->nodes);

You'll note that this has enabled us to get rid of r_dlightframecount and use r_framecount instead, which is more nice cleaning up.

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);
      }
   }

To this not-so-mess:
Code: Select all
   if (clmodel->firstmodelsurface != 0) R_PushDlights (clmodel->nodes + clmodel->hulls[0].firstclipnode);

More cleaning up here.

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;

To this:
Code: Select all
if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31)))) continue;

And that's it. Have fun.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Postby qbism » Tue Aug 23, 2011 2:25 am

This tute could be subtitled "cleaning up a lot of dlight garbage". R_MarkLights is greatly cleaned up. Silly r_dlightframecount goes away. Thank you!

In SW engine, R_PushDlights call would go in R_RenderView under R_SetupFrame.

BTW, R_PushDlights declaration could go to r_local.h.
User avatar
qbism
 
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am

Re: Extending the number of dynamic lights

Postby leileilol » Tue Aug 23, 2011 1:20 pm

mh wrote: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).


Could've been cutting room floor for bitflags for unreal-esque dynamic light effects such as this:

Image


Hopefully this dlight cleanup code helps my shitty shadow implementation lol
i should not be here
leileilol
 
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Postby qbism » Wed Aug 24, 2011 3:26 am

That shimmer would be cool around water/ lava.

Darklights still bleed through like regular dlights unless expensive vis checks... checks that slow platforms can't cash.
User avatar
qbism
 
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am


Return to Programming Tutorials

Who is online

Users browsing this forum: No registered users and 1 guest