mirror of
https://github.com/nzp-team/quakec.git
synced 2025-02-17 17:31:14 +00:00
Adds FTE navmesh editor from navmesh branch
This commit is contained in:
parent
30a0895d45
commit
316a8b3372
13 changed files with 3497 additions and 12 deletions
|
@ -4,8 +4,10 @@
|
|||
../source/shared/defs/custom.qc
|
||||
../source/shared/sound_enhanced.qc
|
||||
../source/shared/weapon_defines.qc
|
||||
../source/shared/navmesh_defines.qc
|
||||
../source/client/defs/custom.qc
|
||||
../source/client/menu.qc
|
||||
../source/client/achievements.qc
|
||||
../source/client/hud.qc
|
||||
../source/client/main.qc
|
||||
../source/client/navmesh_editor.qc
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
../source/server/defs/fte.qc
|
||||
../source/shared/defs/custom.qc
|
||||
../source/shared/weapon_defines.qc
|
||||
../source/shared/navmesh_defines.qc
|
||||
../source/server/defs/custom.qc
|
||||
../source/server/clientfuncs.qc
|
||||
|
||||
|
@ -33,7 +34,9 @@
|
|||
|
||||
../source/server/entities/powerups.qc
|
||||
|
||||
../source/server/ai/navmesh_core.qc
|
||||
../source/server/ai/pathfind_code.qc
|
||||
../source/server/ai/chase_ai.qc
|
||||
../source/server/ai/ai_core.qc
|
||||
../source/server/ai/fte/waypoints_core.qc
|
||||
../source/server/ai/zombie_core.qc
|
||||
|
|
|
@ -28,6 +28,13 @@
|
|||
|
||||
#pragma warning disable Q302
|
||||
|
||||
#define VEC_HULL_MIN '-16 -16 -32'
|
||||
#define VEC_HULL_MAX '16 16 40'
|
||||
|
||||
#define VEC_HULL2_MIN '-32 -32 -24'
|
||||
#define VEC_HULL2_MAX '32 32 64'
|
||||
string mappath;
|
||||
|
||||
vector cursor_pos; /* Current mouse cursor position, updated in csqc_inputevent */
|
||||
float g_width, g_height; /* Globals for screen width and height */
|
||||
|
||||
|
@ -143,6 +150,11 @@ float achievement_pages;
|
|||
|
||||
float K_LEFTDOWN, K_RIGHTDOWN, K_BACKDOWN, K_FORWARDDOWN;
|
||||
|
||||
//Navmesh defs
|
||||
void() cl_register_navmesh_commands;
|
||||
float(string cmd) cl_navmesh_console_commands;
|
||||
void() cl_navmesh_editor_draw;
|
||||
|
||||
#define P_JUG 1
|
||||
#define P_DOUBLE 2
|
||||
#define P_SPEED 4
|
||||
|
|
|
@ -78,6 +78,8 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init =
|
|||
else
|
||||
platform_is_web = false;
|
||||
|
||||
cl_register_navmesh_commands();
|
||||
|
||||
//print("CSQC Started\n");
|
||||
dummy = spawn();
|
||||
if(serverkey("constate") == "disconnected")
|
||||
|
@ -219,6 +221,9 @@ noref void() CSQC_WorldLoaded =
|
|||
playerpoints[2] = -1;
|
||||
playerpoints[3] = -1;
|
||||
|
||||
mappath = strcat("maps/", mapname);
|
||||
mappath = strzone(mappath);
|
||||
|
||||
Achievement_Init();
|
||||
|
||||
// Dummy so that our other point particles work!
|
||||
|
@ -582,6 +587,10 @@ noref void(float width, float height, float menushown) CSQC_UpdateView =
|
|||
deltalisten("models/weapons/pistol/pistol.iqm", add_outline, 0);*/
|
||||
//deltalisten("models/humanoid_simplerig.iqm", add_outline, 0);
|
||||
|
||||
if(cvar("navmesh_edit_mode")) {
|
||||
cl_navmesh_editor_draw();
|
||||
}
|
||||
|
||||
//does what you think it does
|
||||
renderscene();
|
||||
|
||||
|
@ -634,6 +643,8 @@ noref float(string cmd) CSQC_ConsoleCommand =
|
|||
return TRUE;
|
||||
break;
|
||||
default:
|
||||
if(cl_navmesh_console_commands(cmd))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
|
|
2999
source/client/navmesh_editor.qc
Normal file
2999
source/client/navmesh_editor.qc
Normal file
File diff suppressed because it is too large
Load diff
|
@ -216,17 +216,17 @@ void create_framegroups() {
|
|||
|
||||
// Performs 1D linear interpolation between x1 and x2 on t=0 to t=1
|
||||
// NOTE - the value of t is clamped to always be 0<=t<=1
|
||||
float(float x1, float x2, float t) lerp = {
|
||||
// t = min(max(t,0.0), 1.0);
|
||||
// Thanks, QC
|
||||
if(t < 0.0) {
|
||||
t = 0.0;
|
||||
}
|
||||
else if(t > 1.0) {
|
||||
t = 1.0;
|
||||
}
|
||||
return t * (x2 - x1) + x1;
|
||||
};
|
||||
// float(float x1, float x2, float t) lerp = {
|
||||
// // t = min(max(t,0.0), 1.0);
|
||||
// // Thanks, QC
|
||||
// if(t < 0.0) {
|
||||
// t = 0.0;
|
||||
// }
|
||||
// else if(t > 1.0) {
|
||||
// t = 1.0;
|
||||
// }
|
||||
// return t * (x2 - x1) + x1;
|
||||
// };
|
||||
|
||||
|
||||
class AI_Zombie : AI_Chase {
|
||||
|
|
299
source/server/ai/navmesh_core.qc
Normal file
299
source/server/ai/navmesh_core.qc
Normal file
|
@ -0,0 +1,299 @@
|
|||
//List of all navmesh verts loaded on the server
|
||||
navmesh_vertex sv_navmesh_verts[NAV_MAX_VERTS];
|
||||
float sv_navmesh_vert_count;
|
||||
|
||||
//List of all navmesh polies loaded on the server
|
||||
navmesh_poly sv_navmesh_polies[NAV_MAX_POLIES];
|
||||
float sv_navmesh_poly_count;
|
||||
|
||||
void () Navmesh_Editor_Logic =
|
||||
{
|
||||
if (!cl_navmesh_edit_mode) {
|
||||
cl_navmesh_edit_mode = 1;
|
||||
|
||||
// ------------------------------------
|
||||
// Remove and disable all zombies
|
||||
// ------------------------------------
|
||||
entity zent;
|
||||
|
||||
zent = find (world, classname, "ai_zombie");
|
||||
while (zent)
|
||||
{
|
||||
remove(zent.goaldummy);
|
||||
remove(zent.larm);
|
||||
remove(zent.rarm);
|
||||
remove(zent.head);
|
||||
remove (zent);
|
||||
zent = find (zent, classname, "ai_zombie");
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
// Reset all doors and rename to "door_nzp"
|
||||
// -----------------------------------------
|
||||
|
||||
zent = find (world, classname, "door_nzp_cost");
|
||||
while (zent)
|
||||
{
|
||||
zent.solid = SOLID_NOT;
|
||||
zent.touch = SUB_Null;
|
||||
zent = find (zent, classname, "door_nzp_cost");
|
||||
}
|
||||
zent = find (world, classname, "door_nzp");
|
||||
while (zent)
|
||||
{
|
||||
zent.solid = SOLID_NOT;
|
||||
zent.touch = SUB_Null;
|
||||
zent.solid = SOLID_NOT;
|
||||
zent = find (zent, classname, "door_nzp");
|
||||
}
|
||||
zent = find (world, classname, "window");
|
||||
while (zent)
|
||||
{
|
||||
zent.solid = SOLID_NOT;
|
||||
zent.touch = SUB_Null;
|
||||
zent = find (zent, classname, "window");
|
||||
}
|
||||
|
||||
}
|
||||
// FIXME - Does navmesh need this?
|
||||
// We do need to modify the server, as doors need to be set to nonsolid,
|
||||
// but the client-side navmesh editor / functions is pretty nifty...
|
||||
// Waypoint_Functions();
|
||||
};
|
||||
|
||||
|
||||
void sv_load_navmesh_data()
|
||||
{
|
||||
string filepath;
|
||||
float file;
|
||||
|
||||
filepath = strcat(mappath, ".nav");
|
||||
file = fopen(filepath,FILE_READ);
|
||||
|
||||
if(file == -1)
|
||||
{
|
||||
print("Error: file \"",filepath,"\" not found.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//First line contains navmesh file semver
|
||||
string nav_file_version = fgets(file);
|
||||
|
||||
//Next line contains vertex count
|
||||
string line = fgets(file);
|
||||
float vert_count = stof(line);
|
||||
|
||||
if(vert_count > sv_navmesh_verts.length)
|
||||
{
|
||||
print("Error: navmesh file \"",filepath,"\" has an invalid vert count. (" , line, " > ", ftos(sv_navmesh_verts.length),").\n");
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
//The navmesh appears to be valid (we shouldn't need to clear the current navmesh values)
|
||||
sv_navmesh_vert_count = vert_count;
|
||||
|
||||
//Temp vector to assign component-wise
|
||||
vector temp;
|
||||
|
||||
|
||||
//Reading all of the vertex positions
|
||||
for(float i = 0; i < sv_navmesh_vert_count; i++)
|
||||
{
|
||||
line = fgets(file);
|
||||
temp = stov(line);
|
||||
sv_navmesh_verts[i].pos.x = temp.x;
|
||||
sv_navmesh_verts[i].pos.y = temp.y;
|
||||
sv_navmesh_verts[i].pos.z = temp.z;
|
||||
}
|
||||
|
||||
//Next line contains the number of polygons
|
||||
sv_navmesh_poly_count = stof(fgets(file));
|
||||
|
||||
//The next lines are each polygon
|
||||
for(float i = 0; i < sv_navmesh_poly_count; i++)
|
||||
{
|
||||
//Getting vertex count
|
||||
sv_navmesh_polies[i].vert_count = stof(fgets(file));
|
||||
//Getting vertices
|
||||
sv_navmesh_polies[i].verts[0] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].verts[1] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].verts[2] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].verts[3] = stof(fgets(file));
|
||||
//Getting polygon center
|
||||
temp = stov(fgets(file));
|
||||
sv_navmesh_polies[i].center.x = temp.x;
|
||||
sv_navmesh_polies[i].center.y = temp.y;
|
||||
sv_navmesh_polies[i].center.z = temp.z;
|
||||
//Getting link count
|
||||
sv_navmesh_polies[i].connected_polies_count = stof(fgets(file));
|
||||
//Getting links
|
||||
sv_navmesh_polies[i].connected_polies[0] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies[1] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies[2] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies[3] = stof(fgets(file));
|
||||
//Getting link edge left vertex
|
||||
sv_navmesh_polies[i].connected_polies_left_vert[0] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies_left_vert[1] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies_left_vert[2] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies_left_vert[3] = stof(fgets(file));
|
||||
//Getting link edge right vertex
|
||||
sv_navmesh_polies[i].connected_polies_right_vert[0] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies_right_vert[1] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies_right_vert[2] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies_right_vert[3] = stof(fgets(file));
|
||||
//Get link edge neighbor entrance edge index
|
||||
sv_navmesh_polies[i].connected_polies_neighbor_edge_index[0] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies_neighbor_edge_index[1] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies_neighbor_edge_index[2] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].connected_polies_neighbor_edge_index[3] = stof(fgets(file));
|
||||
//Get polygon doortarget
|
||||
sv_navmesh_polies[i].doortarget = fgets(file);
|
||||
//Get entrance edge
|
||||
sv_navmesh_polies[i].entrance_edge = stoi(fgets(file));
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
|
||||
//Navmesh functions used in pathfinding
|
||||
|
||||
//Returns 1 if pos is inside poly at index poly_index, 0 otherwise
|
||||
float sv_navmesh_is_inside_poly(vector pos, float poly_index)
|
||||
{
|
||||
//TODO: check if z coord is close enough to poly
|
||||
|
||||
local vector vert_to_pos;//points from vert to pos
|
||||
local vector vert_to_next;//points from vert to the next vertex
|
||||
local vector vert;
|
||||
local vector next_vert;
|
||||
float vert_count = sv_navmesh_polies[poly_index].vert_count;
|
||||
//We are considered to be in the polygon, if pos is on the left of all edges of the polygon (if verts are ordered in CW order)
|
||||
for(float i = 0; i < vert_count; i++)
|
||||
{
|
||||
vert = sv_navmesh_verts[sv_navmesh_polies[poly_index].verts[i]].pos;
|
||||
next_vert = sv_navmesh_verts[sv_navmesh_polies[poly_index].verts[(i + 1) % vert_count]].pos;
|
||||
|
||||
vert_to_pos = pos - vert;
|
||||
vert_to_next = next_vert - vert;
|
||||
|
||||
//Check if vert_to_pos is to the left of vert_to_next
|
||||
if(vert_to_next.x * vert_to_pos.y - vert_to_next.y * vert_to_pos.x < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//Returns distance from pos to an edge of the poly if pos is very close to an edge of the poly at index poly_index, -1 otherwise
|
||||
float sv_navmesh_dist_to_poly(vector pos, float poly_index)
|
||||
{
|
||||
float leeway = 30;//Must be within 30 qu of edge to be considered close
|
||||
|
||||
//TODO: check if close enough on z-axis
|
||||
local vector vert;
|
||||
local vector next_vert;
|
||||
float vert_count = sv_navmesh_polies[poly_index].vert_count;
|
||||
|
||||
float shortest_dist = 100000;
|
||||
|
||||
//Only considering 2D
|
||||
//pos.z = 0;
|
||||
|
||||
//We are considered to be in the polygon, if pos is on the left of all edges of the polygon (if verts are ordered in CW order)
|
||||
for(float i = 0; i < vert_count; i++)
|
||||
{
|
||||
vert = sv_navmesh_verts[sv_navmesh_polies[poly_index].verts[i]].pos;
|
||||
next_vert = sv_navmesh_verts[sv_navmesh_polies[poly_index].verts[(i + 1) % vert_count]].pos;
|
||||
|
||||
//Calculating in 2D:
|
||||
//vert.z = 0;
|
||||
//next_vert.z = 0;
|
||||
|
||||
float temp_dist = navmesh_2D_line_point_dist(vert, next_vert, pos);
|
||||
|
||||
if(temp_dist < shortest_dist)
|
||||
{
|
||||
shortest_dist = temp_dist;
|
||||
}
|
||||
}
|
||||
|
||||
if(shortest_dist < leeway)
|
||||
return shortest_dist;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Returns polygon that pos is inside of.
|
||||
//If we are in no polygon, returns a polygon whose edge we are sufficiently close to (might be in but are not due to a small error)
|
||||
//Otherwise, returns -1
|
||||
float sv_navmesh_get_containing_poly(vector pos)
|
||||
{
|
||||
//Get nearest polygon, and check if pos is in that polygon
|
||||
float closest_poly = -1;
|
||||
float closest_poly_dist = 1000000;
|
||||
|
||||
//In reality, there's no need to try ALL polygons, the one we are in should be within the nearest 10 or so, but checking all to be safe
|
||||
for(float i = 0; i < sv_navmesh_poly_count; i++)
|
||||
{
|
||||
//Check if we are sufficiently close enough to polygon i in the z-axis
|
||||
//Current method of checking: if pos is within 30 qu of polygon z-axis bounds
|
||||
float poly_min_z = sv_navmesh_verts[sv_navmesh_polies[i].verts[0]].pos.z;
|
||||
float poly_max_z = poly_min_z;
|
||||
|
||||
for(float j = 0; j < sv_navmesh_polies[i].vert_count; j++)
|
||||
{
|
||||
float vert_z = sv_navmesh_verts[sv_navmesh_polies[i].verts[j]].pos.z;
|
||||
poly_min_z = min(poly_min_z, vert_z);
|
||||
poly_max_z = max(poly_max_z, vert_z);
|
||||
}
|
||||
|
||||
// If we NOT between [min - 30, max + 30], skip this polygon
|
||||
// if(fabs(sv_navmesh_polies[0].center.z - pos.z) >= 30)
|
||||
if(pos.z < poly_min_z - 30 || pos.z > poly_max_z + 30)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
//Check if we are in polygon i
|
||||
if(sv_navmesh_is_inside_poly(pos,i))
|
||||
{
|
||||
// NOTE - Because is_inside_poly only checks if we are in it on X & Y axes,
|
||||
// NOTE we may have found a polygon on a floor below us or above us.
|
||||
// NOTE However, this may not be an issue. A polygon on a floor below
|
||||
// NOTE us would be at least about 80-ish qu away, and the checks done for
|
||||
// NOTE z proximity might be enough to stop us from choosing polygons on
|
||||
// NOTE different floors. I shall assume this works fine, and wait for a
|
||||
// NOTE counter-example that shows we'll need a more sophisticated strategy.
|
||||
//print("Ent pos is inside poly: ",ftos(i),".\n");
|
||||
return i;
|
||||
}
|
||||
|
||||
//If we are not in polygon i, check if we arse very close to one of its edges
|
||||
float dist = sv_navmesh_dist_to_poly(pos,i);
|
||||
|
||||
if(dist >= 0)
|
||||
{
|
||||
if(dist < closest_poly_dist)
|
||||
{
|
||||
closest_poly = i;
|
||||
closest_poly_dist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//============================================
|
||||
|
||||
/*if(closest_poly == -1)
|
||||
{
|
||||
print("Ent pos is not in or near any polygons.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
print("Ent pos is near but not in poly: closest_poly.\n");
|
||||
}*/
|
||||
|
||||
return closest_poly;
|
||||
}
|
|
@ -429,6 +429,7 @@ float rounds_change;
|
|||
void () Waypoint_Logic;
|
||||
entity current_way;
|
||||
float waypoint_mode;
|
||||
float cl_navmesh_edit_mode;
|
||||
entity active_way;
|
||||
|
||||
#define MAX_WAY_TARGETS 10
|
||||
|
@ -472,6 +473,18 @@ string world_fog;
|
|||
#define UT_ZOOM2 4
|
||||
#define UT_CROSSHAIR 5
|
||||
|
||||
//======================= Navmesh defs ============================
|
||||
#ifdef PC
|
||||
void() Navmesh_Editor_Logic;
|
||||
void() sv_load_navmesh_data;
|
||||
#endif // PC
|
||||
|
||||
// //One struct for temp pathfinding calculations per zombie
|
||||
// //pathfind_result sv_zombie_pathfind_result[MAX_ZOMBIES];
|
||||
// pathfind_result *sv_zombie_pathfind_result;
|
||||
|
||||
//=================================================================
|
||||
|
||||
//Misc patch definitions
|
||||
.string teddyremovetarget;
|
||||
|
||||
|
|
|
@ -346,6 +346,18 @@ void() door_trigger_touch =
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef PC
|
||||
if(cvar("navmesh_edit_mode")) {
|
||||
if(strcmp(cvar_string("nav_editor_active_door"), self.owner.wayTarget) != 0) {
|
||||
bprint(PRINT_HIGH, "Current Door for navmesh editor set to \"");
|
||||
bprint(PRINT_HIGH, self.owner.wayTarget); // naiveil (FIXME)
|
||||
bprint(PRINT_HIGH, "\"\n");
|
||||
cvar_set("nav_editor_active_door", self.owner.wayTarget);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif // PC
|
||||
|
||||
if (other.health <= 20)
|
||||
return;
|
||||
|
||||
|
|
|
@ -98,6 +98,11 @@ void() StartFrame =
|
|||
return;
|
||||
}
|
||||
|
||||
if (cl_navmesh_edit_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (roundinit) {
|
||||
Round_Core();
|
||||
|
@ -335,6 +340,13 @@ void() worldspawn =
|
|||
mappath = strzone(mappath);
|
||||
|
||||
LoadWaypointData();
|
||||
// sv_load_navmesh_data();
|
||||
|
||||
// //Allocating memory for the zombie's pathfinding data
|
||||
// sv_zombie_pathfind_result = memalloc(sizeof(pathfind_result) * MAX_ZOMBIES);
|
||||
//I should technically deallocate the memory, but I've nowhere to put this, and it SHOULD be cleared automatically upon vm reset
|
||||
//memfree(sv_zombie_pathfind_result);
|
||||
|
||||
|
||||
//set game elements
|
||||
G_STARTPOINTS = 500;
|
||||
|
|
|
@ -309,7 +309,13 @@ void() PlayerPreThink =
|
|||
|
||||
if (cvar("waypoint_mode")) {
|
||||
Waypoint_Logic();
|
||||
} else {
|
||||
}
|
||||
#ifdef PC
|
||||
else if (cvar("navmesh_edit_mode")) {
|
||||
Navmesh_Editor_Logic();
|
||||
}
|
||||
#endif // PC
|
||||
else {
|
||||
Weapon_Logic();
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,13 @@ const float EVENT_REVIVECHANGE = 39;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// NAVMESH BEGIN - Increases stringtable size, adds support for memalloc.
|
||||
#ifdef PC
|
||||
#pragma target FTE
|
||||
#endif
|
||||
// NAVMESH END
|
||||
|
||||
// Weapon Firetype definitions
|
||||
#define FIRETYPE_FULLAUTO 0
|
||||
#define FIRETYPE_SEMIAUTO 1
|
||||
|
|
109
source/shared/navmesh_defines.qc
Normal file
109
source/shared/navmesh_defines.qc
Normal file
|
@ -0,0 +1,109 @@
|
|||
//A single navmesh vertex
|
||||
struct navmesh_vertex
|
||||
{
|
||||
vector pos;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//Either a tri or a quad
|
||||
struct navmesh_poly
|
||||
{
|
||||
float verts[4];
|
||||
float vert_count;
|
||||
string doortarget; // "" or matches the .wayTarget field of a door entity. Polygon is only used when door is open (i.e. door.state == STATE_BOTTOM)
|
||||
// TODO - Remove this, will be replaced by traversals
|
||||
int entrance_edge; // If != -1, specifies which edge index this polygon can be entered from. (0,1,2, or 3)
|
||||
|
||||
//The following fields are only used for actually pathfinding on the navmesh
|
||||
//The values are calculated in the editor when the navmesh is saved, but are not assigned in the editor before that.
|
||||
//These values are saved in the navmesh file, and loaded into the server's navmesh
|
||||
//FIXME: Unhandled edge case when a polygon shares a single edge with more than one polygon (like dropping down from a ledge)
|
||||
float connected_polies_count;//How many polygons we share an edge with
|
||||
float connected_polies[4];//Index of the polygons that we share an edge with (similar to links), more than 4 should be impossible (FIXME: highly unlikely)
|
||||
float connected_polies_left_vert[4];//The left vertex of the shared edge
|
||||
float connected_polies_right_vert[4];//The right vertex of the shared edge
|
||||
float connected_polies_neighbor_edge_index[4]; // conected_polies_neighbor_edge_index[i] holds the ith neighbor's edge index we are traversing to enter the neighbor polygon. This is used for polygons that may only be entered from a specific direction.
|
||||
vector center;//The center of the polygon in 3D space (pre-calculated because why calculate it at runtime)
|
||||
};
|
||||
|
||||
|
||||
#define NAV_MAX_VERTS 1024
|
||||
#define NAV_MAX_POLIES 512
|
||||
|
||||
// ============================================================================
|
||||
// Shared Navmesh functions used by both client and server
|
||||
// ============================================================================
|
||||
|
||||
//Returns the distance between the 2d line l1->l2 and pos
|
||||
float navmesh_2D_line_point_dist(vector l1, vector l2, vector pos)
|
||||
{
|
||||
float dot = (l2 - l1) * (pos - l2);
|
||||
if(dot > 0)
|
||||
return vlen(l2 - pos);
|
||||
|
||||
dot = (l1 - l2) * (pos - l1);
|
||||
if(dot > 0)
|
||||
return vlen(l1 - pos);
|
||||
|
||||
//2D cross product between (next_vert-vert) and (pos-vert)
|
||||
//float dist = (l2.x - l1.x) * (pos.y - l1.y) - (l2.y - l1.y) * (pos.y - l1.y);
|
||||
//dist = dist / vlen(l1 - l2);
|
||||
|
||||
float dist = vlen(crossproduct(l2-l1,l1-pos))/vlen(l1-l2);
|
||||
|
||||
return fabs(dist);
|
||||
}
|
||||
|
||||
//============= Navmesh Pathfind Defs =============
|
||||
#define PATHFIND_POLY_SET_NONE 0
|
||||
#define PATHFIND_POLY_SET_OPEN 1
|
||||
#define PATHFIND_POLY_SET_CLOSED 2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct pathfind_result
|
||||
{
|
||||
//Contains the set that the ith polygon is in
|
||||
float poly_set[NAV_MAX_POLIES];
|
||||
//Contains the index of the last polygon that we used to get to the ith polygon
|
||||
float poly_prev[NAV_MAX_POLIES];
|
||||
//Contains the g-score of the ith polygon (distance from start node to ith node along the node path)
|
||||
float poly_g_score[NAV_MAX_POLIES];
|
||||
|
||||
//f score = g score + h score
|
||||
float poly_f_score[NAV_MAX_POLIES];
|
||||
|
||||
//Holds list of polygons in the path (indices of polygons from start to goal)
|
||||
float result_node_path[NAV_MAX_POLIES];
|
||||
//How many polies are in the path
|
||||
float result_node_length;
|
||||
|
||||
//Together, these two arrays hold the list of polygon edges we cross on the path
|
||||
float portals_left_vert[NAV_MAX_POLIES];
|
||||
float portals_right_vert[NAV_MAX_POLIES];
|
||||
//How many portals are in the pathfind_portals_left_vert (same as pathfind_result_node_length - 1)
|
||||
float portals_length;
|
||||
|
||||
// The traversal index of the ith polygon's traversal list that was used. -1 if no traversal used.
|
||||
float traversal_index[NAV_MAX_POLIES];
|
||||
|
||||
//Final resultant path:
|
||||
//Contains a list of points that makes up the path
|
||||
vector result_path[NAV_MAX_POLIES];
|
||||
//How many points are in the path
|
||||
float result_length;
|
||||
};
|
||||
|
||||
//Returns some number > 0 if point p is to the left of line a->b
|
||||
//Returns some number < 0 if point is to the right of line a->b
|
||||
//Returns 0 if point is on the line
|
||||
//(Left / Right is defined in the xy plane, z=0)
|
||||
float pathfind_point_is_to_left(vector a, vector b, vector p)
|
||||
{
|
||||
return (b.x - a.x)*(p.y - a.y) - (b.y - a.y)*(p.x - a.x);
|
||||
}
|
||||
|
||||
// ============================================================================
|
Loading…
Reference in a new issue