Forum

Replacing Quake2's RecursiveLightPoint with DarkPlaces'

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

Moderator: InsideQC Admins

Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Postby jitspoe » Wed Jun 05, 2013 4:55 am

The DarkPlaces version has some nice features like axis optimization and bilinear filtering. I was mostly able to copy/paste it with minor changes.

So, here we go: Open gl_light.c and replace RecursiveLightPoint() with this:

Code: Select all
// Taken from LordHavoc's DarkPlaces, slightly modified by jitspoe to be compatible with Quake2
static int LightPoint_RecursiveBSPNode (model_t *model, vec3_t ambientcolor, const mnode_t *node, float x, float y, float startz, float endz)
{
   int side;
   float front, back;
   float mid, distz = endz - startz;

loc0:
   //if (!node->plane)
   if (node->contents != -1)
      return false;      // didn't hit anything

   switch (node->plane->type)
   {
   case PLANE_X:
      node = node->children[x < node->plane->dist];
      goto loc0;
   case PLANE_Y:
      node = node->children[y < node->plane->dist];
      goto loc0;
   case PLANE_Z:
      side = startz < node->plane->dist;
      if ((endz < node->plane->dist) == side)
      {
         node = node->children[side];
         goto loc0;
      }
      // found an intersection
      mid = node->plane->dist;
      break;
   default:
      back = front = x * node->plane->normal[0] + y * node->plane->normal[1];
      front += startz * node->plane->normal[2];
      back += endz * node->plane->normal[2];
      side = front < node->plane->dist;
      if ((back < node->plane->dist) == side)
      {
         node = node->children[side];
         goto loc0;
      }
      // found an intersection
      mid = startz + distz * (front - node->plane->dist) / (front - back);
      break;
   }

   // go down front side
   if (node->children[side]->plane && LightPoint_RecursiveBSPNode(model, ambientcolor, node->children[side], x, y, startz, mid))
   {
      return true;   // hit something
   }
   else
   {
      // check for impact on this node
      if (node->numsurfaces)
      {
         unsigned int i;
         int dsi, dti, lmwidth, lmheight;
         float ds, dt;
         msurface_t *surface;
         unsigned char *lightmap;
         int maps, line3, size3;
         float dsfrac;
         float dtfrac;
         float w00, w01, w10, w11;

         surface = model->surfaces + node->firstsurface;

         for (i = 0; i < node->numsurfaces; ++i, ++surface)
         {
            if (surface->flags & (SURF_DRAWTURB|SURF_DRAWSKY))
               continue;   // no lightmaps

            // location we want to sample in the lightmap
            ds = ((x * surface->texinfo->vecs[0][0] + y * surface->texinfo->vecs[0][1] + mid * surface->texinfo->vecs[0][2] + surface->texinfo->vecs[0][3]) - surface->texturemins[0]) * 0.0625f;
            dt = ((x * surface->texinfo->vecs[1][0] + y * surface->texinfo->vecs[1][1] + mid * surface->texinfo->vecs[1][2] + surface->texinfo->vecs[1][3]) - surface->texturemins[1]) * 0.0625f;

            if (ds >= 0.0f && dt >= 0.0f) // jit - fix for negative light values
            {
               int dsi = (int)ds;
               int dti = (int)dt;

               lmwidth = ((surface->extents[0] >> 4) + 1);
               lmheight = ((surface->extents[1] >> 4) + 1);

               // is it in bounds?
               if (dsi < lmwidth && dti < lmheight) // jit - fix for black models right on brush splits.
               {

                  // calculate bilinear interpolation factors
                  // and also multiply by fixedpoint conversion factors
                  dsfrac = ds - dsi;
                  dtfrac = dt - dti;

                  w00 = (1 - dsfrac) * (1 - dtfrac) * (1.0f / 255.0f);
                  w01 = (    dsfrac) * (1 - dtfrac) * (1.0f / 255.0f);
                  w10 = (1 - dsfrac) * (    dtfrac) * (1.0f / 255.0f);
                  w11 = (    dsfrac) * (    dtfrac) * (1.0f / 255.0f);

                  // values for pointer math
                  line3 = lmwidth * 3;
                  size3 = lmwidth * lmheight * 3;

                  // look up the pixel
                  //lightmap = surface->samples + dti * line3 + dsi * 3;
                  lightmap = surface->stain_samples + dti * line3 + dsi * 3; // Note: comment this line out and use the one above if you do not have stainmaps

                  // bilinear filter each lightmap style, and sum them
                  for (maps = 0; maps < MAXLIGHTMAPS && surface->styles[maps] != 255; maps++)
                  {
                     VectorMA(ambientcolor, w00, lightmap            , ambientcolor);
                     VectorMA(ambientcolor, w01, lightmap + 3        , ambientcolor);
                     VectorMA(ambientcolor, w10, lightmap + line3    , ambientcolor);
                     VectorMA(ambientcolor, w11, lightmap + line3 + 3, ambientcolor);

                     lightmap += size3;
                  }

                  return true; // success
               }
            }
         }
      }

      // go down back side
      node = node->children[side ^ 1];
      startz = mid;
      distz = endz - startz;
      goto loc0;
   }
}


Now go to R_LightPoint(), remove "vec3_t end;", and change:

Code: Select all
   end[0] = p[0];
   end[1] = p[1];
   end[2] = p[2] - 2048.0f;
   r = RecursiveLightPoint(r_worldmodel->nodes, p, end);
   
   if (r != -1)


to

Code: Select all
   VectorClear(pointcolor);
   r = LightPoint_RecursiveBSPNode(r_worldmodel, pointcolor, r_worldmodel->nodes, p[0], p[1], p[2], p[2] - 2048.0f);

   if (r <= 0)


Easy peasy!

Not sure if my code is exactly the same as Quake2's there, but it should be close enough. There is one line you will have to change if you're not using stainmaps.vecs
Last edited by jitspoe on Sun Jun 16, 2013 2:28 am, edited 2 times in total.
jitspoe
 
Posts: 217
Joined: Mon Jan 17, 2005 5:27 am

Re: Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Postby leileilol » Fri Jun 07, 2013 10:58 pm

It can also be applied to the software renderer as well.
i should not be here
leileilol
 
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Re: Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Postby jitspoe » Mon Jun 10, 2013 6:21 am

I have seen a strange issue with flag models in some maps in Paintball2 after using this. They will be dark at spawn, but if I pick up the flag and drop it, it's fine. I tried moving the starting point for the light trace up a little, as I thought the flag may be spawning slightly in the ground, but that didn't appear to fix it. I'll have to investigate further. I'm wondering if the flag spawn is exactly on a brush split or something causing this oddity.
jitspoe
 
Posts: 217
Joined: Mon Jan 17, 2005 5:27 am

Re: Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Postby leileilol » Mon Jun 10, 2013 7:26 am

i should not be here
leileilol
 
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Re: Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Postby jitspoe » Tue Jun 11, 2013 2:41 pm

I've tracked down the issue and posted a reply in the thread you linked. In short, it's because the entities are exactly on the edge of the lightmap. I've modified the code with a simple tweak that fixes that particular issue, but it may result in others (haven't seen any yet).
jitspoe
 
Posts: 217
Joined: Mon Jan 17, 2005 5:27 am

Re: Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Postby jitspoe » Sun Jun 16, 2013 2:28 am

Updated with another fix for negative values being returned.
jitspoe
 
Posts: 217
Joined: Mon Jan 17, 2005 5:27 am


Return to Programming Tutorials

Who is online

Users browsing this forum: No registered users and 1 guest