Break out the leaf visit code into its own funciton.

This commit is contained in:
Bill Currie 2011-12-04 18:52:17 +09:00
parent 4e76aa3025
commit 053d801e92

View file

@ -631,31 +631,91 @@ trace_contents (hull_t *hull, trace_t *trace, clipleaf_t *leaf,
return contents; return contents;
} }
typedef struct {
qboolean seen_empty;
qboolean seen_solid;
qboolean moved;
plane_t *split_plane;
vec3_t vel;
const vec_t *origin;
const vec_t *start_point;
const vec_t *end_point;
} trace_state_t;
static int
visit_leaf (hull_t *hull, int num, clipleaf_t *leaf, trace_t *trace,
trace_state_t *state)
{
// it's not possible to not be in the leaf when doing a point trace
// if leaf is null, assume we're in the leaf
// if plane is null, the trace did not cross the last node plane
int in_leaf = 1;
if (trace->type != tr_point && leaf && state->split_plane)
in_leaf = check_in_leaf (hull, trace, leaf, state->split_plane,
state->vel, state->origin);
if (in_leaf && num == CONTENTS_SOLID) {
if (!state->seen_empty && !state->seen_solid) {
// this is the first leaf visited, thus the start leaf
trace->startsolid = state->seen_solid = true;
} else if (!state->seen_empty && state->seen_solid) {
// If crossing from one solid leaf to another, treat the
// whole trace as solid (this is what id does).
// However, since allsolid is initialized to true, no need
// to do anything.
if (state->moved)
return 1;
} else {
// crossing from an empty leaf to a solid leaf: the trace
// has collided.
if (state->split_plane) {
calc_impact (hull, trace, state->start_point, state->end_point,
leaf, state->split_plane);
} else {
// if there's no split plane, then there is no impact
trace->fraction = 1.0;
}
if (trace->type == tr_point)
return 1;
}
} else if (in_leaf) {
state->seen_empty = true;
trace->allsolid = false;
if (num == CONTENTS_EMPTY)
trace->inopen = true;
else
trace->inwater = true;
}
return 0;
}
VISIBLE void VISIBLE void
MOD_TraceLine (hull_t *hull, int num, MOD_TraceLine (hull_t *hull, int num,
const vec3_t start_point, const vec3_t end_point, const vec3_t start_point, const vec3_t end_point,
trace_t *trace) trace_t *trace)
{ {
vec_t start_dist, end_dist, frac[2], offset; vec_t start_dist, end_dist, frac[2], offset;
vec3_t start, end, dist, vel; vec3_t start, end, dist;
int side; int side;
qboolean seen_empty, seen_solid, moved;
tracestack_t *tstack; tracestack_t *tstack;
tracestack_t tracestack[256]; tracestack_t tracestack[256];
mclipnode_t *node; mclipnode_t *node;
plane_t *plane, *split_plane; plane_t *plane;
clipleaf_t *leaf; clipleaf_t *leaf;
trace_state_t trace_state;
VectorCopy (start_point, start); VectorCopy (start_point, start);
VectorCopy (end_point, end); VectorCopy (end_point, end);
VectorSubtract (end, start, vel); VectorSubtract (end, start, trace_state.vel);
VectorNormalize (vel); VectorNormalize (trace_state.vel);
tstack = tracestack; tstack = tracestack;
seen_empty = false; trace_state.start_point = start_point;
seen_solid = false; trace_state.end_point = end_point;
moved = false; trace_state.origin = start;
split_plane = 0; trace_state.seen_empty = false;
trace_state.seen_solid = false;
trace_state.moved = false;
trace_state.split_plane = 0;
leaf = 0; leaf = 0;
plane = 0; plane = 0;
@ -667,45 +727,8 @@ MOD_TraceLine (hull_t *hull, int num,
while (1) { while (1) {
while (num < 0) { while (num < 0) {
// it's not possible to not be in the leaf when doing a point trace if (visit_leaf (hull, num, leaf, trace, &trace_state))
// if leaf is null, assume we're in the leaf return;
// if plane is null, the trace did not cross the last node plane
int in_leaf = 1;
if (trace->type != tr_point && leaf && split_plane)
in_leaf = check_in_leaf (hull, trace, leaf, split_plane,
vel, start);
if (in_leaf && num == CONTENTS_SOLID) {
if (!seen_empty && !seen_solid) {
// this is the first leaf visited, thus the start leaf
trace->startsolid = seen_solid = true;
} else if (!seen_empty && seen_solid) {
// If crossing from one solid leaf to another, treat the
// whole trace as solid (this is what id does).
// However, since allsolid is initialized to true, no need
// to do anything.
if (moved)
return;
} else {
// crossing from an empty leaf to a solid leaf: the trace
// has collided.
if (split_plane) {
calc_impact (hull, trace, start_point, end_point, leaf,
split_plane);
} else {
// if there's no split plane, then there is no impact
trace->fraction = 1.0;
}
if (trace->type == tr_point)
return;
}
} else if (in_leaf) {
seen_empty = true;
trace->allsolid = false;
if (num == CONTENTS_EMPTY)
trace->inopen = true;
else
trace->inwater = true;
}
// pop up the stack for a back side // pop up the stack for a back side
do { do {
@ -721,8 +744,8 @@ MOD_TraceLine (hull_t *hull, int num,
// go down the back side // go down the back side
VectorCopy (tstack->end, end); VectorCopy (tstack->end, end);
side = tstack->side; side = tstack->side;
split_plane = tstack->plane; trace_state.split_plane = tstack->plane;
moved = tstack->start_frac > 0; trace_state.moved = tstack->start_frac > 0;
if (hull->nodeleafs) if (hull->nodeleafs)
leaf = hull->nodeleafs[tstack->num].leafs[side ^ 1]; leaf = hull->nodeleafs[tstack->num].leafs[side ^ 1];
@ -788,7 +811,7 @@ MOD_TraceLine (hull_t *hull, int num,
// if the move is parallel to the plane, then the plane is not a good // if the move is parallel to the plane, then the plane is not a good
// split plane // split plane
if (start_dist == end_dist) if (start_dist == end_dist)
tstack->plane = split_plane; tstack->plane = trace_state.split_plane;
VectorCopy (end, tstack->end); VectorCopy (end, tstack->end);
VectorMultAdd (start, frac[side ^ 1], dist, tstack->start); VectorMultAdd (start, frac[side ^ 1], dist, tstack->start);
tstack->start_frac = frac[side ^ 1]; tstack->start_frac = frac[side ^ 1];