diff --git a/include/world.h b/include/world.h index 81d053833..404a0e02b 100644 --- a/include/world.h +++ b/include/world.h @@ -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; diff --git a/libs/models/trace.c b/libs/models/trace.c index 2bcb38b2f..8bef5695a 100644 --- a/libs/models/trace.c +++ b/libs/models/trace.c @@ -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); +}