Add MOD_HullContents().

If trace is null or point type, or the hull doesn't have portals, or the
first node is a leaf, MOD_HullContents operates in point mode (exactly the
same way as SV_HullPointContents()). However, in box mode, all leafs
touched by the trace are checked for their contents. The contents field of
trace (a bit field) will indicate the contents type of all touched leafs.
The returned contents value indicates the most important contents:

    solid > lava > slime > water > empty

The one's complement value of the contents type is the bit number of the
contents bit field. I'm not sure how useful this will be as getting the
amount of overlap is currently not supported.
This commit is contained in:
Bill Currie 2011-12-01 12:26:33 +09:00
parent 7ee31dd475
commit f9d56f2941
2 changed files with 73 additions and 0 deletions

View file

@ -49,6 +49,7 @@ typedef struct trace_s {
vec3_t endpos; // final position
plane_t plane; // surface normal at impact
struct edict_s *ent; // entity the surface is on
unsigned contents; // contents of leafs touched by trace
} trace_t;
@ -117,6 +118,8 @@ hull_t *SV_HullForEntity (struct edict_s *ent, const vec3_t mins,
const vec3_t maxs, vec3_t extents, vec3_t offset);
void MOD_TraceLine (hull_t *hull, int num,
const vec3_t start, const vec3_t end, trace_t *trace);
int MOD_HullContents (hull_t *hull, int num, const vec3_t origin,
trace_t *trace);
typedef struct clipport_s {
int planenum;

View file

@ -455,6 +455,47 @@ finish_impact:
}
}
static int
trace_contents (hull_t *hull, trace_t *trace, clipleaf_t *leaf,
const vec3_t origin)
{
clipport_t *portal;
int side;
int contents = leaf->contents;
// set the auxiliary contents data. this is a bit field of all contents
// types contained within the trace.
// contents start at -1 (empty). bit 0 represents CONTENTS_EMPTY
trace->contents |= 1 << (~contents);
// check all adjoining leafs that contain part of the trace
for (portal = leaf->portals; portal; portal = portal->next[side]) {
vec_t offset;
vec_t dist;
plane_t *plane;
int res;
side = portal->leafs[1] == leaf;
plane = hull->planes + portal->planenum;
dist = PlaneDiff (origin, plane);
offset = calc_offset (trace, plane);
// the side of the plane on which we are does not matter, only
// whether we're crossing the plane. merely touching the plane does
// not cause us to cross it
if (fabs (dist) >= offset)
continue;
//FIXME test portal!
res = trace_contents (hull, trace, portal->leafs[side ^ 1], origin);
//FIXME better test?
// solid > lava > slime > water > empty (desired)
// solid > current (good)
// problem is, current > sky > lava (what is best?)
if (res == CONTENTS_SOLID
|| (contents != CONTENTS_SOLID && res < contents))
contents = res;
}
return contents;
}
VISIBLE void
MOD_TraceLine (hull_t *hull, int num,
const vec3_t start_point, const vec3_t end_point,
@ -612,3 +653,32 @@ MOD_TraceLine (hull_t *hull, int num,
num = node->children[side];
}
}
VISIBLE int
MOD_HullContents (hull_t *hull, int num, const vec3_t origin, trace_t *trace)
{
int prevnode = -1;
int side = 0;
clipleaf_t *leaf;
// follow origin down the bsp tree to find the "central" leaf
while (num >= 0) {
vec_t d;
mclipnode_t *node;
plane_t *plane;
node = hull->clipnodes + num;
plane = hull->planes + node->planenum;
d = PlaneDiff (origin, plane);
prevnode = num;
side = d < 0;
num = node->children[side];
}
if (!trace || trace->type == tr_point
|| prevnode == -1 || !hull->nodeleafs) {
return num;
}
// check the contents of the "central" and surrounding touched leafs
leaf = hull->nodeleafs[prevnode].leafs[side];
trace->contents = 0;
return trace_contents (hull, trace, leaf, origin);
}