Page 1 of 1

Getting Surface Flags in qrad3?

Posted: Tue Mar 03, 2015 3:33 am
by jitspoe
So I'm basically rewriting the sun light feature in qrad3, and I need to do a trace that will return true if it hits sky. I'm running into a bit of an issue, though. For some reason, I can't seem to get to the brushes with the trace.

Original trace:

Code: Select all

int TestLine_r (int node, vec3_t set_start, vec3_t stop)
{
	tnode_t	*tnode;
	float	front, back;
	vec3_t	mid, start;
	float	frac;
	int		side;
	int		r;

	start[0] = set_start[0];
	start[1] = set_start[1];
	start[2] = set_start[2];

re_test:

	if (node & (1<<31))
	{
		return node & ~(1<<31);	// leaf node
	}

	tnode = &tnodes[node];
	switch (tnode->type)
	{
	case PLANE_X:
		front = start[0] - tnode->dist;
		back = stop[0] - tnode->dist;
		break;
	case PLANE_Y:
		front = start[1] - tnode->dist;
		back = stop[1] - tnode->dist;
		break;
	case PLANE_Z:
		front = start[2] - tnode->dist;
		back = stop[2] - tnode->dist;
		break;
	default:
		front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
		back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist;
		break;
	}

	if (front >= -ON_EPSILON && back >= -ON_EPSILON)
	{
		node = tnode->children[0];

		goto re_test;

		//		return TestLine_r (tnode->children[0], start, stop);
	}

	if (front < ON_EPSILON && back < ON_EPSILON)
	{
		node = tnode->children[1];

		goto re_test;

		//		return TestLine_r (tnode->children[1], start, stop);
	}

	side = front < 0;

	frac = front / (front-back);

	mid[0] = start[0] + (stop[0] - start[0])*frac;
	mid[1] = start[1] + (stop[1] - start[1])*frac;
	mid[2] = start[2] + (stop[2] - start[2])*frac;

	r = TestLine_r (tnode->children[side], start, mid);

	if (r)
		return r;

	node = tnode->children[!side];

	start[0] = mid[0];
	start[1] = mid[1];
	start[2] = mid[2];

	goto re_test;

	//    return TestLine_r (tnode->children[!side], mid, stop);
}
My modified version, which tries to collide against the actual brushes (Using CM_TraceToLeaf/CM_ClipBoxToBrush from the engine code as reference):

Code: Select all

// jit - mostly copied from TestLine_r.
static int TraceToSky_r (vec3_t scale, int node, const vec3_t start_in, const vec3_t stop)
{
	tnode_t	*tnode;
	float	front, back;
	vec3_t	mid, start;
	float	frac;
	int		side;
	int		r;

	start[0] = start_in[0];
	start[1] = start_in[1];
	start[2] = start_in[2];

re_test:

	// Nodes < 0 (highest bit set) are leaf nodes.
	if (node & (1<<31))
	{
		int leafnum = node & ~(1<<31);	// leaf node

		if (leafnum)
		{
			int			k;
			int			brushnum;
			dleaf_t		*leaf;
			dbrush_t	*b;
			int			brushtestret;

			//leaf = &map_leafs[leafnum];
			leaf = dleafs + leafnum;

			// trace line against all brushes in the leaf
			for (k = 0; k < leaf->numleafbrushes; ++k)
			{
				//brushnum = map_leafbrushes[leaf->firstleafbrush + k];
				brushnum = dleafbrushes[leaf->firstleafbrush + k];
				//b = &map_brushes[brushnum];
				b = dbrushes + brushnum;

				//if (b->checkcount == checkcount)
				//	continue;	// already checked this brush in another leaf

				//b->checkcount = checkcount;

				//if (!(b->contents & trace_contents))
				//	continue;

				brushtestret = TraceToSkyBrushTest(scale, start, stop, b);

				if (brushtestret != 0)
					return brushtestret;
			}
		}

		return 0;
	}

	// todo: seems the conditional checks here would probably be slower than just doing the math -- test that theory.
	tnode = &tnodes[node];
	switch (tnode->type)
	{
	case PLANE_X:
		front = start[0] - tnode->dist;
		back = stop[0] - tnode->dist;
		break;
	case PLANE_Y:
		front = start[1] - tnode->dist;
		back = stop[1] - tnode->dist;
		break;
	case PLANE_Z:
		front = start[2] - tnode->dist;
		back = stop[2] - tnode->dist;
		break;
	default:
		front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
		back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist;
		break;
	}

	if (front >= -ON_EPSILON && back >= -ON_EPSILON)
	{
		node = tnode->children[0];

		goto re_test;

		//		return TestLine_r (tnode->children[0], start, stop);
	}

	if (front < ON_EPSILON && back < ON_EPSILON)
	{
		node = tnode->children[1];

		goto re_test;

		//		return TestLine_r (tnode->children[1], start, stop);
	}

	side = front < 0;

	frac = front / (front-back);

	mid[0] = start[0] + (stop[0] - start[0])*frac;
	mid[1] = start[1] + (stop[1] - start[1])*frac;
	mid[2] = start[2] + (stop[2] - start[2])*frac;

	r = TraceToSky_r(scale, tnode->children[side], start, mid);

	if (r)
		return r;

	node = tnode->children[!side];

	start[0] = mid[0];
	start[1] = mid[1];
	start[2] = mid[2];

	goto re_test;
}
(Pardon the sloppy WIP code).

Problem I'm running into is that leaf->numleafbrushes is always 0. I never actually get into that loop where it checks against all the brushes.

Most leaf nodes are either 0x80000000 or 0x80000001.

There ARE leaves that have brushes, but I never seem to be hitting them. I'm not sure what I'm doing wrong. Probably something stupid. Any ideas?

Re: Getting Surface Flags in qrad3?

Posted: Tue Mar 03, 2015 4:16 am
by Spike
TestLine returns contents values, not leaf numbers.
MakeTnode stores the leaf's contents into the tnode's parent, so you'll need to either modify the tnodes or just directly use the dnodes+dplanes
that's why your code deals with bits instead of using the if(node<0)leafnum=(-1-node); conversion that is native to the bsp format.

Re: Getting Surface Flags in qrad3?

Posted: Tue Mar 03, 2015 4:44 am
by jitspoe
Ah-HAH! I see it.

Code: Select all

		if (node->children[i] < 0)
		{
			t->children[i] = (dleafs[-node->children[i] - 1].contents & CONTENTS_SOLID) | (1<<31);
		}
		else
		{
			t->children[i] = tnode_p - tnodes;
			MakeTnode (node->children[i]);
		}
Thanks a bunch!