From f9d56f2941582630cfe6a9164b01219dfa2f4ca7 Mon Sep 17 00:00:00 2001
From: Bill Currie <bill@taniwha.org>
Date: Thu, 1 Dec 2011 12:26:33 +0900
Subject: [PATCH] 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.
---
 include/world.h     |  3 ++
 libs/models/trace.c | 70 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+)

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);
+}