Remove get_closest_waypoint prototype functions

This commit is contained in:
blubs 2024-08-04 07:44:56 -07:00
parent 4c6eaf0a2a
commit 2c65089a2c
3 changed files with 0 additions and 496 deletions

View file

@ -1896,129 +1896,6 @@ qboolean ofs_tracebox(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int ty
typedef struct nearest_walkable_waypoint_results_s {
int best_tracebox_waypoint_idx;
float best_tracebox_waypoint_dist_squared;
int best_traceline_waypoint_idx;
float best_tracline_waypoint_dist_squared;
} nearest_walkable_waypoint_results_t;
//
// Recursive K-D tree nearest-neighbor lookup on waypoints
// Searches the subtree with node `waypoint_idx` as the root
//
void nearest_walkable_waypoint_kdtree(int waypoint_idx, edict_t *ent, int debug_level, nearest_walkable_waypoint_results_t *result) {
float waypoint_dist_squared = VectorDistanceSquared(ent->v.origin, waypoints[waypoint_idx].origin);
if(waypoint_dist_squared < result->best_tracebox_waypoint_dist_squared) {
if(ofs_tracebox(ent->v.origin, ai_hull_mins, ai_hull_maxs, waypoints[waypoint_idx].origin, MOVE_NOMONSTERS, ent)) {
result->best_tracebox_waypoint_dist_squared = waypoint_dist_squared;
result->best_tracebox_waypoint_idx = waypoint_idx;
}
}
if(developer.value == 3) {
for(int i = -1; i < debug_level; i++) {
Con_Printf("\t");
}
Con_Printf("kd after checking node %d with dist: %.2f, cur best: %d with dist: %.2f\n",
waypoint_idx,
waypoint_dist_squared,
result->best_tracebox_waypoint_idx,
result->best_tracebox_waypoint_dist_squared
);
}
int axis = waypoints_kdtree_axis[waypoint_idx];
int halfspace_child_idx;
int other_halfspace_child_idx;
if(ent->v.origin[axis] <= waypoints[waypoint_idx].origin[axis]) {
halfspace_child_idx = waypoints_kdtree_left_child_node[waypoint_idx];
other_halfspace_child_idx = waypoints_kdtree_right_child_node[waypoint_idx];
}
else {
halfspace_child_idx = waypoints_kdtree_right_child_node[waypoint_idx];
other_halfspace_child_idx = waypoints_kdtree_left_child_node[waypoint_idx];
}
if(developer.value == 3) {
for(int i = -1; i < debug_level; i++) {
Con_Printf("\t");
}
if(ent->v.origin[axis] <= waypoints[waypoint_idx].origin[axis]) {
Con_Printf("kd - Query point (%.2f, %.2f, %.2f) in left half-space of node %d at (%.2f, %.2f, %.2f) on axis %d. Left child: %d, Right child: %d\n",
ent->v.origin[0], ent->v.origin[1], ent->v.origin[2],
waypoint_idx,
waypoints[waypoint_idx].origin[0], waypoints[waypoint_idx].origin[1], waypoints[waypoint_idx].origin[2],
axis,
waypoints_kdtree_left_child_node[waypoint_idx],
waypoints_kdtree_right_child_node[waypoint_idx]
);
}
else {
Con_Printf("kd - Query point (%.2f, %.2f, %.2f) in right half-space of node %d at (%.2f, %.2f, %.2f) on axis %d. Left child: %d, Right child: %d\n",
ent->v.origin[0], ent->v.origin[1], ent->v.origin[2],
waypoint_idx,
waypoints[waypoint_idx].origin[0], waypoints[waypoint_idx].origin[1], waypoints[waypoint_idx].origin[2],
axis,
waypoints_kdtree_left_child_node[waypoint_idx],
waypoints_kdtree_right_child_node[waypoint_idx]
);
}
}
if(halfspace_child_idx >= 0) {
nearest_walkable_waypoint_kdtree(halfspace_child_idx, ent, debug_level + 1, result);
}
// // Check if the other half-space is closer than the best point so far
if(other_halfspace_child_idx >= 0) {
float other_halfspace_dist_squared = (ent->v.origin[axis] - waypoints[waypoint_idx].origin[axis]);
other_halfspace_dist_squared *= other_halfspace_dist_squared;
if(other_halfspace_dist_squared < result->best_tracebox_waypoint_dist_squared) {
if(developer.value == 3) {
for(int i = -1; i < debug_level; i++) {
Con_Printf("\t");
}
Con_Printf("kd - Query point (%.2f, %.2f, %.2f) dist to half-space plane of node %d at (%.2f, %.2f, %.2f) on axis %d = %.2f < cur best node dist: %.2f -- checking opposite half-space\n",
ent->v.origin[0], ent->v.origin[1], ent->v.origin[2],
waypoint_idx,
waypoints[waypoint_idx].origin[0], waypoints[waypoint_idx].origin[1], waypoints[waypoint_idx].origin[2],
axis,
other_halfspace_dist_squared,
result->best_tracebox_waypoint_dist_squared
);
}
nearest_walkable_waypoint_kdtree(other_halfspace_child_idx, ent, debug_level + 1, result);
}
}
if(developer.value == 3) {
for(int i = -1; i < debug_level; i++) {
Con_Printf("\t");
}
Con_Printf("kd after checking node %d children: cur best: %d with dist: %.2f\n",
result->best_tracebox_waypoint_idx,
result->best_tracebox_waypoint_dist_squared
);
}
// return best_waypoint_idx;
}
//
// Returns the clsoest waypoint to an entity that the entity can walk to
@ -2058,215 +1935,6 @@ int get_closest_waypoint(int entnum) {
return best_waypoint_idx;
}
//
// Returns the clsoest waypoint to an entity that the entity can walk to
// Uses K-D tree lookup
//
int get_closest_waypoint_v1(int entnum) {
trace_t trace;
edict_t *ent = EDICT_NUM(entnum);
int waypoint_idx = -1;
nearest_walkable_waypoint_results_t nearest_waypoint_result;
nearest_waypoint_result.best_tracebox_waypoint_idx = -1;
nearest_waypoint_result.best_tracebox_waypoint_dist_squared = INFINITY;
nearest_waypoint_result.best_traceline_waypoint_idx = -1;
nearest_waypoint_result.best_tracline_waypoint_dist_squared = INFINITY;
vec3_t ent_mins;
vec3_t ent_maxs;
VectorCopy(ai_hull_mins, ent_mins);
VectorCopy(ai_hull_maxs, ent_maxs);
if(developer.value == 3) {
Con_Printf("get_closest_waypoint -- For ent: %d at (%.2f, %.2f, %.2f), prev cloest way: %d, cur dist: %.2f \n",
entnum,
ent->v.origin[0], ent->v.origin[1], ent->v.origin[2],
closest_waypoints[entnum],
closest_waypoints[entnum] < 0 ? NAN : VectorDistanceSquared(ent->v.origin, waypoints[closest_waypoints[entnum]].origin)
);
}
int prev_closest_way = closest_waypoints[entnum];
// Check if the prior closest waypoint is still walkable, if so set that as upper limit when comparing against other waypoints
if(prev_closest_way >= 0) {
// Try against the prev waypoint first
if(ofs_tracebox(ent->v.origin, ent_mins, ent_maxs, waypoints[prev_closest_way].origin, MOVE_NOMONSTERS, ent)) {
nearest_waypoint_result.best_tracebox_waypoint_idx = prev_closest_way;
nearest_waypoint_result.best_tracebox_waypoint_dist_squared = VectorDistanceSquared(waypoints[prev_closest_way].origin, ent->v.origin);
if(developer.value == 3) {
Con_Printf("\tget_closest_waypoint -- Can walk to prev waypoint %d at dist: %.2f\n",
nearest_waypoint_result.best_tracebox_waypoint_idx,
nearest_waypoint_result.best_tracebox_waypoint_dist_squared
);
}
}
}
if(waypoints_kdtree_root_node >= 0) {
nearest_walkable_waypoint_kdtree( waypoints_kdtree_root_node, ent, 0, &nearest_waypoint_result);
waypoint_idx = nearest_waypoint_result.best_tracebox_waypoint_idx;
}
if(developer.value == 3) {
Con_Printf("\tget_closest_waypoint -- Final best waypoint %d at dist: %.2f\n",
nearest_waypoint_result.best_tracebox_waypoint_idx,
nearest_waypoint_result.best_tracebox_waypoint_dist_squared
);
}
closest_waypoints[entnum] = waypoint_idx;
return waypoint_idx;
}
//
// Returns the closest waypoint to an entity that the entity can walk to
//
int get_closest_waypoint_v0(int entnum) {
// int get_closest_waypoint(int entnum) {
trace_t trace;
edict_t *ent = EDICT_NUM(entnum);
// Keep track of the closest waypoint that...
int best_traceline_way = -1; // ... we are able to traceline to
int best_tracebox_way = -1; // ... we are able to tracebox to
float best_traceline_way_dist = max_waypoint_distance * max_waypoint_distance;
float best_tracebox_way_dist = max_waypoint_distance * max_waypoint_distance;
// Start the search from the last known closest waypoint and its neighbors
// Assuming that at least one of the previous waypoint and its neighbors
// is still traceline-able to, we'll easily skip tracelining against most
// map waypoints that are farther away.
int prev_closest_way = closest_waypoints[entnum];
// ------------------------------------------------------------------------
// New logic:
// ------------------------------------------------------------------------
// Try traceboxing against prev waypoint / its neighbors
// If we traceboxed against any, that's the best and skip to checking against all
// Successful tracebox implies successful traceline
//
// If we have a waypoint we've traceboxed against, don't bother tracelining
// against waypoints, we already know which we're going to return in the
// worst-case.
// ------------------------------------------------------------------------
if(prev_closest_way >= 0) {
// Try against the prev waypoint first
trace = SV_Move(ent->v.origin, vec3_origin, vec3_origin, waypoints[prev_closest_way].origin, MOVE_NOMONSTERS, ent);
if(trace.fraction >= 1) {
best_traceline_way_dist = VectorDistanceSquared(waypoints[prev_closest_way].origin, ent->v.origin);
best_traceline_way = prev_closest_way;
}
// Otherwise, try against its neighbors
else {
for(int i = 0; i < 8; i++) {
int neighbor_way = waypoints[prev_closest_way].target[i];
// Skip unused neighbor slots / unused waypoint slots / inactive waypoints
if (neighbor_way < 0 || !waypoints[neighbor_way].used || !waypoints[neighbor_way].open) {
continue;
}
float dist = VectorDistanceSquared(waypoints[neighbor_way].origin, ent->v.origin);
if(dist < best_traceline_way_dist || best_traceline_way == -1) {
trace = SV_Move(ent->v.origin, vec3_origin, vec3_origin, waypoints[neighbor_way].origin, MOVE_NOMONSTERS, ent);
if (trace.fraction >= 1) {
best_traceline_way_dist = dist;
best_traceline_way = neighbor_way;
}
}
}
}
// Try against the prev waypoint first
if(ofs_tracebox(ent->v.origin, ent->v.mins, ent->v.maxs, waypoints[prev_closest_way].origin, MOVE_NOMONSTERS, ent)) {
best_tracebox_way_dist = VectorDistanceSquared(waypoints[prev_closest_way].origin, ent->v.origin);
best_tracebox_way = prev_closest_way;
}
// Otherwise, try against its neighbors
else {
for(int i = 0; i < 8; i++) {
int neighbor_way = waypoints[prev_closest_way].target[i];
// Skip unused neighbor slots / unused waypoint slots / inactive waypoints
if (neighbor_way < 0 || !waypoints[neighbor_way].used || !waypoints[neighbor_way].open) {
continue;
}
float dist = VectorDistanceSquared(waypoints[neighbor_way].origin, ent->v.origin);
if(dist < best_tracebox_way_dist || best_tracebox_way == -1) {
if(ofs_tracebox(ent->v.origin, ent->v.mins, ent->v.maxs, waypoints[neighbor_way].origin, MOVE_NOMONSTERS, ent)) {
best_tracebox_way_dist = dist;
best_tracebox_way = neighbor_way;
}
}
}
}
}
// Now we may have an initial valid `best_traceline_way` / `best_traceline_way_dist`
// We can safely skip all waypoints farther away than this
for(int i = 0; i < n_waypoints; i++) {
// Skip unused waypoint slots / inactive waypoints
if(!waypoints[i].used || !waypoints[i].open) {
continue;
}
float dist = VectorDistanceSquared(waypoints[i].origin, ent->v.origin);
// If we have a `best_tracebox_way`, that will take precedence as a return value over any traceline-able waypoint.
// Therefore, if we know of a waypoint that we can tracebox to, skip all traceline checks against all waypoints
if(best_tracebox_way == -1) {
if((i != best_traceline_way && dist < best_traceline_way_dist) || best_traceline_way == -1) {
trace = SV_Move(ent->v.origin, vec3_origin, vec3_origin, waypoints[i].origin, MOVE_NOMONSTERS, ent);
if(trace.fraction >= 1) {
best_traceline_way_dist = dist;
best_traceline_way = i;
}
}
}
if((i != best_tracebox_way && dist < best_tracebox_way_dist) || best_tracebox_way == -1) {
if(ofs_tracebox(ent->v.origin, ent->v.mins, ent->v.maxs, waypoints[i].origin, MOVE_NOMONSTERS, ent)) {
best_tracebox_way_dist = dist;
best_tracebox_way = i;
}
}
}
int best_way = -1;
// If we can tracebox to any waypoint, return the closest one:
if(best_tracebox_way >= 0) {
best_way = best_tracebox_way;
}
// Otherwise, return the best waypoint we found that we can traceline to
// (which may be none for some if a map's waypoints aren't great)
else {
best_way = best_traceline_way;
}
// Cache the closest waypoint to this entity, so that we start the next search from this same waypoint and its neighbors
closest_waypoints[entnum] = best_way;
return best_way;
}
void Do_Pathfind (void) {

View file

@ -356,11 +356,6 @@ extern waypoint_ai waypoints[MAX_WAYPOINTS];
extern int n_waypoints;
extern short closest_waypoints[MAX_EDICTS];
extern int waypoints_kdtree_root_node;
extern int waypoints_kdtree_left_child_node[MAX_WAYPOINTS];
extern int waypoints_kdtree_right_child_node[MAX_WAYPOINTS];
extern int waypoints_kdtree_axis[MAX_WAYPOINTS];
// thread structs

View file

@ -1388,11 +1388,6 @@ void W_stov (char *v, vec3_t out)
waypoint_ai waypoints[MAX_WAYPOINTS];
int n_waypoints;
int waypoints_kdtree_root_node;
int waypoints_kdtree_left_child_node[MAX_WAYPOINTS];
int waypoints_kdtree_right_child_node[MAX_WAYPOINTS];
int waypoints_kdtree_axis[MAX_WAYPOINTS];
//
@ -1505,157 +1500,6 @@ void Load_Waypoint_NZPBETA() {
W_fclose(h);
}
int build_waypoints_kdsubtree(int *sublist_waypoint_idxs, int sublist_n_waypoints, int *kdtree_left_child_nodes, int *kdtree_right_child_nodes, int *kdtree_axis, int level) {
if(sublist_n_waypoints <= 0) {
return -1;
}
// int axis = level % 3; // At each level, iterate through 3D space axes (x,y,z)
int axis;
// ------------------------------------------------------------------------
// Determine which axis to split on: Whichever has the largest spatial extent
// ------------------------------------------------------------------------
// axis = level % 3;
// -----------------
vec3_t mins;
vec3_t maxs;
VectorCopy(waypoints[sublist_waypoint_idxs[0]].origin, mins);
VectorCopy(waypoints[sublist_waypoint_idxs[0]].origin, maxs);
for(int i = 1; i < sublist_n_waypoints; i++) {
int waypoint_idx = sublist_waypoint_idxs[i];
VectorMin(mins, waypoints[waypoint_idx].origin, mins);
VectorMax(maxs, waypoints[waypoint_idx].origin, maxs);
}
vec3_t spatial_extent;
VectorSubtract(maxs, mins, spatial_extent);
// Pick largest axis:
float max_extent = fmax(spatial_extent[0], fmax(spatial_extent[1], spatial_extent[2]));
axis = (spatial_extent[0] >= max_extent) ? 0 : (spatial_extent[1] >= max_extent) ? 1 : 2;
// ------------------------------------------------------------------------
// Con_Printf("kdtree - building subtree at level: %d\n", level);
// ------------------------------------------------------------------------
// The root node for this subtree will bee the median waypoint along the axis
//
// To find the median, sort the waypoints by their value along the axis
// and take the middle waypoint
// ------------------------------------------------------------------------
argsort_entry_t waypoint_sort_values[MAX_WAYPOINTS];
for(int i = 0; i < sublist_n_waypoints; i++) {
waypoint_sort_values[i].index = sublist_waypoint_idxs[i];
waypoint_sort_values[i].value = waypoints[sublist_waypoint_idxs[i]].origin[axis];
}
// Con_Printf("\tkdtree - about to call qsort for %d waypoints\n", sublist_n_waypoints);
qsort(waypoint_sort_values, sublist_n_waypoints, sizeof(argsort_entry_t), argsort_comparator);
// Con_Printf("\tkdtree - qsort done\n");
// Con_Printf("\tkdtree - qsort list: [");
// for(int i = 0; i < sublist_n_waypoints; i++) {
// Con_Printf("(%d, %d, %.2f), ", i, waypoint_sort_values[i].index, waypoint_sort_values[i].value);
// }
// Con_Printf("]\n");
int median_waypoint_idx = waypoint_sort_values[sublist_n_waypoints / 2].index;
// Con_Printf("\tkdtree - qsort done, median waypoint idx: %d\n", median_waypoint_idx);
// ------------------------------------------------------------------------
// Split all waypoints in this subtree into left / right half-spaces
int left_waypoint_idxs[MAX_WAYPOINTS];
int right_waypoint_idxs[MAX_WAYPOINTS];
int n_left_waypoints = 0;
int n_right_waypoints = 0;
for(int i = 0; i < sublist_n_waypoints; i++) {
int waypoint_idx = sublist_waypoint_idxs[i];
if(waypoint_idx == median_waypoint_idx) {
continue;
}
if(waypoints[waypoint_idx].origin[axis] <= waypoints[median_waypoint_idx].origin[axis]) {
// Con_Printf("\t\tkdtree - (%d, %.2f) <= (%d, %.2f)\n", waypoint_idx, waypoints[waypoint_idx].origin[axis], median_waypoint_idx, waypoints[median_waypoint_idx].origin[axis]);
left_waypoint_idxs[n_left_waypoints++] = waypoint_idx;
}
else {
// Con_Printf("\t\tkdtree - (%d, %.2f) > (%d, %.2f)\n", waypoint_idx, waypoints[waypoint_idx].origin[axis], median_waypoint_idx, waypoints[median_waypoint_idx].origin[axis]);
right_waypoint_idxs[n_right_waypoints++] = waypoint_idx;
}
}
// Con_Printf("\tkdtree - Left subtree: %d, Right subtree: %d\n", n_left_waypoints, n_right_waypoints);
kdtree_left_child_nodes[median_waypoint_idx] = build_waypoints_kdsubtree(left_waypoint_idxs, n_left_waypoints, kdtree_left_child_nodes, kdtree_right_child_nodes, kdtree_axis, level+1);
kdtree_right_child_nodes[median_waypoint_idx] = build_waypoints_kdsubtree(right_waypoint_idxs, n_right_waypoints, kdtree_left_child_nodes, kdtree_right_child_nodes, kdtree_axis, level+1);
kdtree_axis[median_waypoint_idx] = axis;
return median_waypoint_idx;
}
//
// Constructs a K-D tree from the loaded waypoints for efficient nearest-neighbor lookup
//
void build_waypoints_kdtree() {
int n_waypoint_idxs = 0;
int all_waypoint_idxs[MAX_WAYPOINTS];
// Build a contiguous list of valid waypoint indices in the global waypoints array
for(int i = 0; i < MAX_WAYPOINTS; i++) {
// Skip empty waypoint slots in waypoints list
if(waypoints[i].used) {
all_waypoint_idxs[n_waypoint_idxs++] = i;
}
// Initialize values:
waypoints_kdtree_left_child_node[i] = -1;
waypoints_kdtree_right_child_node[i] = -1;
waypoints_kdtree_axis[i] = 0;
}
// Con_Printf("About to build waypoints KD tree\n");
waypoints_kdtree_root_node = build_waypoints_kdsubtree(all_waypoint_idxs, n_waypoint_idxs, waypoints_kdtree_left_child_node, waypoints_kdtree_right_child_node, waypoints_kdtree_axis, 0);
Con_Printf("Root waypoint idx: %d\n", waypoints_kdtree_root_node);
for(int i = 0; i < n_waypoints; i++) {
Con_Printf("{'waypoint_idx': %d, 'pos': [%.2f, %.2f, %.2f], 'axis': %d, 'left_child_idx': %d, 'right_child_idx': %d}\n",
i,
waypoints[i].origin[0], waypoints[i].origin[1], waypoints[i].origin[2],
waypoints_kdtree_axis[i],
waypoints_kdtree_left_child_node[i],
waypoints_kdtree_right_child_node[i]
);
}
}
extern int get_closest_waypoint(int entnum);
void benchmark_waypoints() {
Con_Printf("============== Benchmark Start ==============\n");
int n_iters = 100;
for(int i = 0; i < n_waypoints; i++) {
for(int j = 0; j < n_iters; j++) {
vec3_t query_point;
// Move 50 qu along x-axis
VectorCopy(waypoints[i].origin, query_point);
query_point[0] += 50;
// Yes, this is cursed, but I need to set query point
int entnum = 1;
edict_t *ent = EDICT_NUM(entnum);
VectorCopy(query_point, ent->v.origin);
int closest_waypoint = get_closest_waypoint(entnum);
}
}
Con_Printf("============== Benchmark Done ==============\n");
}
//
// Some waypoint slots in the global list may not have been loaded
// Look for these empty slots, and shift all waypoints down to fill them
@ -1741,7 +1585,6 @@ void Load_Waypoint () {
Con_DPrintf("No waypoint file (%s/maps/%s.way) found, trying beta format..\n", com_gamedir, sv.name);
Load_Waypoint_NZPBETA();
cleanup_waypoints();
build_waypoints_kdtree();
return;
}
@ -1836,8 +1679,6 @@ void Load_Waypoint () {
W_fclose(h);
//Z_Free (w_string_temp);
cleanup_waypoints();
build_waypoints_kdtree();
benchmark_waypoints();
}