Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Post tutorials on how to do certain tasks within game or engine code here.
Post Reply
jitspoe
Posts: 217
Joined: Mon Jan 17, 2005 5:27 am

Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Post by jitspoe »

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.
leileilol
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Re: Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Post by leileilol »

It can also be applied to the software renderer as well.
i should not be here
jitspoe
Posts: 217
Joined: Mon Jan 17, 2005 5:27 am

Re: Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Post by jitspoe »

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.
leileilol
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Re: Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Post by leileilol »

i should not be here
jitspoe
Posts: 217
Joined: Mon Jan 17, 2005 5:27 am

Re: Replacing Quake2's RecursiveLightPoint with DarkPlaces'

Post by jitspoe »

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'

Post by jitspoe »

Updated with another fix for negative values being returned.
Post Reply