Initial commit
This commit is contained in:
12
.gitmodules
vendored
Normal file
12
.gitmodules
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[submodule "godot"]
|
||||||
|
path = godot
|
||||||
|
url = https://github.com/godotengine/godot
|
||||||
|
branch = 3.x
|
||||||
|
[submodule "modules/voronoi/thirdparty/voronoi"]
|
||||||
|
path = modules/voronoi/thirdparty/voronoi
|
||||||
|
url = https://github.com/JCash/voronoi
|
||||||
|
branch = dev
|
||||||
|
[submodule "modules/voxel"]
|
||||||
|
path = modules/voxel
|
||||||
|
url = https://github.com/Zylann/godot_voxel
|
||||||
|
branch = master
|
||||||
6
Makefile
Normal file
6
Makefile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
all:
|
||||||
|
cd godot; \
|
||||||
|
scons platform=x11 target=release_debug tools=yes custom_modules=../modules -j6
|
||||||
|
# scons platform=x11 target=release tools=yes custom_modules=../modules -j6
|
||||||
|
# scons platform=windows target=release tools=yes custom_modules=../modules -j6
|
||||||
|
# scons platform=javascript target=release tools=yes custom_modules=../modules -j6
|
||||||
1
godot
Submodule
1
godot
Submodule
Submodule godot added at 504f47eaec
77
modules/detour/SCsub
Normal file
77
modules/detour/SCsub
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from methods import using_gcc, get_compiler_version
|
||||||
|
|
||||||
|
Import('env')
|
||||||
|
Import('env_modules')
|
||||||
|
|
||||||
|
env_detour = env_modules.Clone()
|
||||||
|
|
||||||
|
# Thirdparty source files
|
||||||
|
# TODO: clean this up for recastnav+fastlz
|
||||||
|
detour_sources = []
|
||||||
|
thirdparty_sources = []
|
||||||
|
thirdparty_dir = "#thirdparty/recastnavigation/"
|
||||||
|
detour_dir = "thirdparty/"
|
||||||
|
if env['builtin_recast'] and not env["tools"]:
|
||||||
|
thirdparty_sources = [
|
||||||
|
"Recast/Source/Recast.cpp",
|
||||||
|
"Recast/Source/RecastAlloc.cpp",
|
||||||
|
"Recast/Source/RecastArea.cpp",
|
||||||
|
"Recast/Source/RecastAssert.cpp",
|
||||||
|
"Recast/Source/RecastContour.cpp",
|
||||||
|
"Recast/Source/RecastFilter.cpp",
|
||||||
|
"Recast/Source/RecastLayers.cpp",
|
||||||
|
"Recast/Source/RecastMesh.cpp",
|
||||||
|
"Recast/Source/RecastMeshDetail.cpp",
|
||||||
|
"Recast/Source/RecastRasterization.cpp",
|
||||||
|
"Recast/Source/RecastRegion.cpp",
|
||||||
|
]
|
||||||
|
# Detour source files
|
||||||
|
detour_sources += [
|
||||||
|
"Detour/Source/DetourAlloc.cpp",
|
||||||
|
"Detour/Source/DetourAssert.cpp",
|
||||||
|
"Detour/Source/DetourCommon.cpp",
|
||||||
|
"Detour/Source/DetourNavMeshBuilder.cpp",
|
||||||
|
"Detour/Source/DetourNavMesh.cpp",
|
||||||
|
"Detour/Source/DetourNavMeshQuery.cpp",
|
||||||
|
"Detour/Source/DetourNode.cpp",
|
||||||
|
]
|
||||||
|
|
||||||
|
# DetourCrowd source files
|
||||||
|
detour_sources += [
|
||||||
|
"DetourCrowd/Source/DetourCrowd.cpp",
|
||||||
|
"DetourCrowd/Source/DetourLocalBoundary.cpp",
|
||||||
|
"DetourCrowd/Source/DetourObstacleAvoidance.cpp",
|
||||||
|
"DetourCrowd/Source/DetourPathCorridor.cpp",
|
||||||
|
"DetourCrowd/Source/DetourPathQueue.cpp",
|
||||||
|
"DetourCrowd/Source/DetourProximityGrid.cpp",
|
||||||
|
]
|
||||||
|
|
||||||
|
# DetiurTileCache source files
|
||||||
|
detour_sources += [
|
||||||
|
"DetourTileCache/Source/DetourTileCacheBuilder.cpp",
|
||||||
|
"DetourTileCache/Source/DetourTileCache.cpp",
|
||||||
|
]
|
||||||
|
|
||||||
|
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||||
|
thirdparty_sources += [detour_dir + file for file in detour_sources]
|
||||||
|
|
||||||
|
env_detour.add_source_files(env.modules_sources, thirdparty_sources)
|
||||||
|
env_detour.Append(CPPPATH=[thirdparty_dir + "/Recast/Include",
|
||||||
|
detour_dir + "/Detour/Include",
|
||||||
|
detour_dir + "/DetourCrowd/Include",
|
||||||
|
detour_dir + "/DetourTileCache/Include",
|
||||||
|
"#thirdparty/misc"])
|
||||||
|
env_detour.Append(CPPFLAGS=["-DNDEBUG", "-DTILE_CACHE"])
|
||||||
|
# See https://github.com/recastnavigation/recastnavigation/issues/380
|
||||||
|
# for Wno-error=class-memaccess
|
||||||
|
if using_gcc(env):
|
||||||
|
gcc_version = get_compiler_version(env)
|
||||||
|
if gcc_version != None and gcc_version[0] >= 8 and not env["platform"] == "windows":
|
||||||
|
env_detour.Append(CPPFLAGS=["-Wno-error=class-memaccess", "-Wno-error=shadow=local"])
|
||||||
|
|
||||||
|
# Godot source files
|
||||||
|
env_detour.add_source_files(env.modules_sources, "*.cpp")
|
||||||
|
|
||||||
|
Export('env')
|
||||||
8
modules/detour/TODO.txt
Normal file
8
modules/detour/TODO.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
1. Node position fixup at start of loop (before update) (enable only when crowd does not control agents directly)
|
||||||
|
2. Fix agent states before update (need setting for that, disable by default)
|
||||||
|
3. Implement signal notification of nodes about their state, position, velocity
|
||||||
|
4. Implement agent parameters setting
|
||||||
|
5. bind agent state constants and allow checking agent state
|
||||||
|
6. Implement physics motion.
|
||||||
|
7. Implement area tagging
|
||||||
|
8. Implement tiled mesh and obstacles.
|
||||||
BIN
modules/detour/__pycache__/config.cpython-38.pyc
Normal file
BIN
modules/detour/__pycache__/config.cpython-38.pyc
Normal file
Binary file not shown.
BIN
modules/detour/__pycache__/config.cpython-39.pyc
Normal file
BIN
modules/detour/__pycache__/config.cpython-39.pyc
Normal file
Binary file not shown.
5
modules/detour/config.py
Normal file
5
modules/detour/config.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
def can_build(env, platform):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def configure(env):
|
||||||
|
pass
|
||||||
671
modules/detour/crowd.cpp
Normal file
671
modules/detour/crowd.cpp
Normal file
@@ -0,0 +1,671 @@
|
|||||||
|
#include <cassert>
|
||||||
|
#include "crowd.h"
|
||||||
|
#include "navmesh_query.h"
|
||||||
|
#include <DetourCrowd.h>
|
||||||
|
#include <DetourCommon.h>
|
||||||
|
|
||||||
|
#define MAX_AGENTS 20
|
||||||
|
|
||||||
|
DetourCrowdManager::DetourCrowdManager() :
|
||||||
|
Node(),
|
||||||
|
crowd(0),
|
||||||
|
dirty(false),
|
||||||
|
initialized(false),
|
||||||
|
query(memnew(DetourNavigationQuery)),
|
||||||
|
max_agents(20),
|
||||||
|
max_agent_radius(0.0f) {}
|
||||||
|
DetourCrowdManager::~DetourCrowdManager() {
|
||||||
|
if (crowd) {
|
||||||
|
if (initialized)
|
||||||
|
dtFreeCrowd(crowd);
|
||||||
|
else
|
||||||
|
dtFree(crowd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::set_navigation_mesh(
|
||||||
|
const Ref<DetourNavigationMesh> &navmesh, const Transform &xform) {
|
||||||
|
this->navmesh = navmesh;
|
||||||
|
this->transform = xform;
|
||||||
|
query->init(navmesh, xform);
|
||||||
|
|
||||||
|
create_crowd();
|
||||||
|
}
|
||||||
|
Ref<DetourNavigationMesh> DetourCrowdManager::get_navigation_mesh() const {
|
||||||
|
return navmesh;
|
||||||
|
}
|
||||||
|
int DetourCrowdManager::add_agent(Object *agent, int mode, bool signals, PoolVector<float> inparams) {
|
||||||
|
AgentData *new_agent = memnew(AgentData);
|
||||||
|
int aid = -1, id;
|
||||||
|
uint64_t pref;
|
||||||
|
|
||||||
|
new_agent->obj_id = agent->get_instance_id();
|
||||||
|
new_agent->mode = mode;
|
||||||
|
if (inparams.size() != 4) {
|
||||||
|
inparams.resize(4);
|
||||||
|
inparams.write()[0] = 1.0f;
|
||||||
|
inparams.write()[1] = 2.0f;
|
||||||
|
inparams.write()[2] = 0.5f;
|
||||||
|
inparams.write()[3] = 100.0f;
|
||||||
|
}
|
||||||
|
new_agent->radius = inparams[0];
|
||||||
|
new_agent->height = inparams[1];
|
||||||
|
new_agent->max_accel = inparams[2];
|
||||||
|
new_agent->max_speed = inparams[3];
|
||||||
|
new_agent->filter_id = 0;
|
||||||
|
new_agent->oa_id = 0;
|
||||||
|
new_agent->mode = mode;
|
||||||
|
new_agent->send_signals = signals;
|
||||||
|
Vector3 pos;
|
||||||
|
Spatial *obj = Object::cast_to<Spatial>(agent);
|
||||||
|
if (obj)
|
||||||
|
pos = obj->get_global_transform().origin;
|
||||||
|
pos = _nearest_point(pos, 0, &pref);
|
||||||
|
assert(pref > 0);
|
||||||
|
dtCrowdAgentParams params;
|
||||||
|
memset(¶ms, 0, sizeof(params));
|
||||||
|
params.radius = new_agent->radius;
|
||||||
|
params.height = new_agent->height;
|
||||||
|
params.maxAcceleration = new_agent->max_accel;
|
||||||
|
params.maxSpeed = new_agent->max_speed;
|
||||||
|
params.pathOptimizationRange = params.radius * 30.0f;
|
||||||
|
params.queryFilterType = (unsigned char)new_agent->filter_id;
|
||||||
|
params.obstacleAvoidanceType = (unsigned char)new_agent->oa_id;
|
||||||
|
if (agents.size() == 0) {
|
||||||
|
agents.push_back(new_agent);
|
||||||
|
aid = 0;
|
||||||
|
} else {
|
||||||
|
bool ok = false;
|
||||||
|
for (aid = 0; aid < agents.size(); aid++)
|
||||||
|
if (agents[aid] == NULL) {
|
||||||
|
agents.write[aid] = new_agent;
|
||||||
|
ok = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!ok)
|
||||||
|
aid = -1;
|
||||||
|
}
|
||||||
|
if (aid == -1) {
|
||||||
|
agents.push_back(new_agent);
|
||||||
|
aid = 0;
|
||||||
|
}
|
||||||
|
params.userData = new_agent;
|
||||||
|
id = crowd->addAgent(&pos.coord[0], ¶ms);
|
||||||
|
assert(id >= 0);
|
||||||
|
// printf("agent id = %d\n", id);
|
||||||
|
new_agent->id = id;
|
||||||
|
dtCrowdAgent *ag = crowd->getEditableAgent(id);
|
||||||
|
assert(ag);
|
||||||
|
assert(ag->state != DT_CROWDAGENT_STATE_INVALID);
|
||||||
|
ag->state = DT_CROWDAGENT_STATE_WALKING;
|
||||||
|
|
||||||
|
if (max_agents < agents.size()) {
|
||||||
|
max_agents = agents.size() + 20;
|
||||||
|
create_crowd();
|
||||||
|
}
|
||||||
|
if (signals && obj)
|
||||||
|
obj->emit_signal("agent_added", id);
|
||||||
|
obj->set_meta("agent_id", aid);
|
||||||
|
obj->set_meta("agent_crowd_id", id);
|
||||||
|
return agents.size() - 1;
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::remove_agent(Object *agent) {
|
||||||
|
int agent_id = agent->get_instance_id();
|
||||||
|
for (int i = 0; i < agents.size(); i++) {
|
||||||
|
if (!agents[i])
|
||||||
|
continue;
|
||||||
|
if (agents[i]->obj_id == agent_id) {
|
||||||
|
crowd->removeAgent(agents[i]->id);
|
||||||
|
memfree(agents[i]);
|
||||||
|
agents.write[i] = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::clear_agent_list() {
|
||||||
|
agents.clear();
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::set_target(const Vector3 &position) {}
|
||||||
|
void DetourCrowdManager::set_velocity(const Vector3 &position) {}
|
||||||
|
void DetourCrowdManager::reset_target() {}
|
||||||
|
void DetourCrowdManager::set_max_agents(int max_agents) {
|
||||||
|
this->max_agents = max_agents;
|
||||||
|
create_crowd();
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::set_max_agent_radius(float radius) {
|
||||||
|
max_agent_radius = radius;
|
||||||
|
create_crowd();
|
||||||
|
}
|
||||||
|
DetourCrowdManager::AgentData::AgentData() :
|
||||||
|
obj_id(-1),
|
||||||
|
mode(0),
|
||||||
|
id(0),
|
||||||
|
radius(1.0f),
|
||||||
|
height(2.0f),
|
||||||
|
max_accel(10.5f),
|
||||||
|
max_speed(30.0f),
|
||||||
|
filter_id(0),
|
||||||
|
oa_id(0) {}
|
||||||
|
DetourCrowdManager::AgentData::~AgentData() {}
|
||||||
|
void DetourCrowdManager::process_agent(dtCrowdAgent *agent) {
|
||||||
|
if (!agent || !agent->params.userData)
|
||||||
|
return;
|
||||||
|
AgentData *data = (AgentData *)agent->params.userData;
|
||||||
|
bool update_params = false;
|
||||||
|
Object * obj = ObjectDB::get_instance(data->obj_id);
|
||||||
|
if (!obj)
|
||||||
|
return;
|
||||||
|
#if 0
|
||||||
|
Node *node = Object::cast_to<Node>(data->obj);
|
||||||
|
if (!node)
|
||||||
|
returnl
|
||||||
|
if (!node->is_inside_tree())
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
dtCrowdAgentParams params = agent->params;
|
||||||
|
#if 0
|
||||||
|
if (!params.radius > 0.0f) {
|
||||||
|
params.radius = data->radius;
|
||||||
|
params.height = data->height;
|
||||||
|
params.maxAcceleration = data->max_accel;
|
||||||
|
params.pathOptimizationRange = data->radius * 30.0f;
|
||||||
|
params.queryFilterType = data->filter_id;
|
||||||
|
params.obstacleAvoidanceType = data->oa_id;
|
||||||
|
update_params = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!params.updateFlags) {
|
||||||
|
params.updateFlags = DT_CROWD_OPTIMIZE_TOPO | DT_CROWD_OPTIMIZE_VIS |
|
||||||
|
DT_CROWD_ANTICIPATE_TURNS | DT_CROWD_SEPARATION |
|
||||||
|
DT_CROWD_OBSTACLE_AVOIDANCE;
|
||||||
|
update_params = true;
|
||||||
|
}
|
||||||
|
if (!(params.separationWeight > 0.0f)) {
|
||||||
|
params.separationWeight = 4.0f;
|
||||||
|
params.collisionQueryRange = 16.0f * data->radius; /* *radius */
|
||||||
|
update_params = true;
|
||||||
|
}
|
||||||
|
if (update_params)
|
||||||
|
crowd->updateAgentParameters(data->id, ¶ms);
|
||||||
|
Vector3 position;
|
||||||
|
Vector3 velocity;
|
||||||
|
Vector3 desired_velocity;
|
||||||
|
memcpy(&position, agent->npos, sizeof(float) * 3);
|
||||||
|
memcpy(&velocity, agent->vel, sizeof(float) * 3);
|
||||||
|
memcpy(&desired_velocity, agent->dvel, sizeof(float) * 3);
|
||||||
|
#if 0
|
||||||
|
printf("process_agent: %p: position: %ls, velocity: %ls, desired_velocity: %ls, state: %d\n",
|
||||||
|
agent, String(position).c_str(),
|
||||||
|
String(velocity).c_str(), String(desired_velocity).c_str(),
|
||||||
|
(int)agent->state);
|
||||||
|
#endif
|
||||||
|
#if 0
|
||||||
|
Transform transform = data->obj->get_global_transform();
|
||||||
|
if (velocity.length() == 0.0f)
|
||||||
|
velocity = transform.basis[2];
|
||||||
|
if (data->mode == 0)
|
||||||
|
data->obj->look_at_from_position(position, position + velocity,
|
||||||
|
Vector3(0, 1, 0));
|
||||||
|
#endif
|
||||||
|
if (data->send_signals)
|
||||||
|
obj->emit_signal("agent_position", position, velocity,
|
||||||
|
desired_velocity, (int)agent->state);
|
||||||
|
obj->set_meta("agent_position", position);
|
||||||
|
obj->set_meta("agent_velocity", velocity);
|
||||||
|
obj->set_meta("agent_desired_velocity", desired_velocity);
|
||||||
|
obj->set_meta("agent_state", (int)agent->state);
|
||||||
|
}
|
||||||
|
Vector3 DetourCrowdManager::_nearest_point(const Vector3 &point,
|
||||||
|
int query_filter,
|
||||||
|
polyref_t *nearest_ref) {
|
||||||
|
if (!navmesh.is_valid() || !crowd)
|
||||||
|
return point;
|
||||||
|
polyref_t nearestRef = 0;
|
||||||
|
Vector3 ret;
|
||||||
|
if (!query) {
|
||||||
|
if (nearest_ref)
|
||||||
|
*nearest_ref = nearestRef;
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
ret = query->nearest_point_(point, Vector3(*reinterpret_cast<const Vector3 *>(crowd->getQueryExtents())),
|
||||||
|
crowd->getFilter(query_filter), &nearestRef);
|
||||||
|
if (nearest_ref)
|
||||||
|
*nearest_ref = nearestRef;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bool DetourCrowdManager::has_arrived(int id)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
dtCrowdAgent* ag = crowd->getEditableAgent(agents[id]->id);
|
||||||
|
assert(ag);
|
||||||
|
ret = !ag->ncorners ||
|
||||||
|
(ag->cornerFlags[ag->ncorners - 1] & DT_STRAIGHTPATH_END &&
|
||||||
|
dtVdist2D(ag->npos, &ag->cornerVerts[(ag->ncorners - 1) * 3]) <=
|
||||||
|
ag->params.radius);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::clear_agent_target(int id)
|
||||||
|
{
|
||||||
|
if (!agents[id]) {
|
||||||
|
printf("!!bad agent %d\n", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(agents[id]);
|
||||||
|
crowd->resetMoveTarget(agents[id]->id);
|
||||||
|
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::set_agent_target_position(int id,
|
||||||
|
const Vector3 &position) {
|
||||||
|
uint64_t pref;
|
||||||
|
if (!agents[id]) {
|
||||||
|
printf("!!bad agent %d\n", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(agents[id]);
|
||||||
|
Vector3 close = _nearest_point(position, 0, &pref);
|
||||||
|
dtPolyRef nearestRef = (dtPolyRef)pref;
|
||||||
|
// printf("set target position %d %d %ls\n", id, agents[id]->id, String(close).c_str());
|
||||||
|
dtCrowdAgent *ag = crowd->getEditableAgent(agents[id]->id);
|
||||||
|
if (ag->state == DT_CROWDAGENT_STATE_INVALID)
|
||||||
|
ag->state = DT_CROWDAGENT_STATE_WALKING;
|
||||||
|
crowd->requestMoveTarget(agents[id]->id, nearestRef, &close.coord[0]);
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::reset_agent(int id)
|
||||||
|
{
|
||||||
|
dtCrowdAgent *ag = crowd->getEditableAgent(agents[id]->id);
|
||||||
|
dtCrowdAgentParams params;
|
||||||
|
Vector3 pos, target;
|
||||||
|
uint64_t tref;
|
||||||
|
Object *obj = ObjectDB::get_instance(agents[id]->obj_id);
|
||||||
|
assert(obj);
|
||||||
|
Spatial *sp = Object::cast_to<Spatial>(obj);
|
||||||
|
|
||||||
|
assert(ag);
|
||||||
|
memcpy(¶ms, &ag->params, sizeof(params));
|
||||||
|
if (!sp)
|
||||||
|
memcpy(&pos.coord[0], ag->npos, sizeof(pos.coord));
|
||||||
|
else
|
||||||
|
pos = sp->get_global_transform().origin;
|
||||||
|
memcpy(&target.coord[0], ag->targetPos, sizeof(target.coord));
|
||||||
|
|
||||||
|
tref = ag->targetRef;
|
||||||
|
crowd->removeAgent(agents[id]->id);
|
||||||
|
int new_agent = crowd->addAgent(&pos.coord[0], ¶ms);
|
||||||
|
assert(new_agent >= 0);
|
||||||
|
agents[id]->id = new_agent;
|
||||||
|
crowd->requestMoveTarget(agents[id]->id, tref, &target.coord[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourCrowdManager::_notification(int p_what) {
|
||||||
|
switch (p_what) {
|
||||||
|
case NOTIFICATION_READY:
|
||||||
|
create_crowd();
|
||||||
|
set_process(true);
|
||||||
|
break;
|
||||||
|
case NOTIFICATION_ENTER_TREE:
|
||||||
|
create_crowd();
|
||||||
|
break;
|
||||||
|
case NOTIFICATION_EXIT_TREE:
|
||||||
|
agents.clear();
|
||||||
|
break;
|
||||||
|
case NOTIFICATION_PROCESS:
|
||||||
|
float delta = get_process_delta_time();
|
||||||
|
// update_crowd(delta);
|
||||||
|
if (crowd && navmesh.is_valid() && agents.size() > 0) {
|
||||||
|
int i;
|
||||||
|
crowd->update(delta, NULL);
|
||||||
|
Vector<dtCrowdAgent *> active_agents;
|
||||||
|
active_agents.resize(agents.size());
|
||||||
|
int nactive =
|
||||||
|
crowd->getActiveAgents(&active_agents.write[0], agents.size());
|
||||||
|
for (i = 0; i < nactive; i++)
|
||||||
|
process_agent(active_agents[i]);
|
||||||
|
for (i = 0; i < agents.size(); i++) {
|
||||||
|
if (!agents[i])
|
||||||
|
continue;
|
||||||
|
Object *obj = ObjectDB::get_instance(agents[i]->obj_id);
|
||||||
|
assert(obj);
|
||||||
|
if (!obj->has_meta("agent_position"))
|
||||||
|
continue;
|
||||||
|
Vector3 pos = obj->get_meta("agent_position");
|
||||||
|
Spatial *sp = Object::cast_to<Spatial>(obj);
|
||||||
|
Vector3 opos = sp->get_global_transform().origin;
|
||||||
|
if (fabs(pos.y - opos.y) < 1.5f)
|
||||||
|
pos.y = opos.y;
|
||||||
|
/* resetting agent position */
|
||||||
|
dtCrowdAgent *ag = crowd->getEditableAgent(agents[i]->id);
|
||||||
|
if (!ag->active)
|
||||||
|
continue;
|
||||||
|
// printf("%d:%d active: %d state: %d tstate: %d vel: %f %f %f\n", i, agents[i]->id, ag->active, ag->state, ag->targetState, ag->vel[0], ag->vel[1], ag->vel[2]);
|
||||||
|
if (opos.distance_squared_to(pos) > 0.01f ||
|
||||||
|
ag->state == DT_CROWDAGENT_STATE_INVALID) {
|
||||||
|
uint64_t pref;
|
||||||
|
Vector3 close = _nearest_point(opos, 0, &pref);
|
||||||
|
dtPolyRef nearestRef = (dtPolyRef)pref;
|
||||||
|
memcpy(ag->npos, &close.coord[0], sizeof(float) * 3);
|
||||||
|
if (ag->targetState != DT_CROWDAGENT_TARGET_NONE)
|
||||||
|
crowd->requestMoveTarget(agents[i]->id, ag->targetRef, ag->targetPos);
|
||||||
|
}
|
||||||
|
if (ag->state == DT_CROWDAGENT_STATE_INVALID) {
|
||||||
|
ag->state = DT_CROWDAGENT_STATE_WALKING;
|
||||||
|
if (ag->targetState != DT_CROWDAGENT_TARGET_NONE)
|
||||||
|
crowd->requestMoveTarget(agents[i]->id, ag->targetRef, ag->targetPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::update_crowd(float delta) {
|
||||||
|
if (dirty)
|
||||||
|
create_crowd();
|
||||||
|
}
|
||||||
|
bool DetourCrowdManager::create_crowd() {
|
||||||
|
dirty = true;
|
||||||
|
if (!navmesh.is_valid())
|
||||||
|
return false;
|
||||||
|
if (crowd) {
|
||||||
|
if (initialized)
|
||||||
|
dtFreeCrowd(crowd);
|
||||||
|
else
|
||||||
|
dtFree(crowd);
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
crowd = dtAllocCrowd();
|
||||||
|
if (max_agent_radius == 0.0f)
|
||||||
|
max_agent_radius = navmesh->get_agent_radius();
|
||||||
|
if (navmesh->get_navmesh() != NULL)
|
||||||
|
print_line("good navmesh");
|
||||||
|
else
|
||||||
|
print_line("bad navmesh");
|
||||||
|
if (!crowd->init(max_agents, max_agent_radius, navmesh->get_navmesh()))
|
||||||
|
return false;
|
||||||
|
dirty = false;
|
||||||
|
initialized = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::set_area_cost(int filter_id, int area_id, float cost) {
|
||||||
|
dtQueryFilter *filter = crowd->getEditableFilter(filter_id);
|
||||||
|
if (filter)
|
||||||
|
filter->setAreaCost(area_id, cost);
|
||||||
|
}
|
||||||
|
float DetourCrowdManager::get_area_cost(int filter_id, int area_id) {
|
||||||
|
const dtQueryFilter *filter = crowd->getFilter(filter_id);
|
||||||
|
if (!filter)
|
||||||
|
return 1.0f;
|
||||||
|
return filter->getAreaCost(area_id);
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::set_include_flags(int filter_id,
|
||||||
|
unsigned short flags) {
|
||||||
|
dtQueryFilter *filter = crowd->getEditableFilter(filter_id);
|
||||||
|
if (filter)
|
||||||
|
filter->setIncludeFlags(flags);
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::set_exclude_flags(int filter_id,
|
||||||
|
unsigned short flags) {
|
||||||
|
dtQueryFilter *filter = crowd->getEditableFilter(filter_id);
|
||||||
|
if (filter)
|
||||||
|
filter->setExcludeFlags(flags);
|
||||||
|
}
|
||||||
|
unsigned short DetourCrowdManager::get_include_flags(int filter_id) {
|
||||||
|
const dtQueryFilter *filter = crowd->getFilter(filter_id);
|
||||||
|
if (!filter)
|
||||||
|
return 0U;
|
||||||
|
return filter->getIncludeFlags();
|
||||||
|
}
|
||||||
|
unsigned short DetourCrowdManager::get_exclude_flags(int filter_id) {
|
||||||
|
const dtQueryFilter *filter = crowd->getFilter(filter_id);
|
||||||
|
if (!filter)
|
||||||
|
return 0U;
|
||||||
|
return filter->getExcludeFlags();
|
||||||
|
}
|
||||||
|
void DetourCrowdManager::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navmesh", "xform"),
|
||||||
|
&DetourCrowdManager::set_navigation_mesh);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_navigation_mesh"),
|
||||||
|
&DetourCrowdManager::get_navigation_mesh);
|
||||||
|
ClassDB::bind_method(D_METHOD("add_agent", "agent", "mode", "signals", "params"),
|
||||||
|
&DetourCrowdManager::add_agent);
|
||||||
|
ClassDB::bind_method(D_METHOD("remove_agent", "agent"),
|
||||||
|
&DetourCrowdManager::remove_agent);
|
||||||
|
ClassDB::bind_method(D_METHOD("clear_agent_list"),
|
||||||
|
&DetourCrowdManager::clear_agent_list);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_agent_obj", "id"),
|
||||||
|
&DetourCrowdManager::get_agent_obj);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_agent_mode", "id"),
|
||||||
|
&DetourCrowdManager::get_agent_mode);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_agent_count"),
|
||||||
|
&DetourCrowdManager::get_agent_count);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_target", "position"),
|
||||||
|
&DetourCrowdManager::set_target);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"),
|
||||||
|
&DetourCrowdManager::set_velocity);
|
||||||
|
ClassDB::bind_method(D_METHOD("reset_target"),
|
||||||
|
&DetourCrowdManager::reset_target);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_max_agents", "max_agents"),
|
||||||
|
&DetourCrowdManager::set_max_agents);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_max_agents"),
|
||||||
|
&DetourCrowdManager::get_max_agents);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_max_agent_radius", "max_agent_radius"),
|
||||||
|
&DetourCrowdManager::set_max_agent_radius);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_max_agent_radius"),
|
||||||
|
&DetourCrowdManager::get_max_agent_radius);
|
||||||
|
ClassDB::bind_method(
|
||||||
|
D_METHOD("set_area_cost", "filter_id", "area_id", "cost"),
|
||||||
|
&DetourCrowdManager::set_area_cost);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_area_cost", "filter_id", "area_id"),
|
||||||
|
&DetourCrowdManager::get_area_cost);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_include_flags", "filter_id", "flags"),
|
||||||
|
&DetourCrowdManager::set_include_flags);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_include_flags", "filter_id"),
|
||||||
|
&DetourCrowdManager::get_include_flags);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_exclude_flags", "filter_id", "flags"),
|
||||||
|
&DetourCrowdManager::set_exclude_flags);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_exclude_flags", "filter_id"),
|
||||||
|
&DetourCrowdManager::get_exclude_flags);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_agent_target_position", "id", "position"),
|
||||||
|
&DetourCrowdManager::set_agent_target_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// void DetourCrowdManager::agent_update_cb(dtCrowdAgent *ag, float dt)
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
bool Crowd::_set(const StringName &p_name, const Variant &p_value) {
|
||||||
|
print_line("_set");
|
||||||
|
if (!manager)
|
||||||
|
return false;
|
||||||
|
String name = p_name;
|
||||||
|
print_line(String() + "setting " + name);
|
||||||
|
if (name == "add_object") {
|
||||||
|
if (p_value.get_type() == Variant::NIL)
|
||||||
|
return false;
|
||||||
|
String path = p_value;
|
||||||
|
NodePath npname = p_value;
|
||||||
|
print_line(String() + "setting spatial " + path);
|
||||||
|
agent_paths.push_back(npname);
|
||||||
|
modes.push_back(0);
|
||||||
|
print_line(String() + "agent count: " + itos(agent_paths.size()));
|
||||||
|
update_agent_list();
|
||||||
|
_change_notify();
|
||||||
|
return true;
|
||||||
|
} else if (name == "nav_mesh") {
|
||||||
|
if (p_value.get_type() == Variant::NODE_PATH) {
|
||||||
|
NodePath path = p_value;
|
||||||
|
DetourNavigationMeshInstance *nmi = (DetourNavigationMeshInstance*)get_node(path);
|
||||||
|
if (nmi) {
|
||||||
|
manager->set_navigation_mesh(nmi->get_navmesh());
|
||||||
|
_change_notify();
|
||||||
|
print_line("navmesh set from path");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (p_value.get_type() == Variant::OBJECT) {
|
||||||
|
Ref<Resource> ov = p_value;
|
||||||
|
if (ov.is_valid()) {
|
||||||
|
manager->set_navigation_mesh((Ref<DetourNavigationMesh>)ov);
|
||||||
|
print_line("navmesh set from resource");
|
||||||
|
_change_notify();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
print_line(String() + "type: " + itos(p_value.get_type()));
|
||||||
|
return false;
|
||||||
|
} else if (name.begins_with("agents")) {
|
||||||
|
int idx = name.get_slice("/", 1).to_int();
|
||||||
|
String what = name.get_slice("/", 2);
|
||||||
|
if (what == "path") {
|
||||||
|
if (agent_paths.size() > idx) {
|
||||||
|
NodePath path = p_value;
|
||||||
|
agent_paths.write[idx] = path;
|
||||||
|
} else {
|
||||||
|
NodePath path = p_value;
|
||||||
|
agent_paths.push_back(path);
|
||||||
|
}
|
||||||
|
} else if (what == "mode") {
|
||||||
|
int mode = p_value;
|
||||||
|
if (modes.size() > idx)
|
||||||
|
modes.write[idx] = mode;
|
||||||
|
else
|
||||||
|
modes.push_back(mode);
|
||||||
|
} else if (what == "remove") {
|
||||||
|
bool rm = p_value;
|
||||||
|
if (rm) {
|
||||||
|
agent_paths.remove(idx);
|
||||||
|
modes.remove(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_change_notify();
|
||||||
|
update_agent_list();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool Crowd::_get(const StringName &p_name, Variant &r_ret) const {
|
||||||
|
print_line("_get");
|
||||||
|
if (!manager)
|
||||||
|
return false;
|
||||||
|
String name = p_name;
|
||||||
|
if (name == "nav_mesh") {
|
||||||
|
r_ret = manager->get_navigation_mesh();
|
||||||
|
return true;
|
||||||
|
} else if (name.begins_with("agents")) {
|
||||||
|
int idx = name.get_slice("/", 1).to_int();
|
||||||
|
String what = name.get_slice("/", 2);
|
||||||
|
if (what == "path") {
|
||||||
|
r_ret = agent_paths[idx];
|
||||||
|
return true;
|
||||||
|
} else if (what == "mode") {
|
||||||
|
if (modes.size() > idx)
|
||||||
|
r_ret = modes[idx];
|
||||||
|
else
|
||||||
|
r_ret = 0;
|
||||||
|
return true;
|
||||||
|
} else if (what == "remove") {
|
||||||
|
r_ret = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void Crowd::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||||
|
print_line("_get_property_list");
|
||||||
|
if (!manager)
|
||||||
|
return;
|
||||||
|
if (manager->get_agent_count() > 0) {
|
||||||
|
for (int i = 0; i < agent_paths.size(); i++) {
|
||||||
|
p_list->push_back(PropertyInfo(Variant::NODE_PATH, "agents/" + itos(i) + "/path", PROPERTY_HINT_NONE, ""));
|
||||||
|
p_list->push_back(PropertyInfo(Variant::INT, "agents/" + itos(i) + "/mode", PROPERTY_HINT_ENUM, "normal,signal"));
|
||||||
|
p_list->push_back(PropertyInfo(Variant::BOOL, "agents/" + itos(i) + "/remove", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p_list->push_back(PropertyInfo(Variant::NODE_PATH, "add_object", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Spatial"));
|
||||||
|
if (!manager->get_navigation_mesh().is_valid())
|
||||||
|
p_list->push_back(PropertyInfo(Variant::NODE_PATH, "nav_mesh", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "DetourNavigationMeshInstance"));
|
||||||
|
else
|
||||||
|
p_list->push_back(PropertyInfo(Variant::OBJECT, "nav_mesh", PROPERTY_HINT_RESOURCE_TYPE, "DetourNavigationMesh"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Crowd::Crowd() :
|
||||||
|
manager(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Crowd::~Crowd()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Crowd::_notification(int p_what) {
|
||||||
|
switch(p_what) {
|
||||||
|
case NOTIFICATION_READY:
|
||||||
|
print_line("a");
|
||||||
|
if (!manager)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
update_agent_list();
|
||||||
|
break;
|
||||||
|
case NOTIFICATION_ENTER_TREE:
|
||||||
|
print_line("b");
|
||||||
|
manager = Object::cast_to<DetourCrowdManager>(get_parent());
|
||||||
|
if (!manager)
|
||||||
|
return;
|
||||||
|
else {
|
||||||
|
print_line("manager set");
|
||||||
|
update_agent_list();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NOTIFICATION_EXIT_TREE:
|
||||||
|
print_line("c");
|
||||||
|
manager = NULL;
|
||||||
|
break;
|
||||||
|
case NOTIFICATION_PROCESS:
|
||||||
|
float delta = get_process_delta_time();
|
||||||
|
// update_crowd(delta);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String Crowd::get_configuration_warning()
|
||||||
|
{
|
||||||
|
String ret;
|
||||||
|
print_line("get_configuration_warning");
|
||||||
|
if (!is_inside_tree())
|
||||||
|
return ret;
|
||||||
|
if (!manager)
|
||||||
|
ret += TTR("Incorrect instancing. ");
|
||||||
|
if (!Object::cast_to<DetourCrowdManager>(get_parent()))
|
||||||
|
ret += TTR("Should be parented to DetourCrowdManager. ");
|
||||||
|
if (manager && !manager->get_navigation_mesh().is_valid())
|
||||||
|
ret += TTR("No navmesh data are set to function. ");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
void Crowd::update_agent_list()
|
||||||
|
{
|
||||||
|
if (!is_inside_tree())
|
||||||
|
return;
|
||||||
|
if (!manager)
|
||||||
|
return;
|
||||||
|
print_line("update_agent_list");
|
||||||
|
manager->clear_agent_list();
|
||||||
|
print_line("update_agent_list 1");
|
||||||
|
for (int i = 0; i < agent_paths.size(); i++) {
|
||||||
|
print_line("update_agent_list 2: " + itos(i));
|
||||||
|
if (String(agent_paths[i]).length() > 0) {
|
||||||
|
print_line("update_agent_list 3: " + itos(i));
|
||||||
|
Spatial *obj = (Spatial *)get_node(agent_paths[i]);
|
||||||
|
print_line("update_agent_list 4: " + itos(i));
|
||||||
|
if (obj) {
|
||||||
|
print_line("update_agent_list 5: " + itos(i));
|
||||||
|
manager->add_agent(obj, modes[i]);
|
||||||
|
print_line("object added ok 0");
|
||||||
|
}
|
||||||
|
print_line("update_agent_list 6: " + itos(i));
|
||||||
|
} else {
|
||||||
|
print_line("update_agent_list 7: " + itos(i));
|
||||||
|
manager->add_agent(NULL, modes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_line("update_agent_list done");
|
||||||
|
}
|
||||||
|
void Crowd::_bind_methods()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
113
modules/detour/crowd.h
Normal file
113
modules/detour/crowd.h
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#include "detour.h"
|
||||||
|
#ifndef CROWD_H
|
||||||
|
#define CROWD_H
|
||||||
|
|
||||||
|
class dtCrowd;
|
||||||
|
class dtQueryFilter;
|
||||||
|
class DetourNavigationQuery;
|
||||||
|
struct dtCrowdAgent;
|
||||||
|
#if 0
|
||||||
|
class Crowd;
|
||||||
|
#endif
|
||||||
|
class DetourCrowdManager : public Node {
|
||||||
|
GDCLASS(DetourCrowdManager, Node);
|
||||||
|
class CrowdAgent;
|
||||||
|
struct AgentData {
|
||||||
|
int obj_id;
|
||||||
|
int mode;
|
||||||
|
int id;
|
||||||
|
float radius;
|
||||||
|
float height;
|
||||||
|
float max_accel;
|
||||||
|
float max_speed;
|
||||||
|
int filter_id;
|
||||||
|
int oa_id;
|
||||||
|
bool send_signals;
|
||||||
|
AgentData();
|
||||||
|
~AgentData();
|
||||||
|
};
|
||||||
|
Vector<AgentData *> agents;
|
||||||
|
friend class CrowdAgent;
|
||||||
|
dtCrowd *crowd;
|
||||||
|
bool dirty, initialized;
|
||||||
|
static void _bind_methods();
|
||||||
|
DetourNavigationQuery *query;
|
||||||
|
Transform transform;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void process_agent(dtCrowdAgent *agent);
|
||||||
|
void _notification(int p_what);
|
||||||
|
int max_agents;
|
||||||
|
float max_agent_radius;
|
||||||
|
const dtCrowdAgent *get_detour_crowd_agent(int agent);
|
||||||
|
const dtQueryFilter *get_detour_query_filter(int query_filter);
|
||||||
|
bool create_crowd();
|
||||||
|
dtCrowd *get_crowd() const { return crowd; }
|
||||||
|
Ref<DetourNavigationMesh> navmesh;
|
||||||
|
void update_crowd(float delta);
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef uint64_t polyref_t;
|
||||||
|
DetourCrowdManager();
|
||||||
|
~DetourCrowdManager();
|
||||||
|
Dictionary create_default_params() const;
|
||||||
|
int add_agent(Object *agent, int mode, bool signals, PoolVector<float> params);
|
||||||
|
void remove_agent(Object *agent);
|
||||||
|
void clear_agent_list();
|
||||||
|
Object *get_agent_obj(int id) const { return ObjectDB::get_instance(agents[id]->obj_id); }
|
||||||
|
int get_agent_mode(int id) const { return agents[id]->mode; }
|
||||||
|
int get_agent_count() const { return agents.size(); }
|
||||||
|
void set_agent_target_position(int id, const Vector3 &position);
|
||||||
|
void set_target(const Vector3 &position);
|
||||||
|
// void set_crowd_target_node(const Spatial *target);
|
||||||
|
void set_velocity(const Vector3 &position);
|
||||||
|
void reset_target();
|
||||||
|
void set_max_agents(int max_agents);
|
||||||
|
int get_max_agents() const { return max_agents; }
|
||||||
|
void set_max_agent_radius(float radius);
|
||||||
|
float get_max_agent_radius() const { return max_agent_radius; }
|
||||||
|
void set_navigation_mesh(const Ref<DetourNavigationMesh> &mesh, const Transform &xform);
|
||||||
|
Transform get_navigation_transform() const { return transform; }
|
||||||
|
Ref<DetourNavigationMesh> get_navigation_mesh() const;
|
||||||
|
/* Query filter */
|
||||||
|
void set_include_flags(int filter_id, unsigned short flags);
|
||||||
|
unsigned short get_include_flags(int filter_id);
|
||||||
|
void set_exclude_flags(int query_filter, unsigned short flags);
|
||||||
|
unsigned short get_exclude_flags(int query_filter);
|
||||||
|
void set_area_cost(int filter_id, int area_id, float cost);
|
||||||
|
float get_area_cost(int filter_id, int area_id);
|
||||||
|
int get_num_query_filters() const;
|
||||||
|
int get_num_aread(int query_filter) const;
|
||||||
|
/* Queries, FIXME */
|
||||||
|
Vector3 nearest_point(const Vector3 &point, int query_filter);
|
||||||
|
Vector3 _nearest_point(const Vector3 &point, int query_filter, polyref_t *nearest_ref);
|
||||||
|
Vector3 move_along_surface(const Vector3 &start, const Vector3 &end, int query_filter, int maxVisited = 3);
|
||||||
|
Vector<Vector3> find_path(const Vector3 &start, const Vector3 &end, int query_filter);
|
||||||
|
Vector3 get_random_point(int query_filter);
|
||||||
|
Vector3 get_random_point_in_circle(const Vector3 ¢er, float radius, int query_filter);
|
||||||
|
float get_distance_to_wall(const Vector3 &point, float radius, int query_filter);
|
||||||
|
Vector3 recast(const Vector3 &start, const Vector3 &end, int query_filter);
|
||||||
|
bool has_arrived(int id);
|
||||||
|
void clear_agent_target(int id);
|
||||||
|
void reset_agent(int id);
|
||||||
|
};
|
||||||
|
#if 0
|
||||||
|
class Crowd : public Spatial {
|
||||||
|
GDCLASS(Crowd, Spatial);
|
||||||
|
Vector<NodePath> agent_paths;
|
||||||
|
Vector<int> modes;
|
||||||
|
bool _set(const StringName &p_name, const Variant &p_value);
|
||||||
|
bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||||
|
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||||
|
void update_agent_list();
|
||||||
|
static void _bind_methods();
|
||||||
|
DetourCrowdManager *manager;
|
||||||
|
protected:
|
||||||
|
void _notification(int p_what);
|
||||||
|
public:
|
||||||
|
String get_configuration_warning();
|
||||||
|
Crowd();
|
||||||
|
~Crowd();
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
BIN
modules/detour/crowd.x11.opt.tools.64.o
Normal file
BIN
modules/detour/crowd.x11.opt.tools.64.o
Normal file
Binary file not shown.
775
modules/detour/detour-navmesh.cpp
Normal file
775
modules/detour/detour-navmesh.cpp
Normal file
@@ -0,0 +1,775 @@
|
|||||||
|
#include "detour-navmesh.h"
|
||||||
|
#include <DetourNavMesh.h>
|
||||||
|
#include <DetourNavMeshBuilder.h>
|
||||||
|
#include <DetourTileCache.h>
|
||||||
|
#include <DetourTileCacheBuilder.h>
|
||||||
|
#include <Recast.h>
|
||||||
|
#include <fastlz.h>
|
||||||
|
|
||||||
|
static const int DEFAULT_TILE_SIZE = 64;
|
||||||
|
static const float DEFAULT_CELL_SIZE = 0.3f;
|
||||||
|
static const float DEFAULT_CELL_HEIGHT = 0.2f;
|
||||||
|
static const float DEFAULT_AGENT_HEIGHT = 2.0f;
|
||||||
|
static const float DEFAULT_AGENT_RADIUS = 0.6f;
|
||||||
|
static const float DEFAULT_AGENT_MAX_CLIMB = 0.9f;
|
||||||
|
static const float DEFAULT_AGENT_MAX_SLOPE = 45.0f;
|
||||||
|
static const float DEFAULT_REGION_MIN_SIZE = 8.0f;
|
||||||
|
static const float DEFAULT_REGION_MERGE_SIZE = 20.0f;
|
||||||
|
static const float DEFAULT_EDGE_MAX_LENGTH = 12.0f;
|
||||||
|
static const float DEFAULT_EDGE_MAX_ERROR = 1.3f;
|
||||||
|
static const float DEFAULT_DETAIL_SAMPLE_DISTANCE = 6.0f;
|
||||||
|
static const float DEFAULT_DETAIL_SAMPLE_MAX_ERROR = 1.0f;
|
||||||
|
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
static const int DEFAULT_MAX_OBSTACLES = 1024;
|
||||||
|
static const int DEFAULT_MAX_LAYERS = 16;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
struct FastLZCompressor : public dtTileCacheCompressor {
|
||||||
|
virtual int maxCompressedSize(const int bufferSize) {
|
||||||
|
return (int)(bufferSize * 1.05f);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual dtStatus compress(const unsigned char *buffer, const int bufferSize,
|
||||||
|
unsigned char *compressed,
|
||||||
|
const int /*maxCompressedSize*/,
|
||||||
|
int *compressedSize) {
|
||||||
|
*compressedSize =
|
||||||
|
fastlz_compress((const void *)buffer, bufferSize, compressed);
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual dtStatus decompress(const unsigned char *compressed,
|
||||||
|
const int compressedSize, unsigned char *buffer,
|
||||||
|
const int maxBufferSize, int *bufferSize) {
|
||||||
|
*bufferSize =
|
||||||
|
fastlz_decompress(compressed, compressedSize, buffer, maxBufferSize);
|
||||||
|
return *bufferSize < 0 ? DT_FAILURE : DT_SUCCESS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct LinearAllocator : public dtTileCacheAlloc {
|
||||||
|
unsigned char *buffer;
|
||||||
|
size_t capacity;
|
||||||
|
size_t top;
|
||||||
|
size_t high;
|
||||||
|
|
||||||
|
LinearAllocator(const size_t cap) :
|
||||||
|
buffer(0),
|
||||||
|
capacity(0),
|
||||||
|
top(0),
|
||||||
|
high(0) {
|
||||||
|
resize(cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
~LinearAllocator() { dtFree(buffer); }
|
||||||
|
|
||||||
|
void resize(const size_t cap) {
|
||||||
|
if (buffer)
|
||||||
|
dtFree(buffer);
|
||||||
|
buffer = (unsigned char *)dtAlloc(cap, DT_ALLOC_PERM);
|
||||||
|
capacity = cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void reset() {
|
||||||
|
high = MAX(high, top);
|
||||||
|
top = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void *alloc(const size_t size) {
|
||||||
|
if (!buffer)
|
||||||
|
return 0;
|
||||||
|
if (top + size > capacity)
|
||||||
|
return 0;
|
||||||
|
unsigned char *mem = &buffer[top];
|
||||||
|
top += size;
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void free(void * /*ptr*/) {
|
||||||
|
// Empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NavMeshProcess : public dtTileCacheMeshProcess {
|
||||||
|
DetourNavigationMesh *nav;
|
||||||
|
inline explicit NavMeshProcess(DetourNavigationMesh *mesh) :
|
||||||
|
nav(mesh) {}
|
||||||
|
virtual void process(struct dtNavMeshCreateParams *params,
|
||||||
|
unsigned char *polyAreas, unsigned short *polyFlags) {
|
||||||
|
/* Add proper flags and offmesh connections here */
|
||||||
|
for (int i = 0; i < params->polyCount; i++) {
|
||||||
|
if (polyAreas[i] != RC_NULL_AREA)
|
||||||
|
polyFlags[i] = RC_WALKABLE_AREA;
|
||||||
|
}
|
||||||
|
params->offMeshConCount = nav->offmesh_radii.size();
|
||||||
|
if (params->offMeshConCount > 0) {
|
||||||
|
params->offMeshConVerts =
|
||||||
|
reinterpret_cast<const float *>(&nav->offmesh_vertices[0]);
|
||||||
|
params->offMeshConRad = &nav->offmesh_radii[0];
|
||||||
|
params->offMeshConFlags = &nav->offmesh_flags[0];
|
||||||
|
params->offMeshConAreas = &nav->offmesh_areas[0];
|
||||||
|
params->offMeshConDir = &nav->offmesh_dir[0];
|
||||||
|
print_line("added offmesh connection");
|
||||||
|
} else {
|
||||||
|
print_line("NO offmesh connection");
|
||||||
|
params->offMeshConVerts = NULL;
|
||||||
|
params->offMeshConRad = NULL;
|
||||||
|
params->offMeshConFlags = NULL;
|
||||||
|
params->offMeshConAreas = NULL;
|
||||||
|
params->offMeshConDir = NULL;
|
||||||
|
}
|
||||||
|
nav->clear_debug_mesh();
|
||||||
|
nav->get_debug_mesh();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DetourNavigationMesh::DetourNavigationMesh() :
|
||||||
|
Resource(),
|
||||||
|
navmesh(NULL),
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
tile_cache(0),
|
||||||
|
tile_cache_alloc(new LinearAllocator(64000)),
|
||||||
|
tile_cache_compressor(new FastLZCompressor),
|
||||||
|
mesh_process(new NavMeshProcess(this)),
|
||||||
|
#endif
|
||||||
|
group(""),
|
||||||
|
initialized(false),
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
max_obstacles(DEFAULT_MAX_OBSTACLES),
|
||||||
|
max_layers(DEFAULT_MAX_LAYERS),
|
||||||
|
#endif
|
||||||
|
tile_size(DEFAULT_TILE_SIZE),
|
||||||
|
cell_size(DEFAULT_CELL_SIZE),
|
||||||
|
cell_height(DEFAULT_CELL_HEIGHT),
|
||||||
|
agent_height(DEFAULT_AGENT_HEIGHT),
|
||||||
|
agent_radius(DEFAULT_AGENT_RADIUS),
|
||||||
|
agent_max_climb(DEFAULT_AGENT_MAX_CLIMB),
|
||||||
|
agent_max_slope(DEFAULT_AGENT_MAX_SLOPE),
|
||||||
|
region_min_size(DEFAULT_REGION_MIN_SIZE),
|
||||||
|
region_merge_size(DEFAULT_REGION_MERGE_SIZE),
|
||||||
|
edge_max_length(DEFAULT_EDGE_MAX_LENGTH),
|
||||||
|
edge_max_error(DEFAULT_EDGE_MAX_ERROR),
|
||||||
|
detail_sample_distance(DEFAULT_DETAIL_SAMPLE_DISTANCE),
|
||||||
|
detail_sample_max_error(DEFAULT_DETAIL_SAMPLE_MAX_ERROR),
|
||||||
|
bounding_box(AABB()),
|
||||||
|
padding(Vector3(1.0f, 1.0f, 1.0f)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DetourNavigationMesh::alloc_tile_cache() {
|
||||||
|
tile_cache = dtAllocTileCache();
|
||||||
|
if (!tile_cache) {
|
||||||
|
ERR_PRINT("Could not allocate tile cache");
|
||||||
|
release_navmesh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourNavigationMesh::release_navmesh() {
|
||||||
|
dtFreeNavMesh((dtNavMesh *)navmesh);
|
||||||
|
navmesh = NULL;
|
||||||
|
num_tiles_x = 0;
|
||||||
|
num_tiles_z = 0;
|
||||||
|
bounding_box = AABB();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourNavigationMesh::set_group(const String &group) {
|
||||||
|
this->group = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int DetourNavigationMesh::add_obstacle(const Vector3 &pos,
|
||||||
|
real_t radius, real_t height) {
|
||||||
|
/* Need to test how this works and why this needed at all */
|
||||||
|
/* TODO implement navmesh changes queue */
|
||||||
|
// while (tile_cache->isObstacleQueueFull())
|
||||||
|
// tile_cache->update(1, navMesh_);
|
||||||
|
dtObstacleRef ref = 0;
|
||||||
|
if (dtStatusFailed(
|
||||||
|
tile_cache->addObstacle(&pos.coord[0], radius, height, &ref))) {
|
||||||
|
ERR_PRINT("can't add obstacle");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (unsigned int)ref;
|
||||||
|
}
|
||||||
|
void DetourNavigationMesh::remove_obstacle(unsigned int id) {
|
||||||
|
/* Need to test how this works and why this needed at all */
|
||||||
|
/* TODO implement navmesh changes queue */
|
||||||
|
// while (tile_cache->isObstacleQueueFull())
|
||||||
|
// tile_cache->update(1, navMesh_);
|
||||||
|
if (dtStatusFailed(tile_cache->removeObstacle(id)))
|
||||||
|
ERR_PRINT("failed to remove obstacle");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DetourNavigationMesh::alloc() {
|
||||||
|
navmesh = dtAllocNavMesh();
|
||||||
|
return navmesh ? true : false;
|
||||||
|
}
|
||||||
|
bool DetourNavigationMesh::init(dtNavMeshParams *params) {
|
||||||
|
if (dtStatusFailed((navmesh)->init(params))) {
|
||||||
|
release_navmesh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
bool DetourNavigationMesh::init_tile_cache(dtTileCacheParams *params) {
|
||||||
|
if (dtStatusFailed(tile_cache->init(params, tile_cache_alloc,
|
||||||
|
tile_cache_compressor, mesh_process))) {
|
||||||
|
ERR_PRINT("Could not initialize tile cache");
|
||||||
|
release_navmesh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Ref<ArrayMesh> DetourNavigationMesh::get_debug_mesh() {
|
||||||
|
if (debug_mesh.is_valid())
|
||||||
|
return debug_mesh;
|
||||||
|
if (!navmesh)
|
||||||
|
return debug_mesh;
|
||||||
|
print_line("building debug navmesh");
|
||||||
|
List<Vector3> lines;
|
||||||
|
const dtNavMesh *navm = navmesh;
|
||||||
|
for (int i = 0; i < navm->getMaxTiles(); i++) {
|
||||||
|
const dtMeshTile *tile = navm->getTile(i);
|
||||||
|
if (!tile || !tile->header)
|
||||||
|
continue;
|
||||||
|
for (int j = 0; j < tile->header->polyCount; j++) {
|
||||||
|
dtPoly *poly = tile->polys + j;
|
||||||
|
if (poly->getType() != DT_POLYTYPE_OFFMESH_CONNECTION) {
|
||||||
|
for (int k = 0; k < poly->vertCount; k++) {
|
||||||
|
lines.push_back(*reinterpret_cast<const Vector3 *>(
|
||||||
|
&tile->verts[poly->verts[k] * 3]));
|
||||||
|
lines.push_back(*reinterpret_cast<const Vector3 *>(
|
||||||
|
&tile->verts[poly->verts[(k + 1) % poly->vertCount] * 3]));
|
||||||
|
}
|
||||||
|
} else if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) {
|
||||||
|
const dtOffMeshConnection *con =
|
||||||
|
&tile->offMeshCons[j - tile->header->offMeshBase];
|
||||||
|
const float *va = &tile->verts[poly->verts[0] * 3];
|
||||||
|
const float *vb = &tile->verts[poly->verts[1] * 3];
|
||||||
|
#if 0
|
||||||
|
/* TODO: implement offmesh debug proper */
|
||||||
|
bool startSet = false;
|
||||||
|
bool endSet = false;
|
||||||
|
for (unsigned int k = poly->firstLink; k != DT_NULL_LINK;
|
||||||
|
k = tile->links[k].next) {
|
||||||
|
if (tile->links[k].edge == 0)
|
||||||
|
startSet = true;
|
||||||
|
if (tile->links[k].edge == 1)
|
||||||
|
endSet = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Vector3 p0 = *reinterpret_cast<const Vector3 *>(va);
|
||||||
|
Vector3 p1 = *reinterpret_cast<const Vector3 *>(&con[0]);
|
||||||
|
Vector3 p2 = *reinterpret_cast<const Vector3 *>(&con[3]);
|
||||||
|
Vector3 p3 = *reinterpret_cast<const Vector3 *>(vb);
|
||||||
|
lines.push_back(p0);
|
||||||
|
lines.push_back(p1);
|
||||||
|
lines.push_back(p1);
|
||||||
|
lines.push_back(p2);
|
||||||
|
lines.push_back(p2);
|
||||||
|
lines.push_back(p3);
|
||||||
|
print_line("debug offmesh connection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_line("debug mesh lines: " + itos(lines.size()));
|
||||||
|
|
||||||
|
PoolVector<Vector3> varr;
|
||||||
|
varr.resize(lines.size());
|
||||||
|
PoolVector<Vector3>::Write w = varr.write();
|
||||||
|
int idx = 0;
|
||||||
|
for (List<Vector3>::Element *E = lines.front(); E; E = E->next()) {
|
||||||
|
w[idx++] = E->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
|
||||||
|
|
||||||
|
Array arr;
|
||||||
|
arr.resize(Mesh::ARRAY_MAX);
|
||||||
|
arr[Mesh::ARRAY_VERTEX] = varr;
|
||||||
|
|
||||||
|
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr);
|
||||||
|
|
||||||
|
return debug_mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourNavigationMesh::set_data(const Dictionary &p_value) {
|
||||||
|
dtNavMeshParams params;
|
||||||
|
Vector3 orig = p_value["orig"];
|
||||||
|
rcVcopy(params.orig, &orig.coord[0]);
|
||||||
|
params.tileWidth = p_value["tile_edge_length"];
|
||||||
|
params.tileHeight = p_value["tile_edge_length"];
|
||||||
|
params.maxTiles = p_value["max_tiles"];
|
||||||
|
params.maxPolys = p_value["max_polys"];
|
||||||
|
if (navmesh) {
|
||||||
|
if (initialized)
|
||||||
|
dtFreeNavMesh(navmesh);
|
||||||
|
else
|
||||||
|
dtFree(navmesh);
|
||||||
|
navmesh = NULL;
|
||||||
|
}
|
||||||
|
if (!alloc())
|
||||||
|
return;
|
||||||
|
if (!init(¶ms))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary DetourNavigationMesh::get_data() {
|
||||||
|
Dictionary t;
|
||||||
|
#if 0
|
||||||
|
t["initialized"] = initialized;
|
||||||
|
if (!initialized) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
const dtNavMeshParams *params = navmesh->getParams();
|
||||||
|
Vector3 orig;
|
||||||
|
rcVcopy(&orig.coord[0], params->orig);
|
||||||
|
t["orig"] = orig;
|
||||||
|
t["tile_edge_length"] = params->tileWidth;
|
||||||
|
t["max_tiles"] = params->maxTiles;
|
||||||
|
t["max_polys"] = params->maxPolys;
|
||||||
|
PoolVector<uint8_t> data;
|
||||||
|
PoolVector<uint8_t>::Write data_w = data.write();
|
||||||
|
const dtNavMesh *nm = navmesh;
|
||||||
|
int pos = 0;
|
||||||
|
for (int z = 0; z < num_tiles_z; z++)
|
||||||
|
for (int x = 0; x < num_tiles_x; x++) {
|
||||||
|
const dtMeshTile* tile = nm->getTileAt(x, z, 0);
|
||||||
|
if (!tile)
|
||||||
|
continue;
|
||||||
|
if (pos >= data.size())
|
||||||
|
data.resize(data.size() + sizeof(int) * 2 + sizeof(unsigned int) * 2 + tile->dataSize);
|
||||||
|
memcpy(&data_w[pos], &x, sizeof(x));
|
||||||
|
pos += sizeof(x);
|
||||||
|
memcpy(&data_w[pos], &z, sizeof(x));
|
||||||
|
pos += sizeof(z);
|
||||||
|
uint32_t tile_ref = (uint32_t)nm->getTileRef(tile);
|
||||||
|
memcpy(&data_w[pos], &tile_ref, sizeof(tile_ref));
|
||||||
|
pos += sizeof(tile_ref);
|
||||||
|
uint32_t data_size = (uint32_t)tile->dataSize;
|
||||||
|
memcpy(&data_w[pos], &data_size, sizeof(data_size));
|
||||||
|
pos += sizeof(data_size);
|
||||||
|
memcpy(&data_w[pos], tile->data, data_size);
|
||||||
|
pos += data_size;
|
||||||
|
}
|
||||||
|
print_line("submitted: " + itos(data.size()));
|
||||||
|
t["data"] = data;
|
||||||
|
#endif
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SETGET(v, t) \
|
||||||
|
ClassDB::bind_method(D_METHOD("set_" #v, #v), \
|
||||||
|
&DetourNavigationMesh::set_##v); \
|
||||||
|
ClassDB::bind_method(D_METHOD("get_" #v), &DetourNavigationMesh::get_##v); \
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::t, #v), "set_" #v, "get_" #v)
|
||||||
|
|
||||||
|
void DetourNavigationMesh::_bind_methods() {
|
||||||
|
SETGET(cell_size, REAL);
|
||||||
|
SETGET(cell_height, REAL);
|
||||||
|
SETGET(agent_height, REAL);
|
||||||
|
SETGET(agent_radius, REAL);
|
||||||
|
SETGET(agent_max_climb, REAL);
|
||||||
|
SETGET(agent_max_slope, REAL);
|
||||||
|
SETGET(region_min_size, REAL);
|
||||||
|
SETGET(region_merge_size, REAL);
|
||||||
|
SETGET(edge_max_length, REAL);
|
||||||
|
SETGET(edge_max_error, REAL);
|
||||||
|
SETGET(detail_sample_distance, REAL);
|
||||||
|
SETGET(detail_sample_max_error, REAL);
|
||||||
|
SETGET(group, STRING);
|
||||||
|
SETGET(padding, VECTOR3);
|
||||||
|
SETGET(tile_size, INT);
|
||||||
|
BIND_ENUM_CONSTANT(PARTITION_WATERSHED);
|
||||||
|
BIND_ENUM_CONSTANT(PARTITION_MONOTONE);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_partition_type", "type"),
|
||||||
|
&DetourNavigationMesh::set_partition_type);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_partition_type"),
|
||||||
|
&DetourNavigationMesh::get_partition_type);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_data", "data"),
|
||||||
|
&DetourNavigationMesh::set_data);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_data"), &DetourNavigationMesh::get_data);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "partition_type", PROPERTY_HINT_ENUM,
|
||||||
|
"watershed,monotone"),
|
||||||
|
"set_partition_type", "get_partition_type");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "",
|
||||||
|
PROPERTY_USAGE_STORAGE),
|
||||||
|
"set_data", "get_data");
|
||||||
|
}
|
||||||
|
#undef SETGET
|
||||||
|
|
||||||
|
void DetourNavigationMesh::get_tile_bounding_box(int x, int z, Vector3 &bmin,
|
||||||
|
Vector3 &bmax) {
|
||||||
|
const float tile_edge_length = (float)tile_size * cell_size;
|
||||||
|
bmin = bounding_box.position +
|
||||||
|
Vector3(tile_edge_length * (float)x, 0, tile_edge_length * (float)z);
|
||||||
|
bmax =
|
||||||
|
bmin + Vector3(tile_edge_length, bounding_box.size.y, tile_edge_length);
|
||||||
|
// print_line("tile bounding box: " +itos(x) + " " + itos(z) + ": " +
|
||||||
|
// String(bmin) + "/" + String(bmax));
|
||||||
|
// print_line("mesh bounding box: " + String(mesh->bounding_box));
|
||||||
|
}
|
||||||
|
bool DetourNavigationMesh::build_tile(const Transform &xform,
|
||||||
|
const Vector<Ref<Mesh> > &geometries,
|
||||||
|
const Vector<Transform> &xforms, int x,
|
||||||
|
int z) {
|
||||||
|
Vector3 bmin, bmax;
|
||||||
|
get_tile_bounding_box(x, z, bmin, bmax);
|
||||||
|
dtNavMesh *nav = get_navmesh();
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
dtTileCache *tile_cache = get_tile_cache();
|
||||||
|
tile_cache->removeTile(nav->getTileRefAt(x, z, 0), NULL, NULL);
|
||||||
|
#else
|
||||||
|
nav->removeTile(nav->getTileRefAt(x, z, 0), NULL, NULL);
|
||||||
|
#endif
|
||||||
|
rcConfig cfg;
|
||||||
|
cfg.cs = cell_size;
|
||||||
|
cfg.ch = cell_height;
|
||||||
|
cfg.walkableSlopeAngle = agent_max_slope;
|
||||||
|
cfg.walkableHeight = (int)ceil(agent_height / cfg.ch);
|
||||||
|
cfg.walkableClimb = (int)floor(agent_max_climb / cfg.ch);
|
||||||
|
cfg.walkableRadius = (int)ceil(agent_radius / cfg.cs);
|
||||||
|
cfg.maxEdgeLen = (int)(edge_max_length / cfg.cs);
|
||||||
|
cfg.maxSimplificationError = edge_max_error;
|
||||||
|
cfg.minRegionArea = (int)sqrtf(region_min_size);
|
||||||
|
cfg.mergeRegionArea = (int)sqrtf(region_merge_size);
|
||||||
|
cfg.maxVertsPerPoly = 6;
|
||||||
|
cfg.tileSize = tile_size;
|
||||||
|
cfg.borderSize = cfg.walkableRadius + 3;
|
||||||
|
cfg.width = cfg.tileSize + cfg.borderSize * 2;
|
||||||
|
cfg.height = cfg.tileSize + cfg.borderSize * 2;
|
||||||
|
cfg.detailSampleDist =
|
||||||
|
detail_sample_distance < 0.9f ? 0.0f : cell_size * detail_sample_distance;
|
||||||
|
cfg.detailSampleMaxError = cell_height * detail_sample_max_error;
|
||||||
|
rcVcopy(cfg.bmin, &bmin.coord[0]);
|
||||||
|
rcVcopy(cfg.bmax, &bmax.coord[0]);
|
||||||
|
cfg.bmin[0] -= cfg.borderSize * cfg.cs;
|
||||||
|
cfg.bmin[2] -= cfg.borderSize * cfg.cs;
|
||||||
|
cfg.bmax[0] += cfg.borderSize * cfg.cs;
|
||||||
|
cfg.bmax[2] += cfg.borderSize * cfg.cs;
|
||||||
|
|
||||||
|
AABB expbox(bmin, bmax - bmin);
|
||||||
|
expbox.position.x -= cfg.borderSize * cfg.cs;
|
||||||
|
expbox.position.z -= cfg.borderSize * cfg.cs;
|
||||||
|
expbox.size.x += 2.0 * cfg.borderSize * cfg.cs;
|
||||||
|
expbox.size.z += 2.0 * cfg.borderSize * cfg.cs;
|
||||||
|
Vector<float> points;
|
||||||
|
Vector<int> indices;
|
||||||
|
Transform base = xform.inverse();
|
||||||
|
for (int idx = 0; idx < geometries.size(); idx++) {
|
||||||
|
if (!geometries[idx].is_valid())
|
||||||
|
continue;
|
||||||
|
AABB mesh_aabb = geometries[idx]->get_aabb();
|
||||||
|
Transform mxform = base * xforms[idx];
|
||||||
|
mesh_aabb = mxform.xform(mesh_aabb);
|
||||||
|
if (!mesh_aabb.intersects_inclusive(expbox) &&
|
||||||
|
!expbox.encloses(mesh_aabb)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Add offmesh
|
||||||
|
// Add NavArea
|
||||||
|
// Add PhysicsBodies?
|
||||||
|
Ref<Mesh> mdata = geometries[idx];
|
||||||
|
// FIXME
|
||||||
|
add_meshdata(mdata, mxform, points, indices);
|
||||||
|
}
|
||||||
|
// print_line(String() + "points: " + itos(points.size()) + " indices: " +
|
||||||
|
// itos(indices.size()) + " tile_size: " + itos(mesh->tile_size));
|
||||||
|
#if 0
|
||||||
|
print_line("mesh points:");
|
||||||
|
for (int k = 0; k < points.size(); k += 3)
|
||||||
|
print_line("point: " + itos(k) + ": " + rtos(points[k]) + ", " + rtos(points[k + 1]) + ", " + rtos(points[k + 2]));
|
||||||
|
#endif
|
||||||
|
if (points.size() == 0 || indices.size() == 0)
|
||||||
|
/* Nothing to do */
|
||||||
|
return true;
|
||||||
|
rcHeightfield *heightfield = rcAllocHeightfield();
|
||||||
|
if (!heightfield) {
|
||||||
|
ERR_PRINT("Failed to allocate height field");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rcContext *ctx = new rcContext(true);
|
||||||
|
if (!rcCreateHeightfield(ctx, *heightfield, cfg.width, cfg.height, cfg.bmin,
|
||||||
|
cfg.bmax, cfg.cs, cfg.ch)) {
|
||||||
|
ERR_PRINT("Failed to create height field");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int ntris = indices.size() / 3;
|
||||||
|
Vector<unsigned char> tri_areas;
|
||||||
|
tri_areas.resize(ntris);
|
||||||
|
memset(&tri_areas.write[0], 0, ntris);
|
||||||
|
rcMarkWalkableTriangles(ctx, cfg.walkableSlopeAngle, &points[0],
|
||||||
|
points.size() / 3, &indices[0], ntris,
|
||||||
|
&tri_areas.write[0]);
|
||||||
|
rcRasterizeTriangles(ctx, &points[0], points.size() / 3, &indices[0],
|
||||||
|
&tri_areas[0], ntris, *heightfield, cfg.walkableClimb);
|
||||||
|
rcFilterLowHangingWalkableObstacles(ctx, cfg.walkableClimb, *heightfield);
|
||||||
|
|
||||||
|
rcFilterLedgeSpans(ctx, cfg.walkableHeight, cfg.walkableClimb, *heightfield);
|
||||||
|
rcFilterWalkableLowHeightSpans(ctx, cfg.walkableHeight, *heightfield);
|
||||||
|
|
||||||
|
rcCompactHeightfield *compact_heightfield = rcAllocCompactHeightfield();
|
||||||
|
if (!compact_heightfield) {
|
||||||
|
ERR_PRINT("Failed to allocate compact height field");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!rcBuildCompactHeightfield(ctx, cfg.walkableHeight, cfg.walkableClimb,
|
||||||
|
*heightfield, *compact_heightfield)) {
|
||||||
|
ERR_PRINT("Could not build compact height field");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!rcErodeWalkableArea(ctx, cfg.walkableRadius, *compact_heightfield)) {
|
||||||
|
ERR_PRINT("Could not erode walkable area");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement area storage in navmesh data and build from that data
|
||||||
|
// populate at collect_geometry stage
|
||||||
|
// areas should indicate if walkable
|
||||||
|
#if 0
|
||||||
|
for (unsigned int i = 0; i < nav_areas.size(); i++) {
|
||||||
|
Vector3 amin = nav_areas[i].bounds.position;
|
||||||
|
Vector3 amax = amin + nav_areas[i].bounds.size;
|
||||||
|
int id = nav_areas[i].id;
|
||||||
|
rcMarkBoxArea(ctx, &amin.coord[0], &amax.coord[0],
|
||||||
|
id, *compact_heightfield);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (partition_type == DetourNavigationMesh::PARTITION_WATERSHED) {
|
||||||
|
if (!rcBuildDistanceField(ctx, *compact_heightfield))
|
||||||
|
return false;
|
||||||
|
if (!rcBuildRegions(ctx, *compact_heightfield, cfg.borderSize,
|
||||||
|
cfg.minRegionArea, cfg.mergeRegionArea))
|
||||||
|
return false;
|
||||||
|
} else if (!rcBuildRegionsMonotone(ctx, *compact_heightfield, cfg.borderSize,
|
||||||
|
cfg.minRegionArea, cfg.mergeRegionArea))
|
||||||
|
return false;
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
rcHeightfieldLayerSet *heightfield_layer_set = rcAllocHeightfieldLayerSet();
|
||||||
|
if (!heightfield_layer_set) {
|
||||||
|
ERR_PRINT("Could not allocate height field layer set");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!rcBuildHeightfieldLayers(ctx, *compact_heightfield, cfg.borderSize,
|
||||||
|
cfg.walkableHeight, *heightfield_layer_set)) {
|
||||||
|
ERR_PRINT("Could not build heightfield layers");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < heightfield_layer_set->nlayers; i++) {
|
||||||
|
dtTileCacheLayerHeader header;
|
||||||
|
header.magic = DT_TILECACHE_MAGIC;
|
||||||
|
header.version = DT_TILECACHE_VERSION;
|
||||||
|
header.tx = x;
|
||||||
|
header.ty = z;
|
||||||
|
header.tlayer = i;
|
||||||
|
rcHeightfieldLayer *layer = &heightfield_layer_set->layers[i];
|
||||||
|
rcVcopy(header.bmin, layer->bmin);
|
||||||
|
rcVcopy(header.bmax, layer->bmax);
|
||||||
|
header.width = (unsigned char)layer->width;
|
||||||
|
header.height = (unsigned char)layer->height;
|
||||||
|
header.minx = (unsigned char)layer->minx;
|
||||||
|
header.maxx = (unsigned char)layer->maxx;
|
||||||
|
header.miny = (unsigned char)layer->miny;
|
||||||
|
header.maxy = (unsigned char)layer->maxy;
|
||||||
|
header.hmin = (unsigned short)layer->hmin;
|
||||||
|
header.hmax = (unsigned short)layer->hmax;
|
||||||
|
unsigned char *tile_data;
|
||||||
|
int tile_data_size;
|
||||||
|
if (dtStatusFailed(dtBuildTileCacheLayer(
|
||||||
|
get_tile_cache_compressor(), &header, layer->heights, layer->areas,
|
||||||
|
layer->cons, &tile_data, &tile_data_size))) {
|
||||||
|
ERR_PRINT("Failed to build tile cache layers");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
dtCompressedTileRef tileRef;
|
||||||
|
int status = tile_cache->addTile(tile_data, tile_data_size,
|
||||||
|
DT_COMPRESSEDTILE_FREE_DATA, &tileRef);
|
||||||
|
if (dtStatusFailed((dtStatus)status)) {
|
||||||
|
dtFree(tile_data);
|
||||||
|
tile_data = NULL;
|
||||||
|
}
|
||||||
|
tile_cache->buildNavMeshTilesAt(x, z, nav);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
rcContourSet *contour_set = rcAllocContourSet();
|
||||||
|
if (!contour_set)
|
||||||
|
return false;
|
||||||
|
print_line("allocated contour set");
|
||||||
|
if (!rcBuildContours(ctx, *compact_heightfield, cfg.maxSimplificationError,
|
||||||
|
cfg.maxEdgeLen, *contour_set))
|
||||||
|
return false;
|
||||||
|
print_line("created contour set");
|
||||||
|
rcPolyMesh *poly_mesh = rcAllocPolyMesh();
|
||||||
|
if (!poly_mesh)
|
||||||
|
return false;
|
||||||
|
print_line("allocated polymesh");
|
||||||
|
if (!rcBuildPolyMesh(ctx, *contour_set, cfg.maxVertsPerPoly, *poly_mesh))
|
||||||
|
return false;
|
||||||
|
print_line("created polymesh");
|
||||||
|
rcPolyMeshDetail *poly_mesh_detail = rcAllocPolyMeshDetail();
|
||||||
|
if (!poly_mesh_detail)
|
||||||
|
return false;
|
||||||
|
print_line("allocated polymesh detail");
|
||||||
|
if (!rcBuildPolyMeshDetail(ctx, *poly_mesh, *compact_heightfield,
|
||||||
|
cfg.detailSampleDist, cfg.detailSampleMaxError,
|
||||||
|
*poly_mesh_detail))
|
||||||
|
return false;
|
||||||
|
print_line("created polymesh detail");
|
||||||
|
/* Assign area flags TODO: use nav area assignment here */
|
||||||
|
for (int i = 0; i < poly_mesh->npolys; i++) {
|
||||||
|
if (poly_mesh->areas[i] != RC_NULL_AREA)
|
||||||
|
poly_mesh->flags[i] = 0x1;
|
||||||
|
}
|
||||||
|
print_line("created area flags");
|
||||||
|
unsigned char *nav_data = NULL;
|
||||||
|
int nav_data_size = 0;
|
||||||
|
dtNavMeshCreateParams params;
|
||||||
|
memset(¶ms, 0, sizeof params);
|
||||||
|
params.verts = poly_mesh->verts;
|
||||||
|
params.vertCount = poly_mesh->nverts;
|
||||||
|
params.polys = poly_mesh->polys;
|
||||||
|
params.polyAreas = poly_mesh->areas;
|
||||||
|
params.polyFlags = poly_mesh->flags;
|
||||||
|
params.polyCount = poly_mesh->npolys;
|
||||||
|
params.nvp = poly_mesh->nvp;
|
||||||
|
params.detailMeshes = poly_mesh_detail->meshes;
|
||||||
|
params.detailVerts = poly_mesh_detail->verts;
|
||||||
|
params.detailVertsCount = poly_mesh_detail->nverts;
|
||||||
|
params.detailTris = poly_mesh_detail->tris;
|
||||||
|
params.detailTriCount = poly_mesh_detail->ntris;
|
||||||
|
params.walkableHeight = mesh->agent_height;
|
||||||
|
params.walkableRadius = mesh->agent_radius;
|
||||||
|
params.walkableClimb = mesh->agent_max_climb;
|
||||||
|
params.tileX = x;
|
||||||
|
params.tileY = z;
|
||||||
|
rcVcopy(params.bmin, poly_mesh->bmin);
|
||||||
|
rcVcopy(params.bmax, poly_mesh->bmax);
|
||||||
|
params.cs = cfg.cs;
|
||||||
|
params.ch = cfg.ch;
|
||||||
|
params.buildBvTree = true;
|
||||||
|
#if 0
|
||||||
|
// building offmesh conections
|
||||||
|
if (build.offMeshRadii_.Size())
|
||||||
|
{
|
||||||
|
params.offMeshConCount = build.offMeshRadii_.Size();
|
||||||
|
params.offMeshConVerts = &build.offMeshVertices_[0].x_;
|
||||||
|
params.offMeshConRad = &build.offMeshRadii_[0];
|
||||||
|
params.offMeshConFlags = &build.offMeshFlags_[0];
|
||||||
|
params.offMeshConAreas = &build.offMeshAreas_[0];
|
||||||
|
params.offMeshConDir = &build.offMeshDir_[0];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
print_line("setup offmesh connections");
|
||||||
|
|
||||||
|
if (!dtCreateNavMeshData(¶ms, &nav_data, &nav_data_size))
|
||||||
|
return false;
|
||||||
|
if (dtStatusFailed(mesh->get_navmesh()->addTile(
|
||||||
|
nav_data, nav_data_size, DT_TILE_FREE_DATA, 0, NULL))) {
|
||||||
|
dtFree(nav_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
print_line("created navmesh data");
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourNavigationMesh::add_meshdata(const Ref<Mesh> &p_mesh,
|
||||||
|
const Transform &p_xform,
|
||||||
|
Vector<float> &p_verticies,
|
||||||
|
Vector<int> &p_indices) {
|
||||||
|
int current_vertex_count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
|
||||||
|
current_vertex_count = p_verticies.size() / 3;
|
||||||
|
|
||||||
|
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int index_count = 0;
|
||||||
|
if (p_mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
|
||||||
|
index_count = p_mesh->surface_get_array_index_len(i);
|
||||||
|
} else {
|
||||||
|
index_count = p_mesh->surface_get_array_len(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_CONTINUE((index_count == 0 || (index_count % 3) != 0));
|
||||||
|
|
||||||
|
int face_count = index_count / 3;
|
||||||
|
|
||||||
|
Array a = p_mesh->surface_get_arrays(i);
|
||||||
|
|
||||||
|
PoolVector<Vector3> mesh_vertices = a[Mesh::ARRAY_VERTEX];
|
||||||
|
PoolVector<Vector3>::Read vr = mesh_vertices.read();
|
||||||
|
|
||||||
|
if (p_mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
|
||||||
|
|
||||||
|
PoolVector<int> mesh_indices = a[Mesh::ARRAY_INDEX];
|
||||||
|
PoolVector<int>::Read ir = mesh_indices.read();
|
||||||
|
|
||||||
|
for (int i = 0; i < mesh_vertices.size(); i++) {
|
||||||
|
Vector3 p_vec3 = p_xform.xform(vr[i]);
|
||||||
|
p_verticies.push_back(p_vec3.x);
|
||||||
|
p_verticies.push_back(p_vec3.y);
|
||||||
|
p_verticies.push_back(p_vec3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < face_count; i++) {
|
||||||
|
// CCW
|
||||||
|
p_indices.push_back(current_vertex_count + (ir[i * 3 + 0]));
|
||||||
|
p_indices.push_back(current_vertex_count + (ir[i * 3 + 2]));
|
||||||
|
p_indices.push_back(current_vertex_count + (ir[i * 3 + 1]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
face_count = mesh_vertices.size() / 3;
|
||||||
|
for (int i = 0; i < face_count; i++) {
|
||||||
|
Vector3 p_vec3 = p_xform.xform(vr[i * 3 + 0]);
|
||||||
|
p_verticies.push_back(p_vec3.x);
|
||||||
|
p_verticies.push_back(p_vec3.y);
|
||||||
|
p_verticies.push_back(p_vec3.z);
|
||||||
|
p_vec3 = p_xform.xform(vr[i * 3 + 2]);
|
||||||
|
p_verticies.push_back(p_vec3.x);
|
||||||
|
p_verticies.push_back(p_vec3.y);
|
||||||
|
p_verticies.push_back(p_vec3.z);
|
||||||
|
p_vec3 = p_xform.xform(vr[i * 3 + 1]);
|
||||||
|
p_verticies.push_back(p_vec3.x);
|
||||||
|
p_verticies.push_back(p_vec3.y);
|
||||||
|
p_verticies.push_back(p_vec3.z);
|
||||||
|
|
||||||
|
p_indices.push_back(current_vertex_count + (i * 3 + 0));
|
||||||
|
p_indices.push_back(current_vertex_count + (i * 3 + 1));
|
||||||
|
p_indices.push_back(current_vertex_count + (i * 3 + 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourNavigationMesh::remove_tile(int x, int z) {
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
dtTileCache *tile_cache = get_tile_cache();
|
||||||
|
tile_cache->removeTile(navmesh->getTileRefAt(x, z, 0), NULL, NULL);
|
||||||
|
#else
|
||||||
|
nav->removeTile(navmesh->getTileRefAt(x, z, 0), NULL, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int DetourNavigationMesh::build_tiles(
|
||||||
|
const Transform &xform, const Vector<Ref<Mesh> > &geometries,
|
||||||
|
const Vector<Transform> &xforms, int x1, int z1, int x2, int z2) {
|
||||||
|
unsigned ret = 0;
|
||||||
|
for (int z = z1; z <= z2; z++) {
|
||||||
|
for (int x = x1; x <= x2; x++) {
|
||||||
|
if (build_tile(xform, geometries, xforms, x, z))
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
get_tile_cache()->update(0, get_navmesh());
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
180
modules/detour/detour-navmesh.h
Normal file
180
modules/detour/detour-navmesh.h
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* detour-navmesh.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
#ifndef DETOUR_NAVMESH_H
|
||||||
|
#define DETOUR_NAVMESH_H
|
||||||
|
#include "core/resource.h"
|
||||||
|
#include "scene/resources/mesh.h"
|
||||||
|
#define SETGET(x, t) \
|
||||||
|
t x; \
|
||||||
|
void set_##x(t v) { x = v; } \
|
||||||
|
t get_##x() { return x; }
|
||||||
|
class dtNavMesh;
|
||||||
|
class dtTileCache;
|
||||||
|
struct dtTileCacheAlloc;
|
||||||
|
struct dtNavMeshParams;
|
||||||
|
struct dtTileCacheCompressor;
|
||||||
|
struct dtTileCacheMeshProcess;
|
||||||
|
struct dtTileCacheParams;
|
||||||
|
class DetourNavigationMesh : public Resource {
|
||||||
|
GDCLASS(DetourNavigationMesh, Resource);
|
||||||
|
dtNavMesh *navmesh;
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
dtTileCache *tile_cache;
|
||||||
|
dtTileCacheAlloc *tile_cache_alloc;
|
||||||
|
dtTileCacheCompressor *tile_cache_compressor;
|
||||||
|
dtTileCacheMeshProcess *mesh_process;
|
||||||
|
#endif
|
||||||
|
String group;
|
||||||
|
bool initialized;
|
||||||
|
static void _bind_methods();
|
||||||
|
Ref<ArrayMesh> debug_mesh;
|
||||||
|
Vector<int> tile_queue;
|
||||||
|
Vector<Vector3> offmesh_vertices;
|
||||||
|
Vector<float> offmesh_radii;
|
||||||
|
Vector<unsigned short> offmesh_flags;
|
||||||
|
Vector<unsigned char> offmesh_areas;
|
||||||
|
Vector<unsigned char> offmesh_dir;
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
friend struct NavMeshProcess;
|
||||||
|
#endif
|
||||||
|
protected:
|
||||||
|
void release_navmesh();
|
||||||
|
int num_tiles_x;
|
||||||
|
int num_tiles_z;
|
||||||
|
void get_tile_bounding_box(int x, int z, Vector3 &bmin, Vector3 &bmax);
|
||||||
|
|
||||||
|
public:
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
int max_obstacles;
|
||||||
|
int max_layers;
|
||||||
|
#endif
|
||||||
|
enum partition_t {
|
||||||
|
PARTITION_WATERSHED,
|
||||||
|
PARTITION_MONOTONE,
|
||||||
|
};
|
||||||
|
void set_num_tiles(int gridW, int gridH) {
|
||||||
|
num_tiles_x = (gridW + tile_size - 1) / tile_size;
|
||||||
|
num_tiles_z = (gridH + tile_size - 1) / tile_size;
|
||||||
|
}
|
||||||
|
int get_num_tiles_x() {
|
||||||
|
return num_tiles_x;
|
||||||
|
}
|
||||||
|
int get_num_tiles_z() {
|
||||||
|
return num_tiles_z;
|
||||||
|
}
|
||||||
|
SETGET(partition_type, int)
|
||||||
|
SETGET(tile_size, int)
|
||||||
|
SETGET(cell_size, real_t)
|
||||||
|
SETGET(cell_height, real_t)
|
||||||
|
// real_t cell_height;
|
||||||
|
SETGET(agent_height, real_t)
|
||||||
|
// real_t agent_height;
|
||||||
|
SETGET(agent_radius, real_t)
|
||||||
|
// real_t agent_radius;
|
||||||
|
SETGET(agent_max_climb, real_t)
|
||||||
|
// real_t agent_max_climb;
|
||||||
|
SETGET(agent_max_slope, real_t)
|
||||||
|
// real_t agent_max_slope;
|
||||||
|
SETGET(region_min_size, real_t)
|
||||||
|
// real_t region_min_size;
|
||||||
|
SETGET(region_merge_size, real_t)
|
||||||
|
// real_t region_merge_size;
|
||||||
|
SETGET(edge_max_length, real_t)
|
||||||
|
// real_t edge_max_length;
|
||||||
|
SETGET(edge_max_error, real_t)
|
||||||
|
// real_t edge_max_error;
|
||||||
|
SETGET(detail_sample_distance, real_t)
|
||||||
|
// real_t detail_sample_distance;
|
||||||
|
SETGET(detail_sample_max_error, real_t)
|
||||||
|
// real_t detail_sample_max_error;
|
||||||
|
AABB bounding_box;
|
||||||
|
SETGET(padding, Vector3)
|
||||||
|
// Vector3 padding;
|
||||||
|
void set_group(const String &group);
|
||||||
|
bool alloc();
|
||||||
|
bool init(dtNavMeshParams *params);
|
||||||
|
void set_data(const Dictionary &p_value);
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
bool alloc_tile_cache();
|
||||||
|
bool init_tile_cache(dtTileCacheParams *param);
|
||||||
|
#endif
|
||||||
|
Dictionary get_data();
|
||||||
|
Ref<ArrayMesh> get_debug_mesh();
|
||||||
|
void clear_debug_mesh() {
|
||||||
|
debug_mesh.unref();
|
||||||
|
}
|
||||||
|
const String &get_group() const {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
dtNavMesh *get_navmesh() {
|
||||||
|
return navmesh;
|
||||||
|
}
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
dtTileCache *get_tile_cache() {
|
||||||
|
return tile_cache;
|
||||||
|
}
|
||||||
|
dtTileCacheCompressor *get_tile_cache_compressor() {
|
||||||
|
return tile_cache_compressor;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
inline void add_offmesh_connection(Vector3 start, Vector3 end, real_t radius,
|
||||||
|
unsigned short flags, unsigned char area, bool bidirectional = false) {
|
||||||
|
offmesh_vertices.push_back(start);
|
||||||
|
offmesh_vertices.push_back(end);
|
||||||
|
offmesh_radii.push_back(radius);
|
||||||
|
offmesh_flags.push_back(flags);
|
||||||
|
offmesh_areas.push_back(area);
|
||||||
|
offmesh_dir.push_back(bidirectional ? 1 /* DT_OFFMESH_CON_BIDIR */ : 0);
|
||||||
|
}
|
||||||
|
void clear_offmesh_connections() {
|
||||||
|
offmesh_vertices.clear();
|
||||||
|
offmesh_radii.clear();
|
||||||
|
offmesh_flags.clear();
|
||||||
|
offmesh_areas.clear();
|
||||||
|
offmesh_dir.clear();
|
||||||
|
}
|
||||||
|
void add_meshdata(const Ref<Mesh> &p_mesh,
|
||||||
|
const Transform &p_xform,
|
||||||
|
Vector<float> &p_verticies,
|
||||||
|
Vector<int> &p_indices);
|
||||||
|
unsigned int build_tiles(const Transform &xform, const Vector<Ref<Mesh> > &geometries, const Vector<Transform> &xforms, int x1, int y1, int x2, int y2);
|
||||||
|
inline real_t get_tile_edge_length() const {
|
||||||
|
return ((real_t)tile_size * cell_size);
|
||||||
|
}
|
||||||
|
bool build_tile(const Transform &xform, const Vector<Ref<Mesh> > &geometries, const Vector<Transform> &xforms, int x, int z);
|
||||||
|
void remove_tile(int x, int z);
|
||||||
|
unsigned int add_obstacle(const Vector3 &pos, real_t radius, real_t height);
|
||||||
|
void remove_obstacle(unsigned int id);
|
||||||
|
DetourNavigationMesh();
|
||||||
|
};
|
||||||
|
#undef SETGET
|
||||||
|
VARIANT_ENUM_CAST(DetourNavigationMesh::partition_t);
|
||||||
|
|
||||||
|
#endif
|
||||||
BIN
modules/detour/detour-navmesh.x11.opt.tools.64.o
Normal file
BIN
modules/detour/detour-navmesh.x11.opt.tools.64.o
Normal file
Binary file not shown.
262
modules/detour/detour.cpp
Normal file
262
modules/detour/detour.cpp
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
#include "detour.h"
|
||||||
|
#include "modules/csg/csg_shape.h"
|
||||||
|
#include "obstacle.h"
|
||||||
|
#include "scene/3d/mesh_instance.h"
|
||||||
|
#include <DetourNavMesh.h>
|
||||||
|
#include <DetourNavMeshBuilder.h>
|
||||||
|
#include <DetourNavMeshQuery.h>
|
||||||
|
#include <DetourTileCache.h>
|
||||||
|
#include <DetourTileCacheBuilder.h>
|
||||||
|
#include <Recast.h>
|
||||||
|
|
||||||
|
inline unsigned int nextPow2(unsigned int v) {
|
||||||
|
v--;
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
v++;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int ilog2(unsigned int v) {
|
||||||
|
unsigned int r;
|
||||||
|
unsigned int shift;
|
||||||
|
r = (v > 0xffff) << 4;
|
||||||
|
v >>= r;
|
||||||
|
shift = (v > 0xff) << 3;
|
||||||
|
v >>= shift;
|
||||||
|
r |= shift;
|
||||||
|
shift = (v > 0xf) << 2;
|
||||||
|
v >>= shift;
|
||||||
|
r |= shift;
|
||||||
|
shift = (v > 0x3) << 1;
|
||||||
|
v >>= shift;
|
||||||
|
r |= shift;
|
||||||
|
r |= (v >> 1);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetourNavigationMeshInstance::build() {
|
||||||
|
if (geometries.size() == 0)
|
||||||
|
return;
|
||||||
|
if (!mesh.is_valid())
|
||||||
|
return;
|
||||||
|
print_line("Building");
|
||||||
|
for (int i = 0; i < geometries.size(); i++)
|
||||||
|
if (geometries[i].is_valid()) {
|
||||||
|
AABB convbox = geometries[i]->get_aabb();
|
||||||
|
convbox = xforms[i].xform(convbox);
|
||||||
|
mesh->bounding_box.merge_with(convbox);
|
||||||
|
}
|
||||||
|
print_line("mesh bb: " + String(mesh->bounding_box));
|
||||||
|
mesh->bounding_box.position -= mesh->padding;
|
||||||
|
mesh->bounding_box.size += mesh->padding * 2.0;
|
||||||
|
int gridH = 0, gridW = 0;
|
||||||
|
float tile_edge_length = mesh->get_tile_edge_length();
|
||||||
|
Vector3 bmin = mesh->bounding_box.position;
|
||||||
|
Vector3 bmax = mesh->bounding_box.position + mesh->bounding_box.size;
|
||||||
|
rcCalcGridSize(&bmin.coord[0], &bmax.coord[0], mesh->cell_size, &gridW,
|
||||||
|
&gridH);
|
||||||
|
mesh->set_num_tiles(gridW, gridH);
|
||||||
|
print_line(String() + "tiles x: " + itos(mesh->get_num_tiles_x()) +
|
||||||
|
" tiles z: " + itos(mesh->get_num_tiles_z()));
|
||||||
|
unsigned int tile_bits = (unsigned int)ilog2(
|
||||||
|
nextPow2(mesh->get_num_tiles_x() * mesh->get_num_tiles_z()));
|
||||||
|
if (tile_bits > 14)
|
||||||
|
tile_bits = 14;
|
||||||
|
unsigned int poly_bits = 22 - tile_bits;
|
||||||
|
unsigned int max_tiles = 1u << tile_bits;
|
||||||
|
unsigned int max_polys = 1 << poly_bits;
|
||||||
|
dtNavMeshParams params;
|
||||||
|
rcVcopy(params.orig, &bmin.coord[0]);
|
||||||
|
params.tileWidth = tile_edge_length;
|
||||||
|
params.tileHeight = tile_edge_length;
|
||||||
|
params.maxTiles = max_tiles;
|
||||||
|
params.maxPolys = max_polys;
|
||||||
|
if (!mesh->alloc())
|
||||||
|
return;
|
||||||
|
if (!mesh->init(¶ms))
|
||||||
|
return;
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
dtTileCacheParams tile_cache_params;
|
||||||
|
memset(&tile_cache_params, 0, sizeof(tile_cache_params));
|
||||||
|
rcVcopy(tile_cache_params.orig, &bmin.coord[0]);
|
||||||
|
tile_cache_params.ch = mesh->cell_height;
|
||||||
|
tile_cache_params.cs = mesh->cell_size;
|
||||||
|
tile_cache_params.width = mesh->tile_size;
|
||||||
|
tile_cache_params.height = mesh->tile_size;
|
||||||
|
tile_cache_params.maxSimplificationError = mesh->edge_max_error;
|
||||||
|
tile_cache_params.maxTiles =
|
||||||
|
mesh->get_num_tiles_x() * mesh->get_num_tiles_z() * mesh->max_layers;
|
||||||
|
tile_cache_params.maxObstacles = mesh->max_obstacles;
|
||||||
|
tile_cache_params.walkableClimb = mesh->agent_max_climb;
|
||||||
|
tile_cache_params.walkableHeight = mesh->agent_height;
|
||||||
|
tile_cache_params.walkableRadius = mesh->agent_radius;
|
||||||
|
if (!mesh->alloc_tile_cache())
|
||||||
|
return;
|
||||||
|
if (!mesh->init_tile_cache(&tile_cache_params))
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
Transform xform = get_global_transform();
|
||||||
|
unsigned int result = mesh->build_tiles(xform, geometries, xforms, 0, 0,
|
||||||
|
mesh->get_num_tiles_x() - 1,
|
||||||
|
mesh->get_num_tiles_z() - 1);
|
||||||
|
print_line(String() + "built tiles: " + itos(result));
|
||||||
|
print_line("mesh final bb: " + String(mesh->bounding_box));
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
for (int i = 0; i < obstacles.size(); i++) {
|
||||||
|
DetourNavigationObstacle *obstacle = obstacles[i];
|
||||||
|
/* TODO: Fix transforms */
|
||||||
|
unsigned int id =
|
||||||
|
mesh->add_obstacle(obstacle->get_global_transform().origin,
|
||||||
|
obstacle->get_radius(), obstacle->get_height());
|
||||||
|
obstacle->id = id;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (debug_view && mesh.is_valid()) {
|
||||||
|
print_line("rebuilding debug navmesh");
|
||||||
|
mesh->clear_debug_mesh();
|
||||||
|
Object::cast_to<MeshInstance>(debug_view)->set_mesh(mesh->get_debug_mesh());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/* More complicated queries follow */
|
||||||
|
|
||||||
|
DetourNavigationMeshInstance::DetourNavigationMeshInstance() :
|
||||||
|
Spatial(),
|
||||||
|
mesh(0),
|
||||||
|
debug_view(0) {}
|
||||||
|
|
||||||
|
void DetourNavigation::_bind_methods() {}
|
||||||
|
void DetourNavigationArea::_bind_methods() {}
|
||||||
|
void DetourNavigationOffmeshConnection::_bind_methods() {}
|
||||||
|
void DetourNavigationMeshInstance::collect_geometries(bool recursive) {
|
||||||
|
if (!mesh.is_valid()) {
|
||||||
|
print_line("No valid navmesh set, please set valid navmesh resource");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Node *> groupNodes;
|
||||||
|
Set<Node *> processedNodes;
|
||||||
|
List<Node *> node_queue;
|
||||||
|
geometries.clear();
|
||||||
|
get_tree()->get_nodes_in_group(mesh->get_group(), &groupNodes);
|
||||||
|
for (const List<Node *>::Element *E = groupNodes.front(); E; E = E->next()) {
|
||||||
|
Node *groupNode = E->get();
|
||||||
|
node_queue.push_back(groupNode);
|
||||||
|
}
|
||||||
|
print_line(String() + "node_queue size: " + itos(node_queue.size()));
|
||||||
|
while (node_queue.size() > 0) {
|
||||||
|
Node *groupNode = node_queue.front()->get();
|
||||||
|
node_queue.pop_front();
|
||||||
|
if (Object::cast_to<MeshInstance>(groupNode)) {
|
||||||
|
MeshInstance *mi = Object::cast_to<MeshInstance>(groupNode);
|
||||||
|
Ref<Mesh> mesh = mi->get_mesh();
|
||||||
|
Transform xform = mi->get_global_transform();
|
||||||
|
if (mesh.is_valid())
|
||||||
|
add_mesh(mesh, xform);
|
||||||
|
} else if (Object::cast_to<CSGShape>(groupNode)) {
|
||||||
|
CSGShape *shape = Object::cast_to<CSGShape>(groupNode);
|
||||||
|
Ref<ArrayMesh> mesh(memnew(ArrayMesh));
|
||||||
|
Array arrays;
|
||||||
|
arrays.resize(Mesh::ARRAY_MAX);
|
||||||
|
PoolVector<Vector3> faces = shape->get_brush_faces();
|
||||||
|
arrays[ArrayMesh::ARRAY_VERTEX] = faces;
|
||||||
|
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
|
||||||
|
|
||||||
|
Transform xform = shape->get_global_transform();
|
||||||
|
if (mesh.is_valid())
|
||||||
|
add_mesh(mesh, xform);
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
} else if (Object::cast_to<DetourNavigationObstacle>(groupNode)) {
|
||||||
|
DetourNavigationObstacle *obstacle =
|
||||||
|
Object::cast_to<DetourNavigationObstacle>(groupNode);
|
||||||
|
obstacles.push_back(obstacle);
|
||||||
|
#endif
|
||||||
|
} else if (Object::cast_to<DetourNavigationOffmeshConnection>(groupNode)) {
|
||||||
|
DetourNavigationOffmeshConnection *offcon =
|
||||||
|
Object::cast_to<DetourNavigationOffmeshConnection>(groupNode);
|
||||||
|
Transform xform = offcon->get_global_transform();
|
||||||
|
Transform base = get_global_transform().inverse();
|
||||||
|
Vector3 start = (base * xform).xform(Vector3());
|
||||||
|
Vector3 end = (base * xform).xform(offcon->end);
|
||||||
|
mesh->add_offmesh_connection(start, end, offcon->radius, offcon->flags,
|
||||||
|
offcon->area, offcon->bidirectional);
|
||||||
|
}
|
||||||
|
if (recursive)
|
||||||
|
for (int i = 0; i < groupNode->get_child_count(); i++)
|
||||||
|
node_queue.push_back(groupNode->get_child(i));
|
||||||
|
}
|
||||||
|
print_line(String() + "geometries size: " + itos(geometries.size()));
|
||||||
|
}
|
||||||
|
void DetourNavigationMeshInstance::add_mesh(const Ref<Mesh> &mesh,
|
||||||
|
const Transform &xform) {
|
||||||
|
geometries.push_back(mesh);
|
||||||
|
xforms.push_back(xform);
|
||||||
|
}
|
||||||
|
void DetourNavigationMeshInstance::_notification(int p_what) {
|
||||||
|
|
||||||
|
switch (p_what) {
|
||||||
|
case NOTIFICATION_ENTER_TREE: {
|
||||||
|
if (get_tree()->is_debugging_navigation_hint()) {
|
||||||
|
MeshInstance *dm = memnew(MeshInstance);
|
||||||
|
if (mesh.is_valid())
|
||||||
|
dm->set_mesh(mesh->get_debug_mesh());
|
||||||
|
dm->set_material_override(get_tree()->get_debug_navigation_material());
|
||||||
|
add_child(dm);
|
||||||
|
debug_view = dm;
|
||||||
|
}
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
set_process(true);
|
||||||
|
#endif
|
||||||
|
} break;
|
||||||
|
case NOTIFICATION_EXIT_TREE: {
|
||||||
|
if (debug_view) {
|
||||||
|
debug_view->queue_delete();
|
||||||
|
debug_view = NULL;
|
||||||
|
}
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
set_process(false);
|
||||||
|
#endif
|
||||||
|
} break;
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
case NOTIFICATION_PROCESS: {
|
||||||
|
float delta = get_process_delta_time();
|
||||||
|
if (mesh.is_valid()) {
|
||||||
|
dtTileCache *tile_cache = mesh->get_tile_cache();
|
||||||
|
if (tile_cache) {
|
||||||
|
tile_cache->update(delta, mesh->get_navmesh());
|
||||||
|
if (debug_view)
|
||||||
|
Object::cast_to<MeshInstance>(debug_view)
|
||||||
|
->set_mesh(mesh->get_debug_mesh());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DetourNavigationMeshInstance::set_navmesh(
|
||||||
|
const Ref<DetourNavigationMesh> &mesh) {
|
||||||
|
if (this->mesh != mesh) {
|
||||||
|
this->mesh = mesh;
|
||||||
|
if (debug_view && this->mesh.is_valid())
|
||||||
|
Object::cast_to<MeshInstance>(debug_view)
|
||||||
|
->set_mesh(this->mesh->get_debug_mesh());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DetourNavigationMeshInstance::_bind_methods() {
|
||||||
|
/* Navmesh */
|
||||||
|
ClassDB::bind_method(D_METHOD("build"), &DetourNavigationMeshInstance::build);
|
||||||
|
ClassDB::bind_method(D_METHOD("collect_geometries", "recursive"),
|
||||||
|
&DetourNavigationMeshInstance::collect_geometries);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_navmesh", "navmesh"),
|
||||||
|
&DetourNavigationMeshInstance::set_navmesh);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_navmesh"),
|
||||||
|
&DetourNavigationMeshInstance::get_navmesh);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh",
|
||||||
|
PROPERTY_HINT_RESOURCE_TYPE,
|
||||||
|
"DetourNavigationMesh"),
|
||||||
|
"set_navmesh", "get_navmesh");
|
||||||
|
}
|
||||||
|
#undef SETGET
|
||||||
127
modules/detour/detour.h
Normal file
127
modules/detour/detour.h
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* detour.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
#ifndef DETOUR_H
|
||||||
|
#define DETOUR_H
|
||||||
|
#include "core/resource.h"
|
||||||
|
#include "scene/3d/spatial.h"
|
||||||
|
#include "scene/resources/mesh.h"
|
||||||
|
|
||||||
|
#include "detour-navmesh.h"
|
||||||
|
class DetourNavigation : public Spatial {
|
||||||
|
GDCLASS(DetourNavigation, Spatial);
|
||||||
|
DetourNavigation() :
|
||||||
|
Spatial() {
|
||||||
|
}
|
||||||
|
static void _bind_methods();
|
||||||
|
};
|
||||||
|
class DetourNavigationMeshInstance;
|
||||||
|
class DetourNavigationOffmeshConnection : public Spatial {
|
||||||
|
GDCLASS(DetourNavigationOffmeshConnection, Spatial);
|
||||||
|
friend class DetourNavigationMeshInstance;
|
||||||
|
Vector3 end;
|
||||||
|
float radius;
|
||||||
|
unsigned short flags;
|
||||||
|
unsigned char area;
|
||||||
|
bool bidirectional;
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vector3 endpoint;
|
||||||
|
DetourNavigationOffmeshConnection() :
|
||||||
|
Spatial(),
|
||||||
|
end(Vector3(0, 0, 10.0f)),
|
||||||
|
radius(5.0f),
|
||||||
|
flags(1),
|
||||||
|
area(1),
|
||||||
|
bidirectional(true) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DetourNavigationArea : public Spatial {
|
||||||
|
GDCLASS(DetourNavigationArea, Spatial);
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
AABB bounds;
|
||||||
|
int id;
|
||||||
|
unsigned int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
class dtNavMesh;
|
||||||
|
struct dtNavMeshParams;
|
||||||
|
class dtNavMeshQuery;
|
||||||
|
class dtQueryFilter;
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
class dtTileCache;
|
||||||
|
struct dtTileCacheAlloc;
|
||||||
|
struct dtTileCacheCompressor;
|
||||||
|
struct dtTileCacheMeshProcess;
|
||||||
|
struct dtTileCacheLayer;
|
||||||
|
struct dtTileCacheContourSet;
|
||||||
|
struct dtTileCachePolyMesh;
|
||||||
|
struct dtTileCacheParams;
|
||||||
|
struct NavMeshProcess;
|
||||||
|
#endif
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
class DetourNavigationObstacle;
|
||||||
|
#endif
|
||||||
|
class DetourNavigationMeshInstance : public Spatial {
|
||||||
|
class DetourNavigationQueryData;
|
||||||
|
GDCLASS(DetourNavigationMeshInstance, Spatial);
|
||||||
|
Ref<DetourNavigationMesh> mesh;
|
||||||
|
static void _bind_methods();
|
||||||
|
void _notification(int p_what);
|
||||||
|
Node *debug_view;
|
||||||
|
#ifdef TILE_CACHE
|
||||||
|
Vector<DetourNavigationObstacle *> obstacles;
|
||||||
|
#endif
|
||||||
|
protected:
|
||||||
|
static float random();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_navmesh(const Ref<DetourNavigationMesh> &mesh);
|
||||||
|
Ref<DetourNavigationMesh> get_navmesh() {
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
DetourNavigationMeshInstance();
|
||||||
|
void build();
|
||||||
|
void add_mesh(const Ref<Mesh> &mesh, const Transform &transform);
|
||||||
|
void set_group(const String &group) {
|
||||||
|
mesh->set_group(group);
|
||||||
|
}
|
||||||
|
const String &get_group() const {
|
||||||
|
return mesh->get_group();
|
||||||
|
}
|
||||||
|
Vector<Ref<Mesh> > geometries;
|
||||||
|
Vector<Transform> xforms;
|
||||||
|
Vector<DetourNavigationArea> nav_areas;
|
||||||
|
void collect_geometries(bool recursive);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
BIN
modules/detour/detour.x11.opt.tools.64.o
Normal file
BIN
modules/detour/detour.x11.opt.tools.64.o
Normal file
Binary file not shown.
378
modules/detour/navmesh_query.cpp
Normal file
378
modules/detour/navmesh_query.cpp
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
#include "navmesh_query.h"
|
||||||
|
#include "detour.h"
|
||||||
|
#include <DetourNavMeshQuery.h>
|
||||||
|
DetourNavigationQueryFilter::DetourNavigationQueryFilter() :
|
||||||
|
Reference() {
|
||||||
|
query_filter = memnew(dtQueryFilter());
|
||||||
|
}
|
||||||
|
DetourNavigationQueryFilter::~DetourNavigationQueryFilter() {
|
||||||
|
memdelete(query_filter);
|
||||||
|
}
|
||||||
|
void DetourNavigationQueryFilter::set_area_cost(int area_id, float cost) {
|
||||||
|
if (query_filter)
|
||||||
|
query_filter->setAreaCost(area_id, cost);
|
||||||
|
}
|
||||||
|
float DetourNavigationQueryFilter::get_area_cost(int area_id) {
|
||||||
|
if (query_filter)
|
||||||
|
return query_filter->getAreaCost(area_id);
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
void DetourNavigationQueryFilter::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("set_area_cost", "area_id", "cost"),
|
||||||
|
&DetourNavigationQueryFilter::set_area_cost);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_area_cost", "area_id"),
|
||||||
|
&DetourNavigationQueryFilter::get_area_cost);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DetourNavigationQuery::QueryData {
|
||||||
|
public:
|
||||||
|
Vector3 path_points[MAX_POLYS];
|
||||||
|
unsigned char path_flags[MAX_POLYS];
|
||||||
|
dtPolyRef polys[MAX_POLYS];
|
||||||
|
dtPolyRef path_polys[MAX_POLYS];
|
||||||
|
};
|
||||||
|
|
||||||
|
DetourNavigationQuery::DetourNavigationQuery() :
|
||||||
|
Object(),
|
||||||
|
query_data(memnew(QueryData)) {}
|
||||||
|
|
||||||
|
DetourNavigationQuery::~DetourNavigationQuery() {}
|
||||||
|
void DetourNavigationQuery::init(Ref<DetourNavigationMesh> mesh,
|
||||||
|
const Transform &xform) {
|
||||||
|
navmesh_query = dtAllocNavMeshQuery();
|
||||||
|
if (!navmesh_query) {
|
||||||
|
ERR_PRINT("failed to create navigation query");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dtStatusFailed(navmesh_query->init(mesh->get_navmesh(), MAX_POLYS))) {
|
||||||
|
ERR_PRINT("failed to initialize navigation query");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
transform = xform;
|
||||||
|
inverse = xform.inverse();
|
||||||
|
}
|
||||||
|
float DetourNavigationQuery::random() {
|
||||||
|
return (float)Math::randf();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 DetourNavigationQuery::nearest_point_(const Vector3 &point,
|
||||||
|
const Vector3 &extents,
|
||||||
|
const dtQueryFilter *filter,
|
||||||
|
uint64_t *ppref) {
|
||||||
|
if (!navmesh_query)
|
||||||
|
return point;
|
||||||
|
Vector3 nearest_point;
|
||||||
|
dtPolyRef dtppref = ppref ? (dtPolyRef)(*ppref) : 0;
|
||||||
|
navmesh_query->findNearestPoly(&point.coord[0], &extents.coord[0], filter,
|
||||||
|
&dtppref, &nearest_point.coord[0]);
|
||||||
|
*ppref = dtppref;
|
||||||
|
if (*ppref)
|
||||||
|
return nearest_point;
|
||||||
|
else
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3
|
||||||
|
DetourNavigationQuery::nearest_point(const Vector3 &point,
|
||||||
|
const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter) {
|
||||||
|
if (!navmesh_query)
|
||||||
|
return point;
|
||||||
|
Vector3 local_point = inverse.xform(point);
|
||||||
|
Vector3 nearest_point;
|
||||||
|
polyref_t pref = 0;
|
||||||
|
nearest_point = nearest_point_(local_point, extents, filter, &pref);
|
||||||
|
// what is dtQueryFilter and how to work with it?
|
||||||
|
if (pref)
|
||||||
|
return transform.xform(nearest_point);
|
||||||
|
else
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3
|
||||||
|
DetourNavigationQuery::random_point_(polyref_t *pref,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter) {
|
||||||
|
if (!navmesh_query)
|
||||||
|
return Vector3();
|
||||||
|
Vector3 point;
|
||||||
|
dtPolyRef dtpref = pref ? *pref : 0;
|
||||||
|
navmesh_query->findRandomPoint(filter->get(), random, &dtpref,
|
||||||
|
&point.coord[0]);
|
||||||
|
*pref = dtpref;
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3
|
||||||
|
DetourNavigationQuery::random_point(Ref<DetourNavigationQueryFilter> filter) {
|
||||||
|
polyref_t pref;
|
||||||
|
Vector3 point = random_point_(&pref, filter);
|
||||||
|
return transform.xform(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 DetourNavigationQuery::random_point_in_circle_(
|
||||||
|
const Vector3 ¢er, float radius, const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter, polyref_t *ppref) {
|
||||||
|
if (!navmesh_query)
|
||||||
|
return center;
|
||||||
|
dtPolyRef pref;
|
||||||
|
navmesh_query->findNearestPoly(¢er.coord[0], &extents.coord[0],
|
||||||
|
filter->get(), &pref, NULL);
|
||||||
|
if (!pref)
|
||||||
|
return center;
|
||||||
|
Vector3 point = center;
|
||||||
|
dtPolyRef dtppref = ppref ? *ppref : 0;
|
||||||
|
navmesh_query->findRandomPointAroundCircle(pref, ¢er.coord[0], radius,
|
||||||
|
filter->get(), random, &dtppref,
|
||||||
|
&point.coord[0]);
|
||||||
|
*ppref = dtppref;
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
Vector3 DetourNavigationQuery::random_point_in_circle(
|
||||||
|
const Vector3 ¢er, float radius, const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter) {
|
||||||
|
Vector3 local_center = inverse.xform(center);
|
||||||
|
polyref_t pref2;
|
||||||
|
Vector3 point =
|
||||||
|
random_point_in_circle_(local_center, radius, extents, filter, &pref2);
|
||||||
|
return transform.xform(point);
|
||||||
|
}
|
||||||
|
float DetourNavigationQuery::distance_to_wall_(
|
||||||
|
const Vector3 &point, float radius, const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter, Vector3 *hit_pos,
|
||||||
|
Vector3 *hit_normal) {
|
||||||
|
if (hit_pos)
|
||||||
|
*hit_pos = Vector3();
|
||||||
|
if (hit_normal)
|
||||||
|
*hit_normal = Vector3(0.0, -1.0, 0.0);
|
||||||
|
float distance = radius;
|
||||||
|
dtPolyRef pref;
|
||||||
|
if (!navmesh_query)
|
||||||
|
return distance;
|
||||||
|
navmesh_query->findNearestPoly(&point.coord[0], &extents.coord[0],
|
||||||
|
filter->get(), &pref, NULL);
|
||||||
|
if (!pref)
|
||||||
|
return distance;
|
||||||
|
navmesh_query->findDistanceToWall(pref, &point.coord[0], radius,
|
||||||
|
filter->get(), &distance,
|
||||||
|
reinterpret_cast<float *>(hit_pos),
|
||||||
|
reinterpret_cast<float *>(hit_normal));
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
Dictionary DetourNavigationQuery::distance_to_wall_detailed(
|
||||||
|
const Vector3 &point, float radius, const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter) {
|
||||||
|
Dictionary ret;
|
||||||
|
Vector3 hit_pos = Vector3(), hit_normal = Vector3(0.0, -1.0, 0.0);
|
||||||
|
|
||||||
|
ret["position"] = hit_pos;
|
||||||
|
ret["normal"] = hit_normal;
|
||||||
|
ret["distance"] = radius;
|
||||||
|
Vector3 local_point = inverse.xform(point);
|
||||||
|
float dist = distance_to_wall_(local_point, radius, extents, filter, &hit_pos,
|
||||||
|
&hit_normal);
|
||||||
|
ret["position"] = hit_pos;
|
||||||
|
ret["normal"] = hit_normal;
|
||||||
|
ret["distance"] = dist;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
float DetourNavigationQuery::distance_to_wall(
|
||||||
|
const Vector3 &point, float radius, const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter) {
|
||||||
|
Vector3 local_point = inverse.xform(point);
|
||||||
|
return distance_to_wall_(local_point, radius, extents, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 DetourNavigationQuery::raycast_(const Vector3 &start,
|
||||||
|
const Vector3 &end,
|
||||||
|
const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter,
|
||||||
|
Vector3 *hit_normal) {
|
||||||
|
dtPolyRef pref;
|
||||||
|
float r;
|
||||||
|
if (hit_normal)
|
||||||
|
*hit_normal = Vector3();
|
||||||
|
navmesh_query->findNearestPoly(&start.coord[0], &extents.coord[0],
|
||||||
|
filter->get(), &pref, NULL);
|
||||||
|
if (!pref)
|
||||||
|
return end;
|
||||||
|
int poly_count = 0;
|
||||||
|
navmesh_query->raycast(pref, &start.coord[0], &end.coord[0], filter->get(),
|
||||||
|
&r, reinterpret_cast<float *>(hit_normal),
|
||||||
|
query_data->polys, &poly_count, MAX_POLYS);
|
||||||
|
if (r > 1.0f)
|
||||||
|
r = 1.0f;
|
||||||
|
return start.linear_interpolate(end, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Vector3>
|
||||||
|
DetourNavigationQuery::raycast(const Vector3 &start, const Vector3 &end,
|
||||||
|
const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter) {
|
||||||
|
Vector<Vector3> ret;
|
||||||
|
Vector3 normal(0.0, -1.0, 0.0);
|
||||||
|
if (!navmesh_query) {
|
||||||
|
ret.push_back(end);
|
||||||
|
ret.push_back(normal);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
Vector3 local_start = inverse.xform(start);
|
||||||
|
Vector3 local_end = inverse.xform(end);
|
||||||
|
Vector3 result = raycast_(local_start, local_end, extents, filter, &normal);
|
||||||
|
ret.push_back(transform.xform(result));
|
||||||
|
ret.push_back(normal);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
Vector3 DetourNavigationQuery::move_along_surface_(
|
||||||
|
const Vector3 &start, const Vector3 &end, const Vector3 &extents,
|
||||||
|
int max_visited, Ref<DetourNavigationQueryFilter> filter) {
|
||||||
|
dtPolyRef pstart;
|
||||||
|
navmesh_query->findNearestPoly(&start.coord[0], &extents.coord[0],
|
||||||
|
filter->get(), &pstart, NULL);
|
||||||
|
if (!pstart)
|
||||||
|
return end;
|
||||||
|
Vector3 result;
|
||||||
|
int visited = 0;
|
||||||
|
Vector<dtPolyRef> visited_ref;
|
||||||
|
visited_ref.resize(max_visited);
|
||||||
|
navmesh_query->moveAlongSurface(
|
||||||
|
pstart, &start.coord[0], &end.coord[0], filter->get(), &result.coord[0],
|
||||||
|
max_visited > 0 ? &visited_ref.write[0] : NULL, &visited, max_visited);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Vector3 DetourNavigationQuery::move_along_surface(
|
||||||
|
const Vector3 &start, const Vector3 &end, const Vector3 &extents,
|
||||||
|
int max_visited, Ref<DetourNavigationQueryFilter> filter) {
|
||||||
|
if (!navmesh_query)
|
||||||
|
return end;
|
||||||
|
#if 0
|
||||||
|
/* TODO: are these necessary? */
|
||||||
|
Vector3 local_start = inverse.xform(start);
|
||||||
|
Vector3 local_end = inverse.xform(end);
|
||||||
|
#endif
|
||||||
|
Vector3 result =
|
||||||
|
move_along_surface_(start, end, extents, max_visited, filter);
|
||||||
|
return transform.xform(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary
|
||||||
|
DetourNavigationQuery::find_path_(const Vector3 &start, const Vector3 &end,
|
||||||
|
const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter) {
|
||||||
|
Vector<Vector3> points;
|
||||||
|
Vector<int> flags;
|
||||||
|
Dictionary ret;
|
||||||
|
if (!navmesh_query)
|
||||||
|
return ret;
|
||||||
|
dtPolyRef pstart;
|
||||||
|
dtPolyRef pend;
|
||||||
|
navmesh_query->findNearestPoly(&start.coord[0], &extents.coord[0],
|
||||||
|
filter->get(), &pstart, NULL);
|
||||||
|
navmesh_query->findNearestPoly(&end.coord[0], &extents.coord[0],
|
||||||
|
filter->get(), &pend, NULL);
|
||||||
|
if (!pstart || !pend)
|
||||||
|
return ret;
|
||||||
|
int num_polys = 0;
|
||||||
|
int num_path_points = 0;
|
||||||
|
navmesh_query->findPath(pstart, pend, &start.coord[0], &end.coord[0],
|
||||||
|
filter->get(), query_data->polys, &num_polys,
|
||||||
|
MAX_POLYS);
|
||||||
|
if (!num_polys)
|
||||||
|
return ret;
|
||||||
|
Vector3 actual_end = end;
|
||||||
|
if (query_data->polys[num_polys - 1] != pend) {
|
||||||
|
Vector3 tmp;
|
||||||
|
navmesh_query->closestPointOnPoly(query_data->polys[num_polys - 1],
|
||||||
|
&end.coord[0], &tmp.coord[0], NULL);
|
||||||
|
actual_end = tmp;
|
||||||
|
}
|
||||||
|
navmesh_query->findStraightPath(
|
||||||
|
&start.coord[0], &actual_end.coord[0], query_data->polys, num_polys,
|
||||||
|
&query_data->path_points[0].coord[0], &query_data->path_flags[0],
|
||||||
|
query_data->path_polys, &num_path_points, MAX_POLYS);
|
||||||
|
for (int i = 0; i < num_path_points; i++) {
|
||||||
|
points.push_back(query_data->path_points[i]);
|
||||||
|
flags.push_back(query_data->path_flags[i]);
|
||||||
|
}
|
||||||
|
ret["points"] = points;
|
||||||
|
ret["flags"] = flags;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
Dictionary
|
||||||
|
DetourNavigationQuery::find_path(const Vector3 &start, const Vector3 &end,
|
||||||
|
const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter) {
|
||||||
|
Vector3 local_start = inverse.xform(start);
|
||||||
|
Vector3 local_end = inverse.xform(end);
|
||||||
|
Dictionary result = find_path_(local_start, local_end, extents, filter);
|
||||||
|
Vector<Vector3> points = result["points"];
|
||||||
|
for (int i = 0; i < points.size(); i++)
|
||||||
|
points.write[i] = transform.xform(points[i]);
|
||||||
|
result["points"] = points;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
void DetourNavigationQuery::find_path_array(const Vector3 &start, const Vector3 &end,
|
||||||
|
const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter,
|
||||||
|
Vector<Vector3> &points,
|
||||||
|
Vector<int> &flags) {
|
||||||
|
Dictionary ret;
|
||||||
|
if (!navmesh_query)
|
||||||
|
return;
|
||||||
|
dtPolyRef pstart;
|
||||||
|
dtPolyRef pend;
|
||||||
|
navmesh_query->findNearestPoly(&start.coord[0], &extents.coord[0],
|
||||||
|
filter->get(), &pstart, NULL);
|
||||||
|
navmesh_query->findNearestPoly(&end.coord[0], &extents.coord[0],
|
||||||
|
filter->get(), &pend, NULL);
|
||||||
|
if (!pstart || !pend)
|
||||||
|
return;
|
||||||
|
int num_polys = 0;
|
||||||
|
int num_path_points = 0;
|
||||||
|
navmesh_query->findPath(pstart, pend, &start.coord[0], &end.coord[0],
|
||||||
|
filter->get(), query_data->polys, &num_polys,
|
||||||
|
MAX_POLYS);
|
||||||
|
if (!num_polys)
|
||||||
|
return;
|
||||||
|
Vector3 actual_end = end;
|
||||||
|
if (query_data->polys[num_polys - 1] != pend) {
|
||||||
|
Vector3 tmp;
|
||||||
|
navmesh_query->closestPointOnPoly(query_data->polys[num_polys - 1],
|
||||||
|
&end.coord[0], &tmp.coord[0], NULL);
|
||||||
|
actual_end = tmp;
|
||||||
|
}
|
||||||
|
navmesh_query->findStraightPath(
|
||||||
|
&start.coord[0], &actual_end.coord[0], query_data->polys, num_polys,
|
||||||
|
&query_data->path_points[0].coord[0], &query_data->path_flags[0],
|
||||||
|
query_data->path_polys, &num_path_points, MAX_POLYS);
|
||||||
|
points.resize(num_path_points);
|
||||||
|
flags.resize(num_path_points);
|
||||||
|
for (int i = 0; i < num_path_points; i++) {
|
||||||
|
points.write[i] = transform.xform(query_data->path_points[i]);
|
||||||
|
flags.write[i] = query_data->path_flags[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DetourNavigationQuery::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("init", "navmesh", "xform"),
|
||||||
|
&DetourNavigationQuery::init);
|
||||||
|
ClassDB::bind_method(D_METHOD("nearest_point", "point", "extents", "filter"),
|
||||||
|
&DetourNavigationQuery::nearest_point);
|
||||||
|
ClassDB::bind_method(D_METHOD("random_point", "filter"),
|
||||||
|
&DetourNavigationQuery::random_point);
|
||||||
|
ClassDB::bind_method(D_METHOD("random_point_in_circle", "center", "radius",
|
||||||
|
"extents", "filter"),
|
||||||
|
&DetourNavigationQuery::random_point_in_circle);
|
||||||
|
ClassDB::bind_method(
|
||||||
|
D_METHOD("distance_to_wall", "point", "radius", "extents", "filter"),
|
||||||
|
&DetourNavigationQuery::distance_to_wall);
|
||||||
|
ClassDB::bind_method(D_METHOD("distance_to_wall_detailed", "point", "radius",
|
||||||
|
"extents", "filter"),
|
||||||
|
&DetourNavigationQuery::distance_to_wall_detailed);
|
||||||
|
ClassDB::bind_method(D_METHOD("raycast", "start", "end", "extents", "filter"),
|
||||||
|
&DetourNavigationQuery::raycast);
|
||||||
|
ClassDB::bind_method(D_METHOD("move_along_surface", "start", "end", "extents",
|
||||||
|
"max_visited", "filter"),
|
||||||
|
&DetourNavigationQuery::move_along_surface);
|
||||||
|
ClassDB::bind_method(
|
||||||
|
D_METHOD("find_path", "start", "end", "extents", "filter"),
|
||||||
|
&DetourNavigationQuery::find_path);
|
||||||
|
}
|
||||||
100
modules/detour/navmesh_query.h
Normal file
100
modules/detour/navmesh_query.h
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* navmesh_query.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
#ifndef NAVMESH_QUERY_H
|
||||||
|
#define NAVMESH_QUERY_H
|
||||||
|
#include "core/math/transform.h"
|
||||||
|
#include "core/object.h"
|
||||||
|
#include "core/reference.h"
|
||||||
|
class dtQueryFilter;
|
||||||
|
class dtNavMeshQuery;
|
||||||
|
class DetourNavigationMesh;
|
||||||
|
class DetourNavigationQueryFilter : public Reference {
|
||||||
|
GDCLASS(DetourNavigationQueryFilter, Reference);
|
||||||
|
/* Detour query filter */
|
||||||
|
dtQueryFilter *query_filter;
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
DetourNavigationQueryFilter();
|
||||||
|
~DetourNavigationQueryFilter();
|
||||||
|
const inline dtQueryFilter *get() {
|
||||||
|
return query_filter;
|
||||||
|
}
|
||||||
|
void set_area_cost(int area_id, float cost);
|
||||||
|
float get_area_cost(int area_id);
|
||||||
|
};
|
||||||
|
class DetourNavigationQuery : public Object {
|
||||||
|
GDCLASS(DetourNavigationQuery, Object);
|
||||||
|
dtNavMeshQuery *navmesh_query;
|
||||||
|
/* Navigation mesh transform */
|
||||||
|
Transform transform, inverse;
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static const int MAX_POLYS = 2048;
|
||||||
|
/* query data */
|
||||||
|
class QueryData;
|
||||||
|
QueryData *query_data;
|
||||||
|
static float random();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int get_max_polys() const { return MAX_POLYS; }
|
||||||
|
typedef uint64_t polyref_t;
|
||||||
|
void init(Ref<DetourNavigationMesh> mesh, const Transform &xform);
|
||||||
|
Vector3 nearest_point_(const Vector3 &point, const Vector3 &extents, const dtQueryFilter *filter, polyref_t *ppref);
|
||||||
|
inline Vector3 nearest_point_(const Vector3 &point, const Vector3 &extents, Ref<DetourNavigationQueryFilter> filter, polyref_t *ppref) {
|
||||||
|
return nearest_point_(point, extents, filter->get(), ppref);
|
||||||
|
}
|
||||||
|
Vector3 nearest_point(const Vector3 &point, const Vector3 &extents, Ref<DetourNavigationQueryFilter> filter);
|
||||||
|
Vector3 random_point_(polyref_t *pref, Ref<DetourNavigationQueryFilter> filter);
|
||||||
|
Vector3 random_point(Ref<DetourNavigationQueryFilter> filter);
|
||||||
|
Vector3 random_point_in_circle_(const Vector3 ¢er, float radius, const Vector3 &extents, Ref<DetourNavigationQueryFilter> filter, polyref_t *ppref);
|
||||||
|
Vector3 random_point_in_circle(const Vector3 ¢er, float radius, const Vector3 &extents, Ref<DetourNavigationQueryFilter> filter);
|
||||||
|
float distance_to_wall_(const Vector3 &point, float radius, const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter,
|
||||||
|
Vector3 *hit_pos = NULL, Vector3 *hit_normal = NULL);
|
||||||
|
float distance_to_wall(const Vector3 &point, float radius, const Vector3 &extents, Ref<DetourNavigationQueryFilter> filter);
|
||||||
|
Dictionary distance_to_wall_detailed(const Vector3 &point, float radius, const Vector3 &extents, Ref<DetourNavigationQueryFilter> filter);
|
||||||
|
Vector3 raycast_(const Vector3 &start, const Vector3 &end,
|
||||||
|
const Vector3 &extents, Ref<DetourNavigationQueryFilter> filter,
|
||||||
|
Vector3 *hit_normal);
|
||||||
|
Vector<Vector3> raycast(const Vector3 &start, const Vector3 &end, const Vector3 &extents, Ref<DetourNavigationQueryFilter> filter);
|
||||||
|
Vector3 move_along_surface_(const Vector3 &start, const Vector3 &end,
|
||||||
|
const Vector3 &extents, int max_visited, Ref<DetourNavigationQueryFilter> filter);
|
||||||
|
Vector3 move_along_surface(const Vector3 &start, const Vector3 &end,
|
||||||
|
const Vector3 &extents, int max_visited, Ref<DetourNavigationQueryFilter> filter);
|
||||||
|
Dictionary find_path_(const Vector3 &start, const Vector3 &end, const Vector3 &extents, Ref<DetourNavigationQueryFilter> filter);
|
||||||
|
Dictionary find_path(const Vector3 &start, const Vector3 &end, const Vector3 &extents, Ref<DetourNavigationQueryFilter> filter);
|
||||||
|
void find_path_array(const Vector3 &start, const Vector3 &end, const Vector3 &extents,
|
||||||
|
Ref<DetourNavigationQueryFilter> filter, Vector<Vector3> &points, Vector<int> &flags);
|
||||||
|
DetourNavigationQuery();
|
||||||
|
~DetourNavigationQuery();
|
||||||
|
};
|
||||||
|
#endif
|
||||||
BIN
modules/detour/navmesh_query.x11.opt.tools.64.o
Normal file
BIN
modules/detour/navmesh_query.x11.opt.tools.64.o
Normal file
Binary file not shown.
25
modules/detour/obstacle.cpp
Normal file
25
modules/detour/obstacle.cpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include "obstacle.h"
|
||||||
|
#include "detour.h"
|
||||||
|
DetourNavigationObstacle::DetourNavigationObstacle() :
|
||||||
|
mesh(0),
|
||||||
|
id(0),
|
||||||
|
radius(5.0f),
|
||||||
|
height(5.0f) {}
|
||||||
|
|
||||||
|
DetourNavigationObstacle::~DetourNavigationObstacle() {
|
||||||
|
if (mesh && id > 0)
|
||||||
|
mesh->remove_obstacle(id);
|
||||||
|
}
|
||||||
|
void DetourNavigationObstacle::_bind_methods()
|
||||||
|
{
|
||||||
|
ClassDB::bind_method(D_METHOD("get_radius"),
|
||||||
|
&DetourNavigationObstacle::get_radius);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_radius", "radius"),
|
||||||
|
&DetourNavigationObstacle::set_radius);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_height"),
|
||||||
|
&DetourNavigationObstacle::get_height);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_height", "height"),
|
||||||
|
&DetourNavigationObstacle::set_height);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_NONE, ""), "set_radius", "get_radius");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_NONE, ""), "set_height", "get_height");
|
||||||
|
}
|
||||||
55
modules/detour/obstacle.h
Normal file
55
modules/detour/obstacle.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* obstacle.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
#ifndef OBSTACLE_H
|
||||||
|
#define OBSTACLE_H
|
||||||
|
#include "scene/3d/spatial.h"
|
||||||
|
class DetourNavigationMesh;
|
||||||
|
class DetourNavigationObstacle : public Spatial {
|
||||||
|
GDCLASS(DetourNavigationObstacle, Spatial);
|
||||||
|
friend class DetourNavigationMeshInstance;
|
||||||
|
DetourNavigationMesh *mesh;
|
||||||
|
unsigned int id;
|
||||||
|
real_t radius;
|
||||||
|
real_t height;
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
DetourNavigationObstacle();
|
||||||
|
~DetourNavigationObstacle();
|
||||||
|
real_t get_radius() const { return radius; }
|
||||||
|
real_t get_height() const { return height; }
|
||||||
|
void set_radius(real_t radius) {
|
||||||
|
this->radius = radius;
|
||||||
|
}
|
||||||
|
void set_height(real_t height) {
|
||||||
|
this->height = height;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
BIN
modules/detour/obstacle.x11.opt.tools.64.o
Normal file
BIN
modules/detour/obstacle.x11.opt.tools.64.o
Normal file
Binary file not shown.
52
modules/detour/register_types.cpp
Normal file
52
modules/detour/register_types.cpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* register_types.cpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#include "register_types.h"
|
||||||
|
#include "crowd.h"
|
||||||
|
#include "detour.h"
|
||||||
|
#include "navmesh_query.h"
|
||||||
|
#include "obstacle.h"
|
||||||
|
|
||||||
|
void register_detour_types() {
|
||||||
|
ClassDB::register_class<DetourNavigation>();
|
||||||
|
ClassDB::register_class<DetourNavigationOffmeshConnection>();
|
||||||
|
ClassDB::register_class<DetourNavigationArea>();
|
||||||
|
ClassDB::register_class<DetourNavigationObstacle>();
|
||||||
|
ClassDB::register_class<DetourNavigationMesh>();
|
||||||
|
ClassDB::register_class<DetourNavigationQuery>();
|
||||||
|
ClassDB::register_class<DetourNavigationQueryFilter>();
|
||||||
|
ClassDB::register_class<DetourNavigationMeshInstance>();
|
||||||
|
ClassDB::register_class<DetourCrowdManager>();
|
||||||
|
#if 0
|
||||||
|
ClassDB::register_class<Crowd>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregister_detour_types() {}
|
||||||
32
modules/detour/register_types.h
Normal file
32
modules/detour/register_types.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* register_types.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
void register_detour_types();
|
||||||
|
void unregister_detour_types();
|
||||||
BIN
modules/detour/register_types.x11.opt.tools.64.o
Normal file
BIN
modules/detour/register_types.x11.opt.tools.64.o
Normal file
Binary file not shown.
61
modules/detour/thirdparty/Detour/Include/DetourAlloc.h
vendored
Normal file
61
modules/detour/thirdparty/Detour/Include/DetourAlloc.h
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURALLOCATOR_H
|
||||||
|
#define DETOURALLOCATOR_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/// Provides hint values to the memory allocator on how long the
|
||||||
|
/// memory is expected to be used.
|
||||||
|
enum dtAllocHint
|
||||||
|
{
|
||||||
|
DT_ALLOC_PERM, ///< Memory persist after a function call.
|
||||||
|
DT_ALLOC_TEMP ///< Memory used temporarily within a function.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A memory allocation function.
|
||||||
|
// @param[in] size The size, in bytes of memory, to allocate.
|
||||||
|
// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.
|
||||||
|
// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||||
|
/// @see dtAllocSetCustom
|
||||||
|
typedef void* (dtAllocFunc)(size_t size, dtAllocHint hint);
|
||||||
|
|
||||||
|
/// A memory deallocation function.
|
||||||
|
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAllocFunc.
|
||||||
|
/// @see dtAllocSetCustom
|
||||||
|
typedef void (dtFreeFunc)(void* ptr);
|
||||||
|
|
||||||
|
/// Sets the base custom allocation functions to be used by Detour.
|
||||||
|
/// @param[in] allocFunc The memory allocation function to be used by #dtAlloc
|
||||||
|
/// @param[in] freeFunc The memory de-allocation function to be used by #dtFree
|
||||||
|
void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc);
|
||||||
|
|
||||||
|
/// Allocates a memory block.
|
||||||
|
/// @param[in] size The size, in bytes of memory, to allocate.
|
||||||
|
/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
|
||||||
|
/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||||
|
/// @see dtFree
|
||||||
|
void* dtAlloc(size_t size, dtAllocHint hint);
|
||||||
|
|
||||||
|
/// Deallocates a memory block.
|
||||||
|
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAlloc.
|
||||||
|
/// @see dtAlloc
|
||||||
|
void dtFree(void* ptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
56
modules/detour/thirdparty/Detour/Include/DetourAssert.h
vendored
Normal file
56
modules/detour/thirdparty/Detour/Include/DetourAssert.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURASSERT_H
|
||||||
|
#define DETOURASSERT_H
|
||||||
|
|
||||||
|
// Note: This header file's only purpose is to include define assert.
|
||||||
|
// Feel free to change the file and include your own implementation instead.
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
|
||||||
|
// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
|
||||||
|
# define dtAssert(x) do { (void)sizeof(x); } while((void)(__LINE__==-1),false)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/// An assertion failure function.
|
||||||
|
// @param[in] expression asserted expression.
|
||||||
|
// @param[in] file Filename of the failed assertion.
|
||||||
|
// @param[in] line Line number of the failed assertion.
|
||||||
|
/// @see dtAssertFailSetCustom
|
||||||
|
typedef void (dtAssertFailFunc)(const char* expression, const char* file, int line);
|
||||||
|
|
||||||
|
/// Sets the base custom assertion failure function to be used by Detour.
|
||||||
|
/// @param[in] assertFailFunc The function to be invoked in case of failure of #dtAssert
|
||||||
|
void dtAssertFailSetCustom(dtAssertFailFunc *assertFailFunc);
|
||||||
|
|
||||||
|
/// Gets the base custom assertion failure function to be used by Detour.
|
||||||
|
dtAssertFailFunc* dtAssertFailGetCustom();
|
||||||
|
|
||||||
|
# include <assert.h>
|
||||||
|
# define dtAssert(expression) \
|
||||||
|
{ \
|
||||||
|
dtAssertFailFunc* failFunc = dtAssertFailGetCustom(); \
|
||||||
|
if(failFunc == NULL) { assert(expression); } \
|
||||||
|
else if(!(expression)) { (*failFunc)(#expression, __FILE__, __LINE__); } \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // DETOURASSERT_H
|
||||||
572
modules/detour/thirdparty/Detour/Include/DetourCommon.h
vendored
Normal file
572
modules/detour/thirdparty/Detour/Include/DetourCommon.h
vendored
Normal file
@@ -0,0 +1,572 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURCOMMON_H
|
||||||
|
#define DETOURCOMMON_H
|
||||||
|
|
||||||
|
#include "DetourMath.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
@defgroup detour Detour
|
||||||
|
|
||||||
|
Members in this module are used to create, manipulate, and query navigation
|
||||||
|
meshes.
|
||||||
|
|
||||||
|
@note This is a summary list of members. Use the index or search
|
||||||
|
feature to find minor members.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// @name General helper functions
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Used to ignore a function parameter. VS complains about unused parameters
|
||||||
|
/// and this silences the warning.
|
||||||
|
/// @param [in] _ Unused parameter
|
||||||
|
template<class T> void dtIgnoreUnused(const T&) { }
|
||||||
|
|
||||||
|
/// Swaps the values of the two parameters.
|
||||||
|
/// @param[in,out] a Value A
|
||||||
|
/// @param[in,out] b Value B
|
||||||
|
template<class T> inline void dtSwap(T& a, T& b) { T t = a; a = b; b = t; }
|
||||||
|
|
||||||
|
/// Returns the minimum of two values.
|
||||||
|
/// @param[in] a Value A
|
||||||
|
/// @param[in] b Value B
|
||||||
|
/// @return The minimum of the two values.
|
||||||
|
template<class T> inline T dtMin(T a, T b) { return a < b ? a : b; }
|
||||||
|
|
||||||
|
/// Returns the maximum of two values.
|
||||||
|
/// @param[in] a Value A
|
||||||
|
/// @param[in] b Value B
|
||||||
|
/// @return The maximum of the two values.
|
||||||
|
template<class T> inline T dtMax(T a, T b) { return a > b ? a : b; }
|
||||||
|
|
||||||
|
/// Returns the absolute value.
|
||||||
|
/// @param[in] a The value.
|
||||||
|
/// @return The absolute value of the specified value.
|
||||||
|
template<class T> inline T dtAbs(T a) { return a < 0 ? -a : a; }
|
||||||
|
|
||||||
|
/// Returns the square of the value.
|
||||||
|
/// @param[in] a The value.
|
||||||
|
/// @return The square of the value.
|
||||||
|
template<class T> inline T dtSqr(T a) { return a*a; }
|
||||||
|
|
||||||
|
/// Clamps the value to the specified range.
|
||||||
|
/// @param[in] v The value to clamp.
|
||||||
|
/// @param[in] mn The minimum permitted return value.
|
||||||
|
/// @param[in] mx The maximum permitted return value.
|
||||||
|
/// @return The value, clamped to the specified range.
|
||||||
|
template<class T> inline T dtClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); }
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Vector helper functions.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Derives the cross product of two vectors. (@p v1 x @p v2)
|
||||||
|
/// @param[out] dest The cross product. [(x, y, z)]
|
||||||
|
/// @param[in] v1 A Vector [(x, y, z)]
|
||||||
|
/// @param[in] v2 A vector [(x, y, z)]
|
||||||
|
inline void dtVcross(float* dest, const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||||
|
dest[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||||
|
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the dot product of two vectors. (@p v1 . @p v2)
|
||||||
|
/// @param[in] v1 A Vector [(x, y, z)]
|
||||||
|
/// @param[in] v2 A vector [(x, y, z)]
|
||||||
|
/// @return The dot product.
|
||||||
|
inline float dtVdot(const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s))
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||||
|
/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
|
||||||
|
/// @param[in] s The amount to scale @p v2 by before adding to @p v1.
|
||||||
|
inline void dtVmad(float* dest, const float* v1, const float* v2, const float s)
|
||||||
|
{
|
||||||
|
dest[0] = v1[0]+v2[0]*s;
|
||||||
|
dest[1] = v1[1]+v2[1]*s;
|
||||||
|
dest[2] = v1[2]+v2[2]*s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a linear interpolation between two vectors. (@p v1 toward @p v2)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, x)]
|
||||||
|
/// @param[in] v1 The starting vector.
|
||||||
|
/// @param[in] v2 The destination vector.
|
||||||
|
/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
|
||||||
|
inline void dtVlerp(float* dest, const float* v1, const float* v2, const float t)
|
||||||
|
{
|
||||||
|
dest[0] = v1[0]+(v2[0]-v1[0])*t;
|
||||||
|
dest[1] = v1[1]+(v2[1]-v1[1])*t;
|
||||||
|
dest[2] = v1[2]+(v2[2]-v1[2])*t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a vector addition. (@p v1 + @p v2)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||||
|
/// @param[in] v2 The vector to add to @p v1. [(x, y, z)]
|
||||||
|
inline void dtVadd(float* dest, const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
dest[0] = v1[0]+v2[0];
|
||||||
|
dest[1] = v1[1]+v2[1];
|
||||||
|
dest[2] = v1[2]+v2[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a vector subtraction. (@p v1 - @p v2)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||||
|
/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)]
|
||||||
|
inline void dtVsub(float* dest, const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
dest[0] = v1[0]-v2[0];
|
||||||
|
dest[1] = v1[1]-v2[1];
|
||||||
|
dest[2] = v1[2]-v2[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Scales the vector by the specified value. (@p v * @p t)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v The vector to scale. [(x, y, z)]
|
||||||
|
/// @param[in] t The scaling factor.
|
||||||
|
inline void dtVscale(float* dest, const float* v, const float t)
|
||||||
|
{
|
||||||
|
dest[0] = v[0]*t;
|
||||||
|
dest[1] = v[1]*t;
|
||||||
|
dest[2] = v[2]*t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Selects the minimum value of each element from the specified vectors.
|
||||||
|
/// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)]
|
||||||
|
/// @param[in] v A vector. [(x, y, z)]
|
||||||
|
inline void dtVmin(float* mn, const float* v)
|
||||||
|
{
|
||||||
|
mn[0] = dtMin(mn[0], v[0]);
|
||||||
|
mn[1] = dtMin(mn[1], v[1]);
|
||||||
|
mn[2] = dtMin(mn[2], v[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Selects the maximum value of each element from the specified vectors.
|
||||||
|
/// @param[in,out] mx A vector. (Will be updated with the result.) [(x, y, z)]
|
||||||
|
/// @param[in] v A vector. [(x, y, z)]
|
||||||
|
inline void dtVmax(float* mx, const float* v)
|
||||||
|
{
|
||||||
|
mx[0] = dtMax(mx[0], v[0]);
|
||||||
|
mx[1] = dtMax(mx[1], v[1]);
|
||||||
|
mx[2] = dtMax(mx[2], v[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the vector elements to the specified values.
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] x The x-value of the vector.
|
||||||
|
/// @param[in] y The y-value of the vector.
|
||||||
|
/// @param[in] z The z-value of the vector.
|
||||||
|
inline void dtVset(float* dest, const float x, const float y, const float z)
|
||||||
|
{
|
||||||
|
dest[0] = x; dest[1] = y; dest[2] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a vector copy.
|
||||||
|
/// @param[out] dest The result. [(x, y, z)]
|
||||||
|
/// @param[in] a The vector to copy. [(x, y, z)]
|
||||||
|
inline void dtVcopy(float* dest, const float* a)
|
||||||
|
{
|
||||||
|
dest[0] = a[0];
|
||||||
|
dest[1] = a[1];
|
||||||
|
dest[2] = a[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the scalar length of the vector.
|
||||||
|
/// @param[in] v The vector. [(x, y, z)]
|
||||||
|
/// @return The scalar length of the vector.
|
||||||
|
inline float dtVlen(const float* v)
|
||||||
|
{
|
||||||
|
return dtMathSqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the square of the scalar length of the vector. (len * len)
|
||||||
|
/// @param[in] v The vector. [(x, y, z)]
|
||||||
|
/// @return The square of the scalar length of the vector.
|
||||||
|
inline float dtVlenSqr(const float* v)
|
||||||
|
{
|
||||||
|
return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the distance between two points.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The distance between the two points.
|
||||||
|
inline float dtVdist(const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
const float dx = v2[0] - v1[0];
|
||||||
|
const float dy = v2[1] - v1[1];
|
||||||
|
const float dz = v2[2] - v1[2];
|
||||||
|
return dtMathSqrtf(dx*dx + dy*dy + dz*dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the square of the distance between two points.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The square of the distance between the two points.
|
||||||
|
inline float dtVdistSqr(const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
const float dx = v2[0] - v1[0];
|
||||||
|
const float dy = v2[1] - v1[1];
|
||||||
|
const float dz = v2[2] - v1[2];
|
||||||
|
return dx*dx + dy*dy + dz*dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the distance between the specified points on the xz-plane.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The distance between the point on the xz-plane.
|
||||||
|
///
|
||||||
|
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
inline float dtVdist2D(const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
const float dx = v2[0] - v1[0];
|
||||||
|
const float dz = v2[2] - v1[2];
|
||||||
|
return dtMathSqrtf(dx*dx + dz*dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the square of the distance between the specified points on the xz-plane.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The square of the distance between the point on the xz-plane.
|
||||||
|
inline float dtVdist2DSqr(const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
const float dx = v2[0] - v1[0];
|
||||||
|
const float dz = v2[2] - v1[2];
|
||||||
|
return dx*dx + dz*dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Normalizes the vector.
|
||||||
|
/// @param[in,out] v The vector to normalize. [(x, y, z)]
|
||||||
|
inline void dtVnormalize(float* v)
|
||||||
|
{
|
||||||
|
float d = 1.0f / dtMathSqrtf(dtSqr(v[0]) + dtSqr(v[1]) + dtSqr(v[2]));
|
||||||
|
v[0] *= d;
|
||||||
|
v[1] *= d;
|
||||||
|
v[2] *= d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a 'sloppy' colocation check of the specified points.
|
||||||
|
/// @param[in] p0 A point. [(x, y, z)]
|
||||||
|
/// @param[in] p1 A point. [(x, y, z)]
|
||||||
|
/// @return True if the points are considered to be at the same location.
|
||||||
|
///
|
||||||
|
/// Basically, this function will return true if the specified points are
|
||||||
|
/// close enough to eachother to be considered colocated.
|
||||||
|
inline bool dtVequal(const float* p0, const float* p1)
|
||||||
|
{
|
||||||
|
static const float thr = dtSqr(1.0f/16384.0f);
|
||||||
|
const float d = dtVdistSqr(p0, p1);
|
||||||
|
return d < thr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the specified vector's components are all finite.
|
||||||
|
/// @param[in] v A point. [(x, y, z)]
|
||||||
|
/// @return True if all of the point's components are finite, i.e. not NaN
|
||||||
|
/// or any of the infinities.
|
||||||
|
inline bool dtVisfinite(const float* v)
|
||||||
|
{
|
||||||
|
bool result =
|
||||||
|
dtMathIsfinite(v[0]) &&
|
||||||
|
dtMathIsfinite(v[1]) &&
|
||||||
|
dtMathIsfinite(v[2]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the specified vector's 2D components are finite.
|
||||||
|
/// @param[in] v A point. [(x, y, z)]
|
||||||
|
inline bool dtVisfinite2D(const float* v)
|
||||||
|
{
|
||||||
|
bool result = dtMathIsfinite(v[0]) && dtMathIsfinite(v[2]);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the dot product of two vectors on the xz-plane. (@p u . @p v)
|
||||||
|
/// @param[in] u A vector [(x, y, z)]
|
||||||
|
/// @param[in] v A vector [(x, y, z)]
|
||||||
|
/// @return The dot product on the xz-plane.
|
||||||
|
///
|
||||||
|
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
inline float dtVdot2D(const float* u, const float* v)
|
||||||
|
{
|
||||||
|
return u[0]*v[0] + u[2]*v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the xz-plane 2D perp product of the two vectors. (uz*vx - ux*vz)
|
||||||
|
/// @param[in] u The LHV vector [(x, y, z)]
|
||||||
|
/// @param[in] v The RHV vector [(x, y, z)]
|
||||||
|
/// @return The dot product on the xz-plane.
|
||||||
|
///
|
||||||
|
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
inline float dtVperp2D(const float* u, const float* v)
|
||||||
|
{
|
||||||
|
return u[2]*v[0] - u[0]*v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Computational geometry helper functions.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Derives the signed xz-plane area of the triangle ABC, or the relationship of line AB to point C.
|
||||||
|
/// @param[in] a Vertex A. [(x, y, z)]
|
||||||
|
/// @param[in] b Vertex B. [(x, y, z)]
|
||||||
|
/// @param[in] c Vertex C. [(x, y, z)]
|
||||||
|
/// @return The signed xz-plane area of the triangle.
|
||||||
|
inline float dtTriArea2D(const float* a, const float* b, const float* c)
|
||||||
|
{
|
||||||
|
const float abx = b[0] - a[0];
|
||||||
|
const float abz = b[2] - a[2];
|
||||||
|
const float acx = c[0] - a[0];
|
||||||
|
const float acz = c[2] - a[2];
|
||||||
|
return acx*abz - abx*acz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if two axis-aligned bounding boxes overlap.
|
||||||
|
/// @param[in] amin Minimum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] amax Maximum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] bmin Minimum bounds of box B. [(x, y, z)]
|
||||||
|
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||||
|
/// @return True if the two AABB's overlap.
|
||||||
|
/// @see dtOverlapBounds
|
||||||
|
inline bool dtOverlapQuantBounds(const unsigned short amin[3], const unsigned short amax[3],
|
||||||
|
const unsigned short bmin[3], const unsigned short bmax[3])
|
||||||
|
{
|
||||||
|
bool overlap = true;
|
||||||
|
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||||
|
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
||||||
|
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
||||||
|
return overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if two axis-aligned bounding boxes overlap.
|
||||||
|
/// @param[in] amin Minimum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] amax Maximum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] bmin Minimum bounds of box B. [(x, y, z)]
|
||||||
|
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||||
|
/// @return True if the two AABB's overlap.
|
||||||
|
/// @see dtOverlapQuantBounds
|
||||||
|
inline bool dtOverlapBounds(const float* amin, const float* amax,
|
||||||
|
const float* bmin, const float* bmax)
|
||||||
|
{
|
||||||
|
bool overlap = true;
|
||||||
|
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||||
|
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
||||||
|
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
||||||
|
return overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the closest point on a triangle from the specified reference point.
|
||||||
|
/// @param[out] closest The closest point on the triangle.
|
||||||
|
/// @param[in] p The reference point from which to test. [(x, y, z)]
|
||||||
|
/// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
|
||||||
|
void dtClosestPtPointTriangle(float* closest, const float* p,
|
||||||
|
const float* a, const float* b, const float* c);
|
||||||
|
|
||||||
|
/// Derives the y-axis height of the closest point on the triangle from the specified reference point.
|
||||||
|
/// @param[in] p The reference point from which to test. [(x, y, z)]
|
||||||
|
/// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[out] h The resulting height.
|
||||||
|
bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h);
|
||||||
|
|
||||||
|
bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
|
||||||
|
const float* verts, int nverts,
|
||||||
|
float& tmin, float& tmax,
|
||||||
|
int& segMin, int& segMax);
|
||||||
|
|
||||||
|
bool dtIntersectSegSeg2D(const float* ap, const float* aq,
|
||||||
|
const float* bp, const float* bq,
|
||||||
|
float& s, float& t);
|
||||||
|
|
||||||
|
/// Determines if the specified point is inside the convex polygon on the xz-plane.
|
||||||
|
/// @param[in] pt The point to check. [(x, y, z)]
|
||||||
|
/// @param[in] verts The polygon vertices. [(x, y, z) * @p nverts]
|
||||||
|
/// @param[in] nverts The number of vertices. [Limit: >= 3]
|
||||||
|
/// @return True if the point is inside the polygon.
|
||||||
|
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts);
|
||||||
|
|
||||||
|
bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
|
||||||
|
float* ed, float* et);
|
||||||
|
|
||||||
|
float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t);
|
||||||
|
|
||||||
|
/// Derives the centroid of a convex polygon.
|
||||||
|
/// @param[out] tc The centroid of the polgyon. [(x, y, z)]
|
||||||
|
/// @param[in] idx The polygon indices. [(vertIndex) * @p nidx]
|
||||||
|
/// @param[in] nidx The number of indices in the polygon. [Limit: >= 3]
|
||||||
|
/// @param[in] verts The polygon vertices. [(x, y, z) * vertCount]
|
||||||
|
void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts);
|
||||||
|
|
||||||
|
/// Determines if the two convex polygons overlap on the xz-plane.
|
||||||
|
/// @param[in] polya Polygon A vertices. [(x, y, z) * @p npolya]
|
||||||
|
/// @param[in] npolya The number of vertices in polygon A.
|
||||||
|
/// @param[in] polyb Polygon B vertices. [(x, y, z) * @p npolyb]
|
||||||
|
/// @param[in] npolyb The number of vertices in polygon B.
|
||||||
|
/// @return True if the two polygons overlap.
|
||||||
|
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
||||||
|
const float* polyb, const int npolyb);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Miscellanious functions.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
inline unsigned int dtNextPow2(unsigned int v)
|
||||||
|
{
|
||||||
|
v--;
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
v++;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int dtIlog2(unsigned int v)
|
||||||
|
{
|
||||||
|
unsigned int r;
|
||||||
|
unsigned int shift;
|
||||||
|
r = (v > 0xffff) << 4; v >>= r;
|
||||||
|
shift = (v > 0xff) << 3; v >>= shift; r |= shift;
|
||||||
|
shift = (v > 0xf) << 2; v >>= shift; r |= shift;
|
||||||
|
shift = (v > 0x3) << 1; v >>= shift; r |= shift;
|
||||||
|
r |= (v >> 1);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int dtAlign4(int x) { return (x+3) & ~3; }
|
||||||
|
|
||||||
|
inline int dtOppositeTile(int side) { return (side+4) & 0x7; }
|
||||||
|
|
||||||
|
inline void dtSwapByte(unsigned char* a, unsigned char* b)
|
||||||
|
{
|
||||||
|
unsigned char tmp = *a;
|
||||||
|
*a = *b;
|
||||||
|
*b = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dtSwapEndian(unsigned short* v)
|
||||||
|
{
|
||||||
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dtSwapEndian(short* v)
|
||||||
|
{
|
||||||
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dtSwapEndian(unsigned int* v)
|
||||||
|
{
|
||||||
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dtSwapEndian(int* v)
|
||||||
|
{
|
||||||
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dtSwapEndian(float* v)
|
||||||
|
{
|
||||||
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
|
||||||
|
const float s, const float t, float* out);
|
||||||
|
|
||||||
|
template<typename TypeToRetrieveAs>
|
||||||
|
TypeToRetrieveAs* dtGetThenAdvanceBufferPointer(const unsigned char*& buffer, const size_t distanceToAdvance)
|
||||||
|
{
|
||||||
|
TypeToRetrieveAs* returnPointer = reinterpret_cast<TypeToRetrieveAs*>(buffer);
|
||||||
|
buffer += distanceToAdvance;
|
||||||
|
return returnPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TypeToRetrieveAs>
|
||||||
|
TypeToRetrieveAs* dtGetThenAdvanceBufferPointer(unsigned char*& buffer, const size_t distanceToAdvance)
|
||||||
|
{
|
||||||
|
TypeToRetrieveAs* returnPointer = reinterpret_cast<TypeToRetrieveAs*>(buffer);
|
||||||
|
buffer += distanceToAdvance;
|
||||||
|
return returnPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
#endif // DETOURCOMMON_H
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// This section contains detailed documentation for members that don't have
|
||||||
|
// a source file. It reduces clutter in the main section of the header.
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
@fn float dtTriArea2D(const float* a, const float* b, const float* c)
|
||||||
|
@par
|
||||||
|
|
||||||
|
The vertices are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
|
||||||
|
This is a low cost function than can be used for various purposes. Its main purpose
|
||||||
|
is for point/line relationship testing.
|
||||||
|
|
||||||
|
In all cases: A value of zero indicates that all vertices are collinear or represent the same point.
|
||||||
|
(On the xz-plane.)
|
||||||
|
|
||||||
|
When used for point/line relationship tests, AB usually represents a line against which
|
||||||
|
the C point is to be tested. In this case:
|
||||||
|
|
||||||
|
A positive value indicates that point C is to the left of line AB, looking from A toward B.<br/>
|
||||||
|
A negative value indicates that point C is to the right of lineAB, looking from A toward B.
|
||||||
|
|
||||||
|
When used for evaluating a triangle:
|
||||||
|
|
||||||
|
The absolute value of the return value is two times the area of the triangle when it is
|
||||||
|
projected onto the xz-plane.
|
||||||
|
|
||||||
|
A positive return value indicates:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>The vertices are wrapped in the normal Detour wrap direction.</li>
|
||||||
|
<li>The triangle's 3D face normal is in the general up direction.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
A negative return value indicates:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>The vertices are reverse wrapped. (Wrapped opposite the normal Detour wrap direction.)</li>
|
||||||
|
<li>The triangle's 3D face normal is in the general down direction.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
*/
|
||||||
24
modules/detour/thirdparty/Detour/Include/DetourMath.h
vendored
Normal file
24
modules/detour/thirdparty/Detour/Include/DetourMath.h
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
@defgroup detour Detour
|
||||||
|
|
||||||
|
Members in this module are wrappers around the standard math library
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DETOURMATH_H
|
||||||
|
#define DETOURMATH_H
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
// This include is required because libstdc++ has problems with isfinite
|
||||||
|
// if cmath is included before math.h.
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
inline float dtMathFabsf(float x) { return fabsf(x); }
|
||||||
|
inline float dtMathSqrtf(float x) { return sqrtf(x); }
|
||||||
|
inline float dtMathFloorf(float x) { return floorf(x); }
|
||||||
|
inline float dtMathCeilf(float x) { return ceilf(x); }
|
||||||
|
inline float dtMathCosf(float x) { return cosf(x); }
|
||||||
|
inline float dtMathSinf(float x) { return sinf(x); }
|
||||||
|
inline float dtMathAtan2f(float y, float x) { return atan2f(y, x); }
|
||||||
|
inline bool dtMathIsfinite(float x) { return std::isfinite(x); }
|
||||||
|
|
||||||
|
#endif
|
||||||
784
modules/detour/thirdparty/Detour/Include/DetourNavMesh.h
vendored
Normal file
784
modules/detour/thirdparty/Detour/Include/DetourNavMesh.h
vendored
Normal file
@@ -0,0 +1,784 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURNAVMESH_H
|
||||||
|
#define DETOURNAVMESH_H
|
||||||
|
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
#include "DetourStatus.h"
|
||||||
|
|
||||||
|
// Undefine (or define in a build cofnig) the following line to use 64bit polyref.
|
||||||
|
// Generally not needed, useful for very large worlds.
|
||||||
|
// Note: tiles build using 32bit refs are not compatible with 64bit refs!
|
||||||
|
//#define DT_POLYREF64 1
|
||||||
|
|
||||||
|
#ifdef DT_POLYREF64
|
||||||
|
// TODO: figure out a multiplatform version of uint64_t
|
||||||
|
// - maybe: https://code.google.com/p/msinttypes/
|
||||||
|
// - or: http://www.azillionmonkeys.com/qed/pstdint.h
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Note: If you want to use 64-bit refs, change the types of both dtPolyRef & dtTileRef.
|
||||||
|
// It is also recommended that you change dtHashRef() to a proper 64-bit hash.
|
||||||
|
|
||||||
|
/// A handle to a polygon within a navigation mesh tile.
|
||||||
|
/// @ingroup detour
|
||||||
|
#ifdef DT_POLYREF64
|
||||||
|
static const unsigned int DT_SALT_BITS = 16;
|
||||||
|
static const unsigned int DT_TILE_BITS = 28;
|
||||||
|
static const unsigned int DT_POLY_BITS = 20;
|
||||||
|
typedef uint64_t dtPolyRef;
|
||||||
|
#else
|
||||||
|
typedef unsigned int dtPolyRef;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// A handle to a tile within a navigation mesh.
|
||||||
|
/// @ingroup detour
|
||||||
|
#ifdef DT_POLYREF64
|
||||||
|
typedef uint64_t dtTileRef;
|
||||||
|
#else
|
||||||
|
typedef unsigned int dtTileRef;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// The maximum number of vertices per navigation polygon.
|
||||||
|
/// @ingroup detour
|
||||||
|
static const int DT_VERTS_PER_POLYGON = 6;
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// @name Tile Serialization Constants
|
||||||
|
/// These constants are used to detect whether a navigation tile's data
|
||||||
|
/// and state format is compatible with the current build.
|
||||||
|
///
|
||||||
|
|
||||||
|
/// A magic number used to detect compatibility of navigation tile data.
|
||||||
|
static const int DT_NAVMESH_MAGIC = 'D'<<24 | 'N'<<16 | 'A'<<8 | 'V';
|
||||||
|
|
||||||
|
/// A version number used to detect compatibility of navigation tile data.
|
||||||
|
static const int DT_NAVMESH_VERSION = 7;
|
||||||
|
|
||||||
|
/// A magic number used to detect the compatibility of navigation tile states.
|
||||||
|
static const int DT_NAVMESH_STATE_MAGIC = 'D'<<24 | 'N'<<16 | 'M'<<8 | 'S';
|
||||||
|
|
||||||
|
/// A version number used to detect compatibility of navigation tile states.
|
||||||
|
static const int DT_NAVMESH_STATE_VERSION = 1;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// A flag that indicates that an entity links to an external entity.
|
||||||
|
/// (E.g. A polygon edge is a portal that links to another polygon.)
|
||||||
|
static const unsigned short DT_EXT_LINK = 0x8000;
|
||||||
|
|
||||||
|
/// A value that indicates the entity does not link to anything.
|
||||||
|
static const unsigned int DT_NULL_LINK = 0xffffffff;
|
||||||
|
|
||||||
|
/// A flag that indicates that an off-mesh connection can be traversed in both directions. (Is bidirectional.)
|
||||||
|
static const unsigned int DT_OFFMESH_CON_BIDIR = 1;
|
||||||
|
|
||||||
|
/// The maximum number of user defined area ids.
|
||||||
|
/// @ingroup detour
|
||||||
|
static const int DT_MAX_AREAS = 64;
|
||||||
|
|
||||||
|
/// Tile flags used for various functions and fields.
|
||||||
|
/// For an example, see dtNavMesh::addTile().
|
||||||
|
enum dtTileFlags
|
||||||
|
{
|
||||||
|
/// The navigation mesh owns the tile memory and is responsible for freeing it.
|
||||||
|
DT_TILE_FREE_DATA = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Vertex flags returned by dtNavMeshQuery::findStraightPath.
|
||||||
|
enum dtStraightPathFlags
|
||||||
|
{
|
||||||
|
DT_STRAIGHTPATH_START = 0x01, ///< The vertex is the start position in the path.
|
||||||
|
DT_STRAIGHTPATH_END = 0x02, ///< The vertex is the end position in the path.
|
||||||
|
DT_STRAIGHTPATH_OFFMESH_CONNECTION = 0x04, ///< The vertex is the start of an off-mesh connection.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Options for dtNavMeshQuery::findStraightPath.
|
||||||
|
enum dtStraightPathOptions
|
||||||
|
{
|
||||||
|
DT_STRAIGHTPATH_AREA_CROSSINGS = 0x01, ///< Add a vertex at every polygon edge crossing where area changes.
|
||||||
|
DT_STRAIGHTPATH_ALL_CROSSINGS = 0x02, ///< Add a vertex at every polygon edge crossing.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Options for dtNavMeshQuery::initSlicedFindPath and updateSlicedFindPath
|
||||||
|
enum dtFindPathOptions
|
||||||
|
{
|
||||||
|
DT_FINDPATH_ANY_ANGLE = 0x02, ///< use raycasts during pathfind to "shortcut" (raycast still consider costs)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Options for dtNavMeshQuery::raycast
|
||||||
|
enum dtRaycastOptions
|
||||||
|
{
|
||||||
|
DT_RAYCAST_USE_COSTS = 0x01, ///< Raycast should calculate movement cost along the ray and fill RaycastHit::cost
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dtDetailTriEdgeFlags
|
||||||
|
{
|
||||||
|
DT_DETAIL_EDGE_BOUNDARY = 0x01, ///< Detail triangle edge is part of the poly boundary
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Limit raycasting during any angle pahfinding
|
||||||
|
/// The limit is given as a multiple of the character radius
|
||||||
|
static const float DT_RAY_CAST_LIMIT_PROPORTIONS = 50.0f;
|
||||||
|
|
||||||
|
/// Flags representing the type of a navigation mesh polygon.
|
||||||
|
enum dtPolyTypes
|
||||||
|
{
|
||||||
|
/// The polygon is a standard convex polygon that is part of the surface of the mesh.
|
||||||
|
DT_POLYTYPE_GROUND = 0,
|
||||||
|
/// The polygon is an off-mesh connection consisting of two vertices.
|
||||||
|
DT_POLYTYPE_OFFMESH_CONNECTION = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Defines a polygon within a dtMeshTile object.
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtPoly
|
||||||
|
{
|
||||||
|
/// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.)
|
||||||
|
unsigned int firstLink;
|
||||||
|
|
||||||
|
/// The indices of the polygon's vertices.
|
||||||
|
/// The actual vertices are located in dtMeshTile::verts.
|
||||||
|
unsigned short verts[DT_VERTS_PER_POLYGON];
|
||||||
|
|
||||||
|
/// Packed data representing neighbor polygons references and flags for each edge.
|
||||||
|
unsigned short neis[DT_VERTS_PER_POLYGON];
|
||||||
|
|
||||||
|
/// The user defined polygon flags.
|
||||||
|
unsigned short flags;
|
||||||
|
|
||||||
|
/// The number of vertices in the polygon.
|
||||||
|
unsigned char vertCount;
|
||||||
|
|
||||||
|
/// The bit packed area id and polygon type.
|
||||||
|
/// @note Use the structure's set and get methods to acess this value.
|
||||||
|
unsigned char areaAndtype;
|
||||||
|
|
||||||
|
/// Sets the user defined area id. [Limit: < #DT_MAX_AREAS]
|
||||||
|
inline void setArea(unsigned char a) { areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f); }
|
||||||
|
|
||||||
|
/// Sets the polygon type. (See: #dtPolyTypes.)
|
||||||
|
inline void setType(unsigned char t) { areaAndtype = (areaAndtype & 0x3f) | (t << 6); }
|
||||||
|
|
||||||
|
/// Gets the user defined area id.
|
||||||
|
inline unsigned char getArea() const { return areaAndtype & 0x3f; }
|
||||||
|
|
||||||
|
/// Gets the polygon type. (See: #dtPolyTypes)
|
||||||
|
inline unsigned char getType() const { return areaAndtype >> 6; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Defines the location of detail sub-mesh data within a dtMeshTile.
|
||||||
|
struct dtPolyDetail
|
||||||
|
{
|
||||||
|
unsigned int vertBase; ///< The offset of the vertices in the dtMeshTile::detailVerts array.
|
||||||
|
unsigned int triBase; ///< The offset of the triangles in the dtMeshTile::detailTris array.
|
||||||
|
unsigned char vertCount; ///< The number of vertices in the sub-mesh.
|
||||||
|
unsigned char triCount; ///< The number of triangles in the sub-mesh.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Defines a link between polygons.
|
||||||
|
/// @note This structure is rarely if ever used by the end user.
|
||||||
|
/// @see dtMeshTile
|
||||||
|
struct dtLink
|
||||||
|
{
|
||||||
|
dtPolyRef ref; ///< Neighbour reference. (The neighbor that is linked to.)
|
||||||
|
unsigned int next; ///< Index of the next link.
|
||||||
|
unsigned char edge; ///< Index of the polygon edge that owns this link.
|
||||||
|
unsigned char side; ///< If a boundary link, defines on which side the link is.
|
||||||
|
unsigned char bmin; ///< If a boundary link, defines the minimum sub-edge area.
|
||||||
|
unsigned char bmax; ///< If a boundary link, defines the maximum sub-edge area.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Bounding volume node.
|
||||||
|
/// @note This structure is rarely if ever used by the end user.
|
||||||
|
/// @see dtMeshTile
|
||||||
|
struct dtBVNode
|
||||||
|
{
|
||||||
|
unsigned short bmin[3]; ///< Minimum bounds of the node's AABB. [(x, y, z)]
|
||||||
|
unsigned short bmax[3]; ///< Maximum bounds of the node's AABB. [(x, y, z)]
|
||||||
|
int i; ///< The node's index. (Negative for escape sequence.)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Defines an navigation mesh off-mesh connection within a dtMeshTile object.
|
||||||
|
/// An off-mesh connection is a user defined traversable connection made up to two vertices.
|
||||||
|
struct dtOffMeshConnection
|
||||||
|
{
|
||||||
|
/// The endpoints of the connection. [(ax, ay, az, bx, by, bz)]
|
||||||
|
float pos[6];
|
||||||
|
|
||||||
|
/// The radius of the endpoints. [Limit: >= 0]
|
||||||
|
float rad;
|
||||||
|
|
||||||
|
/// The polygon reference of the connection within the tile.
|
||||||
|
unsigned short poly;
|
||||||
|
|
||||||
|
/// Link flags.
|
||||||
|
/// @note These are not the connection's user defined flags. Those are assigned via the
|
||||||
|
/// connection's dtPoly definition. These are link flags used for internal purposes.
|
||||||
|
unsigned char flags;
|
||||||
|
|
||||||
|
/// End point side.
|
||||||
|
unsigned char side;
|
||||||
|
|
||||||
|
/// The id of the offmesh connection. (User assigned when the navigation mesh is built.)
|
||||||
|
unsigned int userId;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides high level information related to a dtMeshTile object.
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtMeshHeader
|
||||||
|
{
|
||||||
|
int magic; ///< Tile magic number. (Used to identify the data format.)
|
||||||
|
int version; ///< Tile data format version number.
|
||||||
|
int x; ///< The x-position of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||||
|
int y; ///< The y-position of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||||
|
int layer; ///< The layer of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||||
|
unsigned int userId; ///< The user defined id of the tile.
|
||||||
|
int polyCount; ///< The number of polygons in the tile.
|
||||||
|
int vertCount; ///< The number of vertices in the tile.
|
||||||
|
int maxLinkCount; ///< The number of allocated links.
|
||||||
|
int detailMeshCount; ///< The number of sub-meshes in the detail mesh.
|
||||||
|
|
||||||
|
/// The number of unique vertices in the detail mesh. (In addition to the polygon vertices.)
|
||||||
|
int detailVertCount;
|
||||||
|
|
||||||
|
int detailTriCount; ///< The number of triangles in the detail mesh.
|
||||||
|
int bvNodeCount; ///< The number of bounding volume nodes. (Zero if bounding volumes are disabled.)
|
||||||
|
int offMeshConCount; ///< The number of off-mesh connections.
|
||||||
|
int offMeshBase; ///< The index of the first polygon which is an off-mesh connection.
|
||||||
|
float walkableHeight; ///< The height of the agents using the tile.
|
||||||
|
float walkableRadius; ///< The radius of the agents using the tile.
|
||||||
|
float walkableClimb; ///< The maximum climb height of the agents using the tile.
|
||||||
|
float bmin[3]; ///< The minimum bounds of the tile's AABB. [(x, y, z)]
|
||||||
|
float bmax[3]; ///< The maximum bounds of the tile's AABB. [(x, y, z)]
|
||||||
|
|
||||||
|
/// The bounding volume quantization factor.
|
||||||
|
float bvQuantFactor;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Defines a navigation mesh tile.
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtMeshTile
|
||||||
|
{
|
||||||
|
unsigned int salt; ///< Counter describing modifications to the tile.
|
||||||
|
|
||||||
|
unsigned int linksFreeList; ///< Index to the next free link.
|
||||||
|
dtMeshHeader* header; ///< The tile header.
|
||||||
|
dtPoly* polys; ///< The tile polygons. [Size: dtMeshHeader::polyCount]
|
||||||
|
float* verts; ///< The tile vertices. [Size: dtMeshHeader::vertCount]
|
||||||
|
dtLink* links; ///< The tile links. [Size: dtMeshHeader::maxLinkCount]
|
||||||
|
dtPolyDetail* detailMeshes; ///< The tile's detail sub-meshes. [Size: dtMeshHeader::detailMeshCount]
|
||||||
|
|
||||||
|
/// The detail mesh's unique vertices. [(x, y, z) * dtMeshHeader::detailVertCount]
|
||||||
|
float* detailVerts;
|
||||||
|
|
||||||
|
/// The detail mesh's triangles. [(vertA, vertB, vertC, triFlags) * dtMeshHeader::detailTriCount].
|
||||||
|
/// See dtDetailTriEdgeFlags and dtGetDetailTriEdgeFlags.
|
||||||
|
unsigned char* detailTris;
|
||||||
|
|
||||||
|
/// The tile bounding volume nodes. [Size: dtMeshHeader::bvNodeCount]
|
||||||
|
/// (Will be null if bounding volumes are disabled.)
|
||||||
|
dtBVNode* bvTree;
|
||||||
|
|
||||||
|
dtOffMeshConnection* offMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
|
||||||
|
|
||||||
|
unsigned char* data; ///< The tile data. (Not directly accessed under normal situations.)
|
||||||
|
int dataSize; ///< Size of the tile data.
|
||||||
|
int flags; ///< Tile flags. (See: #dtTileFlags)
|
||||||
|
dtMeshTile* next; ///< The next free tile, or the next tile in the spatial grid.
|
||||||
|
private:
|
||||||
|
dtMeshTile(const dtMeshTile&);
|
||||||
|
dtMeshTile& operator=(const dtMeshTile&);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Get flags for edge in detail triangle.
|
||||||
|
/// @param triFlags[in] The flags for the triangle (last component of detail vertices above).
|
||||||
|
/// @param edgeIndex[in] The index of the first vertex of the edge. For instance, if 0,
|
||||||
|
/// returns flags for edge AB.
|
||||||
|
inline int dtGetDetailTriEdgeFlags(unsigned char triFlags, int edgeIndex)
|
||||||
|
{
|
||||||
|
return (triFlags >> (edgeIndex * 2)) & 0x3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration parameters used to define multi-tile navigation meshes.
|
||||||
|
/// The values are used to allocate space during the initialization of a navigation mesh.
|
||||||
|
/// @see dtNavMesh::init()
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtNavMeshParams
|
||||||
|
{
|
||||||
|
float orig[3]; ///< The world space origin of the navigation mesh's tile space. [(x, y, z)]
|
||||||
|
float tileWidth; ///< The width of each tile. (Along the x-axis.)
|
||||||
|
float tileHeight; ///< The height of each tile. (Along the z-axis.)
|
||||||
|
int maxTiles; ///< The maximum number of tiles the navigation mesh can contain. This and maxPolys are used to calculate how many bits are needed to identify tiles and polygons uniquely.
|
||||||
|
int maxPolys; ///< The maximum number of polygons each tile can contain. This and maxTiles are used to calculate how many bits are needed to identify tiles and polygons uniquely.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A navigation mesh based on tiles of convex polygons.
|
||||||
|
/// @ingroup detour
|
||||||
|
class dtNavMesh
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dtNavMesh();
|
||||||
|
~dtNavMesh();
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// @name Initialization and Tile Management
|
||||||
|
|
||||||
|
/// Initializes the navigation mesh for tiled use.
|
||||||
|
/// @param[in] params Initialization parameters.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus init(const dtNavMeshParams* params);
|
||||||
|
|
||||||
|
/// Initializes the navigation mesh for single tile use.
|
||||||
|
/// @param[in] data Data of the new tile. (See: #dtCreateNavMeshData)
|
||||||
|
/// @param[in] dataSize The data size of the new tile.
|
||||||
|
/// @param[in] flags The tile flags. (See: #dtTileFlags)
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
/// @see dtCreateNavMeshData
|
||||||
|
dtStatus init(unsigned char* data, const int dataSize, const int flags);
|
||||||
|
|
||||||
|
/// The navigation mesh initialization params.
|
||||||
|
const dtNavMeshParams* getParams() const;
|
||||||
|
|
||||||
|
/// Adds a tile to the navigation mesh.
|
||||||
|
/// @param[in] data Data for the new tile mesh. (See: #dtCreateNavMeshData)
|
||||||
|
/// @param[in] dataSize Data size of the new tile mesh.
|
||||||
|
/// @param[in] flags Tile flags. (See: #dtTileFlags)
|
||||||
|
/// @param[in] lastRef The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0]
|
||||||
|
/// @param[out] result The tile reference. (If the tile was succesfully added.) [opt]
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result);
|
||||||
|
|
||||||
|
/// Removes the specified tile from the navigation mesh.
|
||||||
|
/// @param[in] ref The reference of the tile to remove.
|
||||||
|
/// @param[out] data Data associated with deleted tile.
|
||||||
|
/// @param[out] dataSize Size of the data associated with deleted tile.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus removeTile(dtTileRef ref, unsigned char** data, int* dataSize);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// @name Query Functions
|
||||||
|
|
||||||
|
/// Calculates the tile grid location for the specified world position.
|
||||||
|
/// @param[in] pos The world position for the query. [(x, y, z)]
|
||||||
|
/// @param[out] tx The tile's x-location. (x, y)
|
||||||
|
/// @param[out] ty The tile's y-location. (x, y)
|
||||||
|
void calcTileLoc(const float* pos, int* tx, int* ty) const;
|
||||||
|
|
||||||
|
/// Gets the tile at the specified grid location.
|
||||||
|
/// @param[in] x The tile's x-location. (x, y, layer)
|
||||||
|
/// @param[in] y The tile's y-location. (x, y, layer)
|
||||||
|
/// @param[in] layer The tile's layer. (x, y, layer)
|
||||||
|
/// @return The tile, or null if the tile does not exist.
|
||||||
|
const dtMeshTile* getTileAt(const int x, const int y, const int layer) const;
|
||||||
|
|
||||||
|
/// Gets all tiles at the specified grid location. (All layers.)
|
||||||
|
/// @param[in] x The tile's x-location. (x, y)
|
||||||
|
/// @param[in] y The tile's y-location. (x, y)
|
||||||
|
/// @param[out] tiles A pointer to an array of tiles that will hold the result.
|
||||||
|
/// @param[in] maxTiles The maximum tiles the tiles parameter can hold.
|
||||||
|
/// @return The number of tiles returned in the tiles array.
|
||||||
|
int getTilesAt(const int x, const int y,
|
||||||
|
dtMeshTile const** tiles, const int maxTiles) const;
|
||||||
|
|
||||||
|
/// Gets the tile reference for the tile at specified grid location.
|
||||||
|
/// @param[in] x The tile's x-location. (x, y, layer)
|
||||||
|
/// @param[in] y The tile's y-location. (x, y, layer)
|
||||||
|
/// @param[in] layer The tile's layer. (x, y, layer)
|
||||||
|
/// @return The tile reference of the tile, or 0 if there is none.
|
||||||
|
dtTileRef getTileRefAt(int x, int y, int layer) const;
|
||||||
|
|
||||||
|
/// Gets the tile reference for the specified tile.
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @return The tile reference of the tile.
|
||||||
|
dtTileRef getTileRef(const dtMeshTile* tile) const;
|
||||||
|
|
||||||
|
/// Gets the tile for the specified tile reference.
|
||||||
|
/// @param[in] ref The tile reference of the tile to retrieve.
|
||||||
|
/// @return The tile for the specified reference, or null if the
|
||||||
|
/// reference is invalid.
|
||||||
|
const dtMeshTile* getTileByRef(dtTileRef ref) const;
|
||||||
|
|
||||||
|
/// The maximum number of tiles supported by the navigation mesh.
|
||||||
|
/// @return The maximum number of tiles supported by the navigation mesh.
|
||||||
|
int getMaxTiles() const;
|
||||||
|
|
||||||
|
/// Gets the tile at the specified index.
|
||||||
|
/// @param[in] i The tile index. [Limit: 0 >= index < #getMaxTiles()]
|
||||||
|
/// @return The tile at the specified index.
|
||||||
|
const dtMeshTile* getTile(int i) const;
|
||||||
|
|
||||||
|
/// Gets the tile and polygon for the specified polygon reference.
|
||||||
|
/// @param[in] ref The reference for the a polygon.
|
||||||
|
/// @param[out] tile The tile containing the polygon.
|
||||||
|
/// @param[out] poly The polygon.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus getTileAndPolyByRef(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
||||||
|
|
||||||
|
/// Returns the tile and polygon for the specified polygon reference.
|
||||||
|
/// @param[in] ref A known valid reference for a polygon.
|
||||||
|
/// @param[out] tile The tile containing the polygon.
|
||||||
|
/// @param[out] poly The polygon.
|
||||||
|
void getTileAndPolyByRefUnsafe(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
||||||
|
|
||||||
|
/// Checks the validity of a polygon reference.
|
||||||
|
/// @param[in] ref The polygon reference to check.
|
||||||
|
/// @return True if polygon reference is valid for the navigation mesh.
|
||||||
|
bool isValidPolyRef(dtPolyRef ref) const;
|
||||||
|
|
||||||
|
/// Gets the polygon reference for the tile's base polygon.
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @return The polygon reference for the base polygon in the specified tile.
|
||||||
|
dtPolyRef getPolyRefBase(const dtMeshTile* tile) const;
|
||||||
|
|
||||||
|
/// Gets the endpoints for an off-mesh connection, ordered by "direction of travel".
|
||||||
|
/// @param[in] prevRef The reference of the polygon before the connection.
|
||||||
|
/// @param[in] polyRef The reference of the off-mesh connection polygon.
|
||||||
|
/// @param[out] startPos The start position of the off-mesh connection. [(x, y, z)]
|
||||||
|
/// @param[out] endPos The end position of the off-mesh connection. [(x, y, z)]
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const;
|
||||||
|
|
||||||
|
/// Gets the specified off-mesh connection.
|
||||||
|
/// @param[in] ref The polygon reference of the off-mesh connection.
|
||||||
|
/// @return The specified off-mesh connection, or null if the polygon reference is not valid.
|
||||||
|
const dtOffMeshConnection* getOffMeshConnectionByRef(dtPolyRef ref) const;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// @name State Management
|
||||||
|
/// These functions do not effect #dtTileRef or #dtPolyRef's.
|
||||||
|
|
||||||
|
/// Sets the user defined flags for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[in] flags The new flags for the polygon.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus setPolyFlags(dtPolyRef ref, unsigned short flags);
|
||||||
|
|
||||||
|
/// Gets the user defined flags for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[out] resultFlags The polygon flags.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) const;
|
||||||
|
|
||||||
|
/// Sets the user defined area for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[in] area The new area id for the polygon. [Limit: < #DT_MAX_AREAS]
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus setPolyArea(dtPolyRef ref, unsigned char area);
|
||||||
|
|
||||||
|
/// Gets the user defined area for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[out] resultArea The area id for the polygon.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus getPolyArea(dtPolyRef ref, unsigned char* resultArea) const;
|
||||||
|
|
||||||
|
/// Gets the size of the buffer required by #storeTileState to store the specified tile's state.
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @return The size of the buffer required to store the state.
|
||||||
|
int getTileStateSize(const dtMeshTile* tile) const;
|
||||||
|
|
||||||
|
/// Stores the non-structural state of the tile in the specified buffer. (Flags, area ids, etc.)
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @param[out] data The buffer to store the tile's state in.
|
||||||
|
/// @param[in] maxDataSize The size of the data buffer. [Limit: >= #getTileStateSize]
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus storeTileState(const dtMeshTile* tile, unsigned char* data, const int maxDataSize) const;
|
||||||
|
|
||||||
|
/// Restores the state of the tile.
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @param[in] data The new state. (Obtained from #storeTileState.)
|
||||||
|
/// @param[in] maxDataSize The size of the state within the data buffer.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// @name Encoding and Decoding
|
||||||
|
/// These functions are generally meant for internal use only.
|
||||||
|
|
||||||
|
/// Derives a standard polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] salt The tile's salt value.
|
||||||
|
/// @param[in] it The index of the tile.
|
||||||
|
/// @param[in] ip The index of the polygon within the tile.
|
||||||
|
inline dtPolyRef encodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const
|
||||||
|
{
|
||||||
|
#ifdef DT_POLYREF64
|
||||||
|
return ((dtPolyRef)salt << (DT_POLY_BITS+DT_TILE_BITS)) | ((dtPolyRef)it << DT_POLY_BITS) | (dtPolyRef)ip;
|
||||||
|
#else
|
||||||
|
return ((dtPolyRef)salt << (m_polyBits+m_tileBits)) | ((dtPolyRef)it << m_polyBits) | (dtPolyRef)ip;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes a standard polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference to decode.
|
||||||
|
/// @param[out] salt The tile's salt value.
|
||||||
|
/// @param[out] it The index of the tile.
|
||||||
|
/// @param[out] ip The index of the polygon within the tile.
|
||||||
|
/// @see #encodePolyId
|
||||||
|
inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const
|
||||||
|
{
|
||||||
|
#ifdef DT_POLYREF64
|
||||||
|
const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
|
||||||
|
const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
|
||||||
|
const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
|
||||||
|
salt = (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
|
||||||
|
it = (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
|
||||||
|
ip = (unsigned int)(ref & polyMask);
|
||||||
|
#else
|
||||||
|
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
||||||
|
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
||||||
|
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
||||||
|
salt = (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
||||||
|
it = (unsigned int)((ref >> m_polyBits) & tileMask);
|
||||||
|
ip = (unsigned int)(ref & polyMask);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts a tile's salt value from the specified polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @see #encodePolyId
|
||||||
|
inline unsigned int decodePolyIdSalt(dtPolyRef ref) const
|
||||||
|
{
|
||||||
|
#ifdef DT_POLYREF64
|
||||||
|
const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
|
||||||
|
return (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
|
||||||
|
#else
|
||||||
|
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
||||||
|
return (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the tile's index from the specified polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @see #encodePolyId
|
||||||
|
inline unsigned int decodePolyIdTile(dtPolyRef ref) const
|
||||||
|
{
|
||||||
|
#ifdef DT_POLYREF64
|
||||||
|
const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
|
||||||
|
return (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
|
||||||
|
#else
|
||||||
|
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
||||||
|
return (unsigned int)((ref >> m_polyBits) & tileMask);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the polygon's index (within its tile) from the specified polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @see #encodePolyId
|
||||||
|
inline unsigned int decodePolyIdPoly(dtPolyRef ref) const
|
||||||
|
{
|
||||||
|
#ifdef DT_POLYREF64
|
||||||
|
const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
|
||||||
|
return (unsigned int)(ref & polyMask);
|
||||||
|
#else
|
||||||
|
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
||||||
|
return (unsigned int)(ref & polyMask);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Explicitly disabled copy constructor and copy assignment operator.
|
||||||
|
dtNavMesh(const dtNavMesh&);
|
||||||
|
dtNavMesh& operator=(const dtNavMesh&);
|
||||||
|
|
||||||
|
/// Returns pointer to tile in the tile array.
|
||||||
|
dtMeshTile* getTile(int i);
|
||||||
|
|
||||||
|
/// Returns neighbour tile based on side.
|
||||||
|
int getTilesAt(const int x, const int y,
|
||||||
|
dtMeshTile** tiles, const int maxTiles) const;
|
||||||
|
|
||||||
|
/// Returns neighbour tile based on side.
|
||||||
|
int getNeighbourTilesAt(const int x, const int y, const int side,
|
||||||
|
dtMeshTile** tiles, const int maxTiles) const;
|
||||||
|
|
||||||
|
/// Returns all polygons in neighbour tile based on portal defined by the segment.
|
||||||
|
int findConnectingPolys(const float* va, const float* vb,
|
||||||
|
const dtMeshTile* tile, int side,
|
||||||
|
dtPolyRef* con, float* conarea, int maxcon) const;
|
||||||
|
|
||||||
|
/// Builds internal polygons links for a tile.
|
||||||
|
void connectIntLinks(dtMeshTile* tile);
|
||||||
|
/// Builds internal polygons links for a tile.
|
||||||
|
void baseOffMeshLinks(dtMeshTile* tile);
|
||||||
|
|
||||||
|
/// Builds external polygon links for a tile.
|
||||||
|
void connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||||
|
/// Builds external polygon links for a tile.
|
||||||
|
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||||
|
|
||||||
|
/// Removes external links at specified side.
|
||||||
|
void unconnectLinks(dtMeshTile* tile, dtMeshTile* target);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed for off-mesh connection finding.
|
||||||
|
|
||||||
|
/// Queries polygons within a tile.
|
||||||
|
int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
||||||
|
dtPolyRef* polys, const int maxPolys) const;
|
||||||
|
/// Find nearest polygon within a tile.
|
||||||
|
dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center,
|
||||||
|
const float* halfExtents, float* nearestPt) const;
|
||||||
|
/// Returns whether position is over the poly and the height at the position if so.
|
||||||
|
bool getPolyHeight(const dtMeshTile* tile, const dtPoly* poly, const float* pos, float* height) const;
|
||||||
|
/// Returns closest point on polygon.
|
||||||
|
void closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
|
||||||
|
|
||||||
|
dtNavMeshParams m_params; ///< Current initialization params. TODO: do not store this info twice.
|
||||||
|
float m_orig[3]; ///< Origin of the tile (0,0)
|
||||||
|
float m_tileWidth, m_tileHeight; ///< Dimensions of each tile.
|
||||||
|
int m_maxTiles; ///< Max number of tiles.
|
||||||
|
int m_tileLutSize; ///< Tile hash lookup size (must be pot).
|
||||||
|
int m_tileLutMask; ///< Tile hash lookup mask.
|
||||||
|
|
||||||
|
dtMeshTile** m_posLookup; ///< Tile hash lookup.
|
||||||
|
dtMeshTile* m_nextFree; ///< Freelist of tiles.
|
||||||
|
dtMeshTile* m_tiles; ///< List of tiles.
|
||||||
|
|
||||||
|
#ifndef DT_POLYREF64
|
||||||
|
unsigned int m_saltBits; ///< Number of salt bits in the tile ID.
|
||||||
|
unsigned int m_tileBits; ///< Number of tile bits in the tile ID.
|
||||||
|
unsigned int m_polyBits; ///< Number of poly bits in the tile ID.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
friend class dtNavMeshQuery;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Allocates a navigation mesh object using the Detour allocator.
|
||||||
|
/// @return A navigation mesh that is ready for initialization, or null on failure.
|
||||||
|
/// @ingroup detour
|
||||||
|
dtNavMesh* dtAllocNavMesh();
|
||||||
|
|
||||||
|
/// Frees the specified navigation mesh object using the Detour allocator.
|
||||||
|
/// @param[in] navmesh A navigation mesh allocated using #dtAllocNavMesh
|
||||||
|
/// @ingroup detour
|
||||||
|
void dtFreeNavMesh(dtNavMesh* navmesh);
|
||||||
|
|
||||||
|
#endif // DETOURNAVMESH_H
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// This section contains detailed documentation for members that don't have
|
||||||
|
// a source file. It reduces clutter in the main section of the header.
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
@typedef dtPolyRef
|
||||||
|
@par
|
||||||
|
|
||||||
|
Polygon references are subject to the same invalidate/preserve/restore
|
||||||
|
rules that apply to #dtTileRef's. If the #dtTileRef for the polygon's
|
||||||
|
tile changes, the polygon reference becomes invalid.
|
||||||
|
|
||||||
|
Changing a polygon's flags, area id, etc. does not impact its polygon
|
||||||
|
reference.
|
||||||
|
|
||||||
|
@typedef dtTileRef
|
||||||
|
@par
|
||||||
|
|
||||||
|
The following changes will invalidate a tile reference:
|
||||||
|
|
||||||
|
- The referenced tile has been removed from the navigation mesh.
|
||||||
|
- The navigation mesh has been initialized using a different set
|
||||||
|
of #dtNavMeshParams.
|
||||||
|
|
||||||
|
A tile reference is preserved/restored if the tile is added to a navigation
|
||||||
|
mesh initialized with the original #dtNavMeshParams and is added at the
|
||||||
|
original reference location. (E.g. The lastRef parameter is used with
|
||||||
|
dtNavMesh::addTile.)
|
||||||
|
|
||||||
|
Basically, if the storage structure of a tile changes, its associated
|
||||||
|
tile reference changes.
|
||||||
|
|
||||||
|
|
||||||
|
@var unsigned short dtPoly::neis[DT_VERTS_PER_POLYGON]
|
||||||
|
@par
|
||||||
|
|
||||||
|
Each entry represents data for the edge starting at the vertex of the same index.
|
||||||
|
E.g. The entry at index n represents the edge data for vertex[n] to vertex[n+1].
|
||||||
|
|
||||||
|
A value of zero indicates the edge has no polygon connection. (It makes up the
|
||||||
|
border of the navigation mesh.)
|
||||||
|
|
||||||
|
The information can be extracted as follows:
|
||||||
|
@code
|
||||||
|
neighborRef = neis[n] & 0xff; // Get the neighbor polygon reference.
|
||||||
|
|
||||||
|
if (neis[n] & #DT_EX_LINK)
|
||||||
|
{
|
||||||
|
// The edge is an external (portal) edge.
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@var float dtMeshHeader::bvQuantFactor
|
||||||
|
@par
|
||||||
|
|
||||||
|
This value is used for converting between world and bounding volume coordinates.
|
||||||
|
For example:
|
||||||
|
@code
|
||||||
|
const float cs = 1.0f / tile->header->bvQuantFactor;
|
||||||
|
const dtBVNode* n = &tile->bvTree[i];
|
||||||
|
if (n->i >= 0)
|
||||||
|
{
|
||||||
|
// This is a leaf node.
|
||||||
|
float worldMinX = tile->header->bmin[0] + n->bmin[0]*cs;
|
||||||
|
float worldMinY = tile->header->bmin[0] + n->bmin[1]*cs;
|
||||||
|
// Etc...
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@struct dtMeshTile
|
||||||
|
@par
|
||||||
|
|
||||||
|
Tiles generally only exist within the context of a dtNavMesh object.
|
||||||
|
|
||||||
|
Some tile content is optional. For example, a tile may not contain any
|
||||||
|
off-mesh connections. In this case the associated pointer will be null.
|
||||||
|
|
||||||
|
If a detail mesh exists it will share vertices with the base polygon mesh.
|
||||||
|
Only the vertices unique to the detail mesh will be stored in #detailVerts.
|
||||||
|
|
||||||
|
@warning Tiles returned by a dtNavMesh object are not guarenteed to be populated.
|
||||||
|
For example: The tile at a location might not have been loaded yet, or may have been removed.
|
||||||
|
In this case, pointers will be null. So if in doubt, check the polygon count in the
|
||||||
|
tile's header to determine if a tile has polygons defined.
|
||||||
|
|
||||||
|
@var float dtOffMeshConnection::pos[6]
|
||||||
|
@par
|
||||||
|
|
||||||
|
For a properly built navigation mesh, vertex A will always be within the bounds of the mesh.
|
||||||
|
Vertex B is not required to be within the bounds of the mesh.
|
||||||
|
|
||||||
|
*/
|
||||||
149
modules/detour/thirdparty/Detour/Include/DetourNavMeshBuilder.h
vendored
Normal file
149
modules/detour/thirdparty/Detour/Include/DetourNavMeshBuilder.h
vendored
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURNAVMESHBUILDER_H
|
||||||
|
#define DETOURNAVMESHBUILDER_H
|
||||||
|
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
|
||||||
|
/// Represents the source data used to build an navigation mesh tile.
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtNavMeshCreateParams
|
||||||
|
{
|
||||||
|
|
||||||
|
/// @name Polygon Mesh Attributes
|
||||||
|
/// Used to create the base navigation graph.
|
||||||
|
/// See #rcPolyMesh for details related to these attributes.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
const unsigned short* verts; ///< The polygon mesh vertices. [(x, y, z) * #vertCount] [Unit: vx]
|
||||||
|
int vertCount; ///< The number vertices in the polygon mesh. [Limit: >= 3]
|
||||||
|
const unsigned short* polys; ///< The polygon data. [Size: #polyCount * 2 * #nvp]
|
||||||
|
const unsigned short* polyFlags; ///< The user defined flags assigned to each polygon. [Size: #polyCount]
|
||||||
|
const unsigned char* polyAreas; ///< The user defined area ids assigned to each polygon. [Size: #polyCount]
|
||||||
|
int polyCount; ///< Number of polygons in the mesh. [Limit: >= 1]
|
||||||
|
int nvp; ///< Number maximum number of vertices per polygon. [Limit: >= 3]
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Height Detail Attributes (Optional)
|
||||||
|
/// See #rcPolyMeshDetail for details related to these attributes.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
const unsigned int* detailMeshes; ///< The height detail sub-mesh data. [Size: 4 * #polyCount]
|
||||||
|
const float* detailVerts; ///< The detail mesh vertices. [Size: 3 * #detailVertsCount] [Unit: wu]
|
||||||
|
int detailVertsCount; ///< The number of vertices in the detail mesh.
|
||||||
|
const unsigned char* detailTris; ///< The detail mesh triangles. [Size: 4 * #detailTriCount]
|
||||||
|
int detailTriCount; ///< The number of triangles in the detail mesh.
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Off-Mesh Connections Attributes (Optional)
|
||||||
|
/// Used to define a custom point-to-point edge within the navigation graph, an
|
||||||
|
/// off-mesh connection is a user defined traversable connection made up to two vertices,
|
||||||
|
/// at least one of which resides within a navigation mesh polygon.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Off-mesh connection vertices. [(ax, ay, az, bx, by, bz) * #offMeshConCount] [Unit: wu]
|
||||||
|
const float* offMeshConVerts;
|
||||||
|
/// Off-mesh connection radii. [Size: #offMeshConCount] [Unit: wu]
|
||||||
|
const float* offMeshConRad;
|
||||||
|
/// User defined flags assigned to the off-mesh connections. [Size: #offMeshConCount]
|
||||||
|
const unsigned short* offMeshConFlags;
|
||||||
|
/// User defined area ids assigned to the off-mesh connections. [Size: #offMeshConCount]
|
||||||
|
const unsigned char* offMeshConAreas;
|
||||||
|
/// The permitted travel direction of the off-mesh connections. [Size: #offMeshConCount]
|
||||||
|
///
|
||||||
|
/// 0 = Travel only from endpoint A to endpoint B.<br/>
|
||||||
|
/// #DT_OFFMESH_CON_BIDIR = Bidirectional travel.
|
||||||
|
const unsigned char* offMeshConDir;
|
||||||
|
/// The user defined ids of the off-mesh connection. [Size: #offMeshConCount]
|
||||||
|
const unsigned int* offMeshConUserID;
|
||||||
|
/// The number of off-mesh connections. [Limit: >= 0]
|
||||||
|
int offMeshConCount;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Tile Attributes
|
||||||
|
/// @note The tile grid/layer data can be left at zero if the destination is a single tile mesh.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
unsigned int userId; ///< The user defined id of the tile.
|
||||||
|
int tileX; ///< The tile's x-grid location within the multi-tile destination mesh. (Along the x-axis.)
|
||||||
|
int tileY; ///< The tile's y-grid location within the multi-tile desitation mesh. (Along the z-axis.)
|
||||||
|
int tileLayer; ///< The tile's layer within the layered destination mesh. [Limit: >= 0] (Along the y-axis.)
|
||||||
|
float bmin[3]; ///< The minimum bounds of the tile. [(x, y, z)] [Unit: wu]
|
||||||
|
float bmax[3]; ///< The maximum bounds of the tile. [(x, y, z)] [Unit: wu]
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name General Configuration Attributes
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
float walkableHeight; ///< The agent height. [Unit: wu]
|
||||||
|
float walkableRadius; ///< The agent radius. [Unit: wu]
|
||||||
|
float walkableClimb; ///< The agent maximum traversable ledge. (Up/Down) [Unit: wu]
|
||||||
|
float cs; ///< The xz-plane cell size of the polygon mesh. [Limit: > 0] [Unit: wu]
|
||||||
|
float ch; ///< The y-axis cell height of the polygon mesh. [Limit: > 0] [Unit: wu]
|
||||||
|
|
||||||
|
/// True if a bounding volume tree should be built for the tile.
|
||||||
|
/// @note The BVTree is not normally needed for layered navigation meshes.
|
||||||
|
bool buildBvTree;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Builds navigation mesh tile data from the provided tile creation data.
|
||||||
|
/// @ingroup detour
|
||||||
|
/// @param[in] params Tile creation data.
|
||||||
|
/// @param[out] outData The resulting tile data.
|
||||||
|
/// @param[out] outDataSize The size of the tile data array.
|
||||||
|
/// @return True if the tile data was successfully created.
|
||||||
|
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize);
|
||||||
|
|
||||||
|
/// Swaps the endianess of the tile data's header (#dtMeshHeader).
|
||||||
|
/// @param[in,out] data The tile data array.
|
||||||
|
/// @param[in] dataSize The size of the data array.
|
||||||
|
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int dataSize);
|
||||||
|
|
||||||
|
/// Swaps endianess of the tile data.
|
||||||
|
/// @param[in,out] data The tile data array.
|
||||||
|
/// @param[in] dataSize The size of the data array.
|
||||||
|
bool dtNavMeshDataSwapEndian(unsigned char* data, const int dataSize);
|
||||||
|
|
||||||
|
#endif // DETOURNAVMESHBUILDER_H
|
||||||
|
|
||||||
|
// This section contains detailed documentation for members that don't have
|
||||||
|
// a source file. It reduces clutter in the main section of the header.
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
@struct dtNavMeshCreateParams
|
||||||
|
@par
|
||||||
|
|
||||||
|
This structure is used to marshal data between the Recast mesh generation pipeline and Detour navigation components.
|
||||||
|
|
||||||
|
See the rcPolyMesh and rcPolyMeshDetail documentation for detailed information related to mesh structure.
|
||||||
|
|
||||||
|
Units are usually in voxels (vx) or world units (wu). The units for voxels, grid size, and cell size
|
||||||
|
are all based on the values of #cs and #ch.
|
||||||
|
|
||||||
|
The standard navigation mesh build process is to create tile data using dtCreateNavMeshData, then add the tile
|
||||||
|
to a navigation mesh using either the dtNavMesh single tile <tt>init()</tt> function or the dtNavMesh::addTile()
|
||||||
|
function.
|
||||||
|
|
||||||
|
@see dtCreateNavMeshData
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
589
modules/detour/thirdparty/Detour/Include/DetourNavMeshQuery.h
vendored
Normal file
589
modules/detour/thirdparty/Detour/Include/DetourNavMeshQuery.h
vendored
Normal file
@@ -0,0 +1,589 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURNAVMESHQUERY_H
|
||||||
|
#define DETOURNAVMESHQUERY_H
|
||||||
|
|
||||||
|
#include "DetourNavMesh.h"
|
||||||
|
#include "DetourStatus.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter.
|
||||||
|
// On certain platforms indirect or virtual function call is expensive. The default
|
||||||
|
// setting is to use non-virtual functions, the actual implementations of the functions
|
||||||
|
// are declared as inline for maximum speed.
|
||||||
|
|
||||||
|
//#define DT_VIRTUAL_QUERYFILTER 1
|
||||||
|
|
||||||
|
/// Defines polygon filtering and traversal costs for navigation mesh query operations.
|
||||||
|
/// @ingroup detour
|
||||||
|
class dtQueryFilter
|
||||||
|
{
|
||||||
|
float m_areaCost[DT_MAX_AREAS]; ///< Cost per area type. (Used by default implementation.)
|
||||||
|
unsigned short m_includeFlags; ///< Flags for polygons that can be visited. (Used by default implementation.)
|
||||||
|
unsigned short m_excludeFlags; ///< Flags for polygons that should not be visted. (Used by default implementation.)
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtQueryFilter();
|
||||||
|
|
||||||
|
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||||
|
virtual ~dtQueryFilter() { }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Returns true if the polygon can be visited. (I.e. Is traversable.)
|
||||||
|
/// @param[in] ref The reference id of the polygon test.
|
||||||
|
/// @param[in] tile The tile containing the polygon.
|
||||||
|
/// @param[in] poly The polygon to test.
|
||||||
|
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||||
|
virtual bool passFilter(const dtPolyRef ref,
|
||||||
|
const dtMeshTile* tile,
|
||||||
|
const dtPoly* poly) const;
|
||||||
|
#else
|
||||||
|
bool passFilter(const dtPolyRef ref,
|
||||||
|
const dtMeshTile* tile,
|
||||||
|
const dtPoly* poly) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Returns cost to move from the beginning to the end of a line segment
|
||||||
|
/// that is fully contained within a polygon.
|
||||||
|
/// @param[in] pa The start position on the edge of the previous and current polygon. [(x, y, z)]
|
||||||
|
/// @param[in] pb The end position on the edge of the current and next polygon. [(x, y, z)]
|
||||||
|
/// @param[in] prevRef The reference id of the previous polygon. [opt]
|
||||||
|
/// @param[in] prevTile The tile containing the previous polygon. [opt]
|
||||||
|
/// @param[in] prevPoly The previous polygon. [opt]
|
||||||
|
/// @param[in] curRef The reference id of the current polygon.
|
||||||
|
/// @param[in] curTile The tile containing the current polygon.
|
||||||
|
/// @param[in] curPoly The current polygon.
|
||||||
|
/// @param[in] nextRef The refernece id of the next polygon. [opt]
|
||||||
|
/// @param[in] nextTile The tile containing the next polygon. [opt]
|
||||||
|
/// @param[in] nextPoly The next polygon. [opt]
|
||||||
|
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||||
|
virtual float getCost(const float* pa, const float* pb,
|
||||||
|
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
||||||
|
const dtPolyRef curRef, const dtMeshTile* curTile, const dtPoly* curPoly,
|
||||||
|
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
||||||
|
#else
|
||||||
|
float getCost(const float* pa, const float* pb,
|
||||||
|
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
||||||
|
const dtPolyRef curRef, const dtMeshTile* curTile, const dtPoly* curPoly,
|
||||||
|
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @name Getters and setters for the default implementation data.
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/// Returns the traversal cost of the area.
|
||||||
|
/// @param[in] i The id of the area.
|
||||||
|
/// @returns The traversal cost of the area.
|
||||||
|
inline float getAreaCost(const int i) const { return m_areaCost[i]; }
|
||||||
|
|
||||||
|
/// Sets the traversal cost of the area.
|
||||||
|
/// @param[in] i The id of the area.
|
||||||
|
/// @param[in] cost The new cost of traversing the area.
|
||||||
|
inline void setAreaCost(const int i, const float cost) { m_areaCost[i] = cost; }
|
||||||
|
|
||||||
|
/// Returns the include flags for the filter.
|
||||||
|
/// Any polygons that include one or more of these flags will be
|
||||||
|
/// included in the operation.
|
||||||
|
inline unsigned short getIncludeFlags() const { return m_includeFlags; }
|
||||||
|
|
||||||
|
/// Sets the include flags for the filter.
|
||||||
|
/// @param[in] flags The new flags.
|
||||||
|
inline void setIncludeFlags(const unsigned short flags) { m_includeFlags = flags; }
|
||||||
|
|
||||||
|
/// Returns the exclude flags for the filter.
|
||||||
|
/// Any polygons that include one ore more of these flags will be
|
||||||
|
/// excluded from the operation.
|
||||||
|
inline unsigned short getExcludeFlags() const { return m_excludeFlags; }
|
||||||
|
|
||||||
|
/// Sets the exclude flags for the filter.
|
||||||
|
/// @param[in] flags The new flags.
|
||||||
|
inline void setExcludeFlags(const unsigned short flags) { m_excludeFlags = flags; }
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides information about raycast hit
|
||||||
|
/// filled by dtNavMeshQuery::raycast
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtRaycastHit
|
||||||
|
{
|
||||||
|
/// The hit parameter. (FLT_MAX if no wall hit.)
|
||||||
|
float t;
|
||||||
|
|
||||||
|
/// hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
||||||
|
float hitNormal[3];
|
||||||
|
|
||||||
|
/// The index of the edge on the final polygon where the wall was hit.
|
||||||
|
int hitEdgeIndex;
|
||||||
|
|
||||||
|
/// Pointer to an array of reference ids of the visited polygons. [opt]
|
||||||
|
dtPolyRef* path;
|
||||||
|
|
||||||
|
/// The number of visited polygons. [opt]
|
||||||
|
int pathCount;
|
||||||
|
|
||||||
|
/// The maximum number of polygons the @p path array can hold.
|
||||||
|
int maxPath;
|
||||||
|
|
||||||
|
/// The cost of the path until hit.
|
||||||
|
float pathCost;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides custom polygon query behavior.
|
||||||
|
/// Used by dtNavMeshQuery::queryPolygons.
|
||||||
|
/// @ingroup detour
|
||||||
|
class dtPolyQuery
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~dtPolyQuery() { }
|
||||||
|
|
||||||
|
/// Called for each batch of unique polygons touched by the search area in dtNavMeshQuery::queryPolygons.
|
||||||
|
/// This can be called multiple times for a single query.
|
||||||
|
virtual void process(const dtMeshTile* tile, dtPoly** polys, dtPolyRef* refs, int count) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides the ability to perform pathfinding related queries against
|
||||||
|
/// a navigation mesh.
|
||||||
|
/// @ingroup detour
|
||||||
|
class dtNavMeshQuery
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dtNavMeshQuery();
|
||||||
|
~dtNavMeshQuery();
|
||||||
|
|
||||||
|
/// Initializes the query object.
|
||||||
|
/// @param[in] nav Pointer to the dtNavMesh object to use for all queries.
|
||||||
|
/// @param[in] maxNodes Maximum number of search nodes. [Limits: 0 < value <= 65535]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus init(const dtNavMesh* nav, const int maxNodes);
|
||||||
|
|
||||||
|
/// @name Standard Pathfinding Functions
|
||||||
|
// /@{
|
||||||
|
|
||||||
|
/// Finds a path from the start polygon to the end polygon.
|
||||||
|
/// @param[in] startRef The refrence id of the start polygon.
|
||||||
|
/// @param[in] endRef The reference id of the end polygon.
|
||||||
|
/// @param[in] startPos A position within the start polygon. [(x, y, z)]
|
||||||
|
/// @param[in] endPos A position within the end polygon. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||||
|
/// [(polyRef) * @p pathCount]
|
||||||
|
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||||
|
/// @param[in] maxPath The maximum number of polygons the @p path array can hold. [Limit: >= 1]
|
||||||
|
dtStatus findPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||||
|
const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* path, int* pathCount, const int maxPath) const;
|
||||||
|
|
||||||
|
/// Finds the straight path from the start to the end position within the polygon corridor.
|
||||||
|
/// @param[in] startPos Path start position. [(x, y, z)]
|
||||||
|
/// @param[in] endPos Path end position. [(x, y, z)]
|
||||||
|
/// @param[in] path An array of polygon references that represent the path corridor.
|
||||||
|
/// @param[in] pathSize The number of polygons in the @p path array.
|
||||||
|
/// @param[out] straightPath Points describing the straight path. [(x, y, z) * @p straightPathCount].
|
||||||
|
/// @param[out] straightPathFlags Flags describing each point. (See: #dtStraightPathFlags) [opt]
|
||||||
|
/// @param[out] straightPathRefs The reference id of the polygon that is being entered at each point. [opt]
|
||||||
|
/// @param[out] straightPathCount The number of points in the straight path.
|
||||||
|
/// @param[in] maxStraightPath The maximum number of points the straight path arrays can hold. [Limit: > 0]
|
||||||
|
/// @param[in] options Query options. (see: #dtStraightPathOptions)
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findStraightPath(const float* startPos, const float* endPos,
|
||||||
|
const dtPolyRef* path, const int pathSize,
|
||||||
|
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||||
|
int* straightPathCount, const int maxStraightPath, const int options = 0) const;
|
||||||
|
|
||||||
|
///@}
|
||||||
|
/// @name Sliced Pathfinding Functions
|
||||||
|
/// Common use case:
|
||||||
|
/// -# Call initSlicedFindPath() to initialize the sliced path query.
|
||||||
|
/// -# Call updateSlicedFindPath() until it returns complete.
|
||||||
|
/// -# Call finalizeSlicedFindPath() to get the path.
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/// Intializes a sliced path query.
|
||||||
|
/// @param[in] startRef The refrence id of the start polygon.
|
||||||
|
/// @param[in] endRef The reference id of the end polygon.
|
||||||
|
/// @param[in] startPos A position within the start polygon. [(x, y, z)]
|
||||||
|
/// @param[in] endPos A position within the end polygon. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[in] options query options (see: #dtFindPathOptions)
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||||
|
const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter, const unsigned int options = 0);
|
||||||
|
|
||||||
|
/// Updates an in-progress sliced path query.
|
||||||
|
/// @param[in] maxIter The maximum number of iterations to perform.
|
||||||
|
/// @param[out] doneIters The actual number of iterations completed. [opt]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus updateSlicedFindPath(const int maxIter, int* doneIters);
|
||||||
|
|
||||||
|
/// Finalizes and returns the results of a sliced path query.
|
||||||
|
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||||
|
/// [(polyRef) * @p pathCount]
|
||||||
|
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||||
|
/// @param[in] maxPath The max number of polygons the path array can hold. [Limit: >= 1]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath);
|
||||||
|
|
||||||
|
/// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest
|
||||||
|
/// polygon on the existing path that was visited during the search.
|
||||||
|
/// @param[in] existing An array of polygon references for the existing path.
|
||||||
|
/// @param[in] existingSize The number of polygon in the @p existing array.
|
||||||
|
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||||
|
/// [(polyRef) * @p pathCount]
|
||||||
|
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||||
|
/// @param[in] maxPath The max number of polygons the @p path array can hold. [Limit: >= 1]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
|
||||||
|
dtPolyRef* path, int* pathCount, const int maxPath);
|
||||||
|
|
||||||
|
///@}
|
||||||
|
/// @name Dijkstra Search Functions
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Finds the polygons along the navigation graph that touch the specified circle.
|
||||||
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
|
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||||
|
/// @param[in] radius The radius of the search circle.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] resultRef The reference ids of the polygons touched by the circle. [opt]
|
||||||
|
/// @param[out] resultParent The reference ids of the parent polygons for each result.
|
||||||
|
/// Zero if a result polygon has no parent. [opt]
|
||||||
|
/// @param[out] resultCost The search cost from @p centerPos to the polygon. [opt]
|
||||||
|
/// @param[out] resultCount The number of polygons found. [opt]
|
||||||
|
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
||||||
|
int* resultCount, const int maxResult) const;
|
||||||
|
|
||||||
|
/// Finds the polygons along the naviation graph that touch the specified convex polygon.
|
||||||
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
|
/// @param[in] verts The vertices describing the convex polygon. (CCW)
|
||||||
|
/// [(x, y, z) * @p nverts]
|
||||||
|
/// @param[in] nverts The number of vertices in the polygon.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] resultRef The reference ids of the polygons touched by the search polygon. [opt]
|
||||||
|
/// @param[out] resultParent The reference ids of the parent polygons for each result. Zero if a
|
||||||
|
/// result polygon has no parent. [opt]
|
||||||
|
/// @param[out] resultCost The search cost from the centroid point to the polygon. [opt]
|
||||||
|
/// @param[out] resultCount The number of polygons found.
|
||||||
|
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findPolysAroundShape(dtPolyRef startRef, const float* verts, const int nverts,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
||||||
|
int* resultCount, const int maxResult) const;
|
||||||
|
|
||||||
|
/// Gets a path from the explored nodes in the previous search.
|
||||||
|
/// @param[in] endRef The reference id of the end polygon.
|
||||||
|
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||||
|
/// [(polyRef) * @p pathCount]
|
||||||
|
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||||
|
/// @param[in] maxPath The maximum number of polygons the @p path array can hold. [Limit: >= 0]
|
||||||
|
/// @returns The status flags. Returns DT_FAILURE | DT_INVALID_PARAM if any parameter is wrong, or if
|
||||||
|
/// @p endRef was not explored in the previous search. Returns DT_SUCCESS | DT_BUFFER_TOO_SMALL
|
||||||
|
/// if @p path cannot contain the entire path. In this case it is filled to capacity with a partial path.
|
||||||
|
/// Otherwise returns DT_SUCCESS.
|
||||||
|
/// @remarks The result of this function depends on the state of the query object. For that reason it should only
|
||||||
|
/// be used immediately after one of the two Dijkstra searches, findPolysAroundCircle or findPolysAroundShape.
|
||||||
|
dtStatus getPathFromDijkstraSearch(dtPolyRef endRef, dtPolyRef* path, int* pathCount, int maxPath) const;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Local Query Functions
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/// Finds the polygon nearest to the specified center point.
|
||||||
|
/// [opt] means the specified parameter can be a null pointer, in that case the output parameter will not be set.
|
||||||
|
///
|
||||||
|
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||||
|
/// @param[in] halfExtents The search distance along each axis. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] nearestRef The reference id of the nearest polygon. Will be set to 0 if no polygon is found.
|
||||||
|
/// @param[out] nearestPt The nearest point on the polygon. Unchanged if no polygon is found. [opt] [(x, y, z)]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findNearestPoly(const float* center, const float* halfExtents,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* nearestRef, float* nearestPt) const;
|
||||||
|
|
||||||
|
/// Finds the polygon nearest to the specified center point.
|
||||||
|
/// [opt] means the specified parameter can be a null pointer, in that case the output parameter will not be set.
|
||||||
|
///
|
||||||
|
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||||
|
/// @param[in] halfExtents The search distance along each axis. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] nearestRef The reference id of the nearest polygon. Will be set to 0 if no polygon is found.
|
||||||
|
/// @param[out] nearestPt The nearest point on the polygon. Unchanged if no polygon is found. [opt] [(x, y, z)]
|
||||||
|
/// @param[out] isOverPoly Set to true if the point's X/Z coordinate lies inside the polygon, false otherwise. Unchanged if no polygon is found. [opt]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findNearestPoly(const float* center, const float* halfExtents,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* nearestRef, float* nearestPt, bool* isOverPoly) const;
|
||||||
|
|
||||||
|
/// Finds polygons that overlap the search box.
|
||||||
|
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||||
|
/// @param[in] halfExtents The search distance along each axis. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] polys The reference ids of the polygons that overlap the query box.
|
||||||
|
/// @param[out] polyCount The number of polygons in the search result.
|
||||||
|
/// @param[in] maxPolys The maximum number of polygons the search result can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus queryPolygons(const float* center, const float* halfExtents,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* polys, int* polyCount, const int maxPolys) const;
|
||||||
|
|
||||||
|
/// Finds polygons that overlap the search box.
|
||||||
|
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||||
|
/// @param[in] halfExtents The search distance along each axis. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[in] query The query. Polygons found will be batched together and passed to this query.
|
||||||
|
dtStatus queryPolygons(const float* center, const float* halfExtents,
|
||||||
|
const dtQueryFilter* filter, dtPolyQuery* query) const;
|
||||||
|
|
||||||
|
/// Finds the non-overlapping navigation polygons in the local neighbourhood around the center position.
|
||||||
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
|
/// @param[in] centerPos The center of the query circle. [(x, y, z)]
|
||||||
|
/// @param[in] radius The radius of the query circle.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] resultRef The reference ids of the polygons touched by the circle.
|
||||||
|
/// @param[out] resultParent The reference ids of the parent polygons for each result.
|
||||||
|
/// Zero if a result polygon has no parent. [opt]
|
||||||
|
/// @param[out] resultCount The number of polygons found.
|
||||||
|
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findLocalNeighbourhood(dtPolyRef startRef, const float* centerPos, const float radius,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* resultRef, dtPolyRef* resultParent,
|
||||||
|
int* resultCount, const int maxResult) const;
|
||||||
|
|
||||||
|
/// Moves from the start to the end position constrained to the navigation mesh.
|
||||||
|
/// @param[in] startRef The reference id of the start polygon.
|
||||||
|
/// @param[in] startPos A position of the mover within the start polygon. [(x, y, x)]
|
||||||
|
/// @param[in] endPos The desired end position of the mover. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] resultPos The result position of the mover. [(x, y, z)]
|
||||||
|
/// @param[out] visited The reference ids of the polygons visited during the move.
|
||||||
|
/// @param[out] visitedCount The number of polygons visited during the move.
|
||||||
|
/// @param[in] maxVisitedSize The maximum number of polygons the @p visited array can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
float* resultPos, dtPolyRef* visited, int* visitedCount, const int maxVisitedSize) const;
|
||||||
|
|
||||||
|
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
||||||
|
/// the start position toward the end position.
|
||||||
|
/// @note A wrapper around raycast(..., RaycastHit*). Retained for backward compatibility.
|
||||||
|
/// @param[in] startRef The reference id of the start polygon.
|
||||||
|
/// @param[in] startPos A position within the start polygon representing
|
||||||
|
/// the start of the ray. [(x, y, z)]
|
||||||
|
/// @param[in] endPos The position to cast the ray toward. [(x, y, z)]
|
||||||
|
/// @param[out] t The hit parameter. (FLT_MAX if no wall hit.)
|
||||||
|
/// @param[out] hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] path The reference ids of the visited polygons. [opt]
|
||||||
|
/// @param[out] pathCount The number of visited polygons. [opt]
|
||||||
|
/// @param[in] maxPath The maximum number of polygons the @p path array can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
float* t, float* hitNormal, dtPolyRef* path, int* pathCount, const int maxPath) const;
|
||||||
|
|
||||||
|
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
||||||
|
/// the start position toward the end position.
|
||||||
|
/// @param[in] startRef The reference id of the start polygon.
|
||||||
|
/// @param[in] startPos A position within the start polygon representing
|
||||||
|
/// the start of the ray. [(x, y, z)]
|
||||||
|
/// @param[in] endPos The position to cast the ray toward. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[in] flags govern how the raycast behaves. See dtRaycastOptions
|
||||||
|
/// @param[out] hit Pointer to a raycast hit structure which will be filled by the results.
|
||||||
|
/// @param[in] prevRef parent of start ref. Used during for cost calculation [opt]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter, const unsigned int options,
|
||||||
|
dtRaycastHit* hit, dtPolyRef prevRef = 0) const;
|
||||||
|
|
||||||
|
|
||||||
|
/// Finds the distance from the specified position to the nearest polygon wall.
|
||||||
|
/// @param[in] startRef The reference id of the polygon containing @p centerPos.
|
||||||
|
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||||
|
/// @param[in] maxRadius The radius of the search circle.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] hitDist The distance to the nearest wall from @p centerPos.
|
||||||
|
/// @param[out] hitPos The nearest position on the wall that was hit. [(x, y, z)]
|
||||||
|
/// @param[out] hitNormal The normalized ray formed from the wall point to the
|
||||||
|
/// source point. [(x, y, z)]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findDistanceToWall(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
float* hitDist, float* hitPos, float* hitNormal) const;
|
||||||
|
|
||||||
|
/// Returns the segments for the specified polygon, optionally including portals.
|
||||||
|
/// @param[in] ref The reference id of the polygon.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] segmentVerts The segments. [(ax, ay, az, bx, by, bz) * segmentCount]
|
||||||
|
/// @param[out] segmentRefs The reference ids of each segment's neighbor polygon.
|
||||||
|
/// Or zero if the segment is a wall. [opt] [(parentRef) * @p segmentCount]
|
||||||
|
/// @param[out] segmentCount The number of segments returned.
|
||||||
|
/// @param[in] maxSegments The maximum number of segments the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter,
|
||||||
|
float* segmentVerts, dtPolyRef* segmentRefs, int* segmentCount,
|
||||||
|
const int maxSegments) const;
|
||||||
|
|
||||||
|
/// Returns random location on navmesh.
|
||||||
|
/// Polygons are chosen weighted by area. The search runs in linear related to number of polygon.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[in] frand Function returning a random number [0..1).
|
||||||
|
/// @param[out] randomRef The reference id of the random location.
|
||||||
|
/// @param[out] randomPt The random location.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findRandomPoint(const dtQueryFilter* filter, float (*frand)(),
|
||||||
|
dtPolyRef* randomRef, float* randomPt) const;
|
||||||
|
|
||||||
|
/// Returns random location on navmesh within the reach of specified location.
|
||||||
|
/// Polygons are chosen weighted by area. The search runs in linear related to number of polygon.
|
||||||
|
/// The location is not exactly constrained by the circle, but it limits the visited polygons.
|
||||||
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
|
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[in] frand Function returning a random number [0..1).
|
||||||
|
/// @param[out] randomRef The reference id of the random location.
|
||||||
|
/// @param[out] randomPt The random location. [(x, y, z)]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findRandomPointAroundCircle(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
||||||
|
const dtQueryFilter* filter, float (*frand)(),
|
||||||
|
dtPolyRef* randomRef, float* randomPt) const;
|
||||||
|
|
||||||
|
/// Finds the closest point on the specified polygon.
|
||||||
|
/// @param[in] ref The reference id of the polygon.
|
||||||
|
/// @param[in] pos The position to check. [(x, y, z)]
|
||||||
|
/// @param[out] closest The closest point on the polygon. [(x, y, z)]
|
||||||
|
/// @param[out] posOverPoly True of the position is over the polygon.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
|
||||||
|
|
||||||
|
/// Returns a point on the boundary closest to the source point if the source point is outside the
|
||||||
|
/// polygon's xz-bounds.
|
||||||
|
/// @param[in] ref The reference id to the polygon.
|
||||||
|
/// @param[in] pos The position to check. [(x, y, z)]
|
||||||
|
/// @param[out] closest The closest point. [(x, y, z)]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const;
|
||||||
|
|
||||||
|
/// Gets the height of the polygon at the provided position using the height detail. (Most accurate.)
|
||||||
|
/// @param[in] ref The reference id of the polygon.
|
||||||
|
/// @param[in] pos A position within the xz-bounds of the polygon. [(x, y, z)]
|
||||||
|
/// @param[out] height The height at the surface of the polygon.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus getPolyHeight(dtPolyRef ref, const float* pos, float* height) const;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Miscellaneous Functions
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Returns true if the polygon reference is valid and passes the filter restrictions.
|
||||||
|
/// @param[in] ref The polygon reference to check.
|
||||||
|
/// @param[in] filter The filter to apply.
|
||||||
|
bool isValidPolyRef(dtPolyRef ref, const dtQueryFilter* filter) const;
|
||||||
|
|
||||||
|
/// Returns true if the polygon reference is in the closed list.
|
||||||
|
/// @param[in] ref The reference id of the polygon to check.
|
||||||
|
/// @returns True if the polygon is in closed list.
|
||||||
|
bool isInClosedList(dtPolyRef ref) const;
|
||||||
|
|
||||||
|
/// Gets the node pool.
|
||||||
|
/// @returns The node pool.
|
||||||
|
class dtNodePool* getNodePool() const { return m_nodePool; }
|
||||||
|
|
||||||
|
/// Gets the navigation mesh the query object is using.
|
||||||
|
/// @return The navigation mesh the query object is using.
|
||||||
|
const dtNavMesh* getAttachedNavMesh() const { return m_nav; }
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Explicitly disabled copy constructor and copy assignment operator
|
||||||
|
dtNavMeshQuery(const dtNavMeshQuery&);
|
||||||
|
dtNavMeshQuery& operator=(const dtNavMeshQuery&);
|
||||||
|
|
||||||
|
/// Queries polygons within a tile.
|
||||||
|
void queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
||||||
|
const dtQueryFilter* filter, dtPolyQuery* query) const;
|
||||||
|
|
||||||
|
/// Returns portal points between two polygons.
|
||||||
|
dtStatus getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right,
|
||||||
|
unsigned char& fromType, unsigned char& toType) const;
|
||||||
|
dtStatus getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
||||||
|
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
||||||
|
float* left, float* right) const;
|
||||||
|
|
||||||
|
/// Returns edge mid point between two polygons.
|
||||||
|
dtStatus getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const;
|
||||||
|
dtStatus getEdgeMidPoint(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
||||||
|
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
||||||
|
float* mid) const;
|
||||||
|
|
||||||
|
// Appends vertex to a straight path
|
||||||
|
dtStatus appendVertex(const float* pos, const unsigned char flags, const dtPolyRef ref,
|
||||||
|
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||||
|
int* straightPathCount, const int maxStraightPath) const;
|
||||||
|
|
||||||
|
// Appends intermediate portal points to a straight path.
|
||||||
|
dtStatus appendPortals(const int startIdx, const int endIdx, const float* endPos, const dtPolyRef* path,
|
||||||
|
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||||
|
int* straightPathCount, const int maxStraightPath, const int options) const;
|
||||||
|
|
||||||
|
// Gets the path leading to the specified end node.
|
||||||
|
dtStatus getPathToNode(struct dtNode* endNode, dtPolyRef* path, int* pathCount, int maxPath) const;
|
||||||
|
|
||||||
|
const dtNavMesh* m_nav; ///< Pointer to navmesh data.
|
||||||
|
|
||||||
|
struct dtQueryData
|
||||||
|
{
|
||||||
|
dtStatus status;
|
||||||
|
struct dtNode* lastBestNode;
|
||||||
|
float lastBestNodeCost;
|
||||||
|
dtPolyRef startRef, endRef;
|
||||||
|
float startPos[3], endPos[3];
|
||||||
|
const dtQueryFilter* filter;
|
||||||
|
unsigned int options;
|
||||||
|
float raycastLimitSqr;
|
||||||
|
};
|
||||||
|
dtQueryData m_query; ///< Sliced query state.
|
||||||
|
|
||||||
|
class dtNodePool* m_tinyNodePool; ///< Pointer to small node pool.
|
||||||
|
class dtNodePool* m_nodePool; ///< Pointer to node pool.
|
||||||
|
class dtNodeQueue* m_openList; ///< Pointer to open list queue.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Allocates a query object using the Detour allocator.
|
||||||
|
/// @return An allocated query object, or null on failure.
|
||||||
|
/// @ingroup detour
|
||||||
|
dtNavMeshQuery* dtAllocNavMeshQuery();
|
||||||
|
|
||||||
|
/// Frees the specified query object using the Detour allocator.
|
||||||
|
/// @param[in] query A query object allocated using #dtAllocNavMeshQuery
|
||||||
|
/// @ingroup detour
|
||||||
|
void dtFreeNavMeshQuery(dtNavMeshQuery* query);
|
||||||
|
|
||||||
|
#endif // DETOURNAVMESHQUERY_H
|
||||||
168
modules/detour/thirdparty/Detour/Include/DetourNode.h
vendored
Normal file
168
modules/detour/thirdparty/Detour/Include/DetourNode.h
vendored
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURNODE_H
|
||||||
|
#define DETOURNODE_H
|
||||||
|
|
||||||
|
#include "DetourNavMesh.h"
|
||||||
|
|
||||||
|
enum dtNodeFlags
|
||||||
|
{
|
||||||
|
DT_NODE_OPEN = 0x01,
|
||||||
|
DT_NODE_CLOSED = 0x02,
|
||||||
|
DT_NODE_PARENT_DETACHED = 0x04, // parent of the node is not adjacent. Found using raycast.
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef unsigned short dtNodeIndex;
|
||||||
|
static const dtNodeIndex DT_NULL_IDX = (dtNodeIndex)~0;
|
||||||
|
|
||||||
|
static const int DT_NODE_PARENT_BITS = 24;
|
||||||
|
static const int DT_NODE_STATE_BITS = 2;
|
||||||
|
struct dtNode
|
||||||
|
{
|
||||||
|
float pos[3]; ///< Position of the node.
|
||||||
|
float cost; ///< Cost from previous node to current node.
|
||||||
|
float total; ///< Cost up to the node.
|
||||||
|
unsigned int pidx : DT_NODE_PARENT_BITS; ///< Index to parent node.
|
||||||
|
unsigned int state : DT_NODE_STATE_BITS; ///< extra state information. A polyRef can have multiple nodes with different extra info. see DT_MAX_STATES_PER_NODE
|
||||||
|
unsigned int flags : 3; ///< Node flags. A combination of dtNodeFlags.
|
||||||
|
dtPolyRef id; ///< Polygon ref the node corresponds to.
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int DT_MAX_STATES_PER_NODE = 1 << DT_NODE_STATE_BITS; // number of extra states per node. See dtNode::state
|
||||||
|
|
||||||
|
class dtNodePool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dtNodePool(int maxNodes, int hashSize);
|
||||||
|
~dtNodePool();
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
// Get a dtNode by ref and extra state information. If there is none then - allocate
|
||||||
|
// There can be more than one node for the same polyRef but with different extra state information
|
||||||
|
dtNode* getNode(dtPolyRef id, unsigned char state=0);
|
||||||
|
dtNode* findNode(dtPolyRef id, unsigned char state);
|
||||||
|
unsigned int findNodes(dtPolyRef id, dtNode** nodes, const int maxNodes);
|
||||||
|
|
||||||
|
inline unsigned int getNodeIdx(const dtNode* node) const
|
||||||
|
{
|
||||||
|
if (!node) return 0;
|
||||||
|
return (unsigned int)(node - m_nodes) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline dtNode* getNodeAtIdx(unsigned int idx)
|
||||||
|
{
|
||||||
|
if (!idx) return 0;
|
||||||
|
return &m_nodes[idx - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const dtNode* getNodeAtIdx(unsigned int idx) const
|
||||||
|
{
|
||||||
|
if (!idx) return 0;
|
||||||
|
return &m_nodes[idx - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int getMemUsed() const
|
||||||
|
{
|
||||||
|
return sizeof(*this) +
|
||||||
|
sizeof(dtNode)*m_maxNodes +
|
||||||
|
sizeof(dtNodeIndex)*m_maxNodes +
|
||||||
|
sizeof(dtNodeIndex)*m_hashSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int getMaxNodes() const { return m_maxNodes; }
|
||||||
|
|
||||||
|
inline int getHashSize() const { return m_hashSize; }
|
||||||
|
inline dtNodeIndex getFirst(int bucket) const { return m_first[bucket]; }
|
||||||
|
inline dtNodeIndex getNext(int i) const { return m_next[i]; }
|
||||||
|
inline int getNodeCount() const { return m_nodeCount; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Explicitly disabled copy constructor and copy assignment operator.
|
||||||
|
dtNodePool(const dtNodePool&);
|
||||||
|
dtNodePool& operator=(const dtNodePool&);
|
||||||
|
|
||||||
|
dtNode* m_nodes;
|
||||||
|
dtNodeIndex* m_first;
|
||||||
|
dtNodeIndex* m_next;
|
||||||
|
const int m_maxNodes;
|
||||||
|
const int m_hashSize;
|
||||||
|
int m_nodeCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
class dtNodeQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dtNodeQueue(int n);
|
||||||
|
~dtNodeQueue();
|
||||||
|
|
||||||
|
inline void clear() { m_size = 0; }
|
||||||
|
|
||||||
|
inline dtNode* top() { return m_heap[0]; }
|
||||||
|
|
||||||
|
inline dtNode* pop()
|
||||||
|
{
|
||||||
|
dtNode* result = m_heap[0];
|
||||||
|
m_size--;
|
||||||
|
trickleDown(0, m_heap[m_size]);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void push(dtNode* node)
|
||||||
|
{
|
||||||
|
m_size++;
|
||||||
|
bubbleUp(m_size-1, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void modify(dtNode* node)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_size; ++i)
|
||||||
|
{
|
||||||
|
if (m_heap[i] == node)
|
||||||
|
{
|
||||||
|
bubbleUp(i, node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool empty() const { return m_size == 0; }
|
||||||
|
|
||||||
|
inline int getMemUsed() const
|
||||||
|
{
|
||||||
|
return sizeof(*this) +
|
||||||
|
sizeof(dtNode*) * (m_capacity + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int getCapacity() const { return m_capacity; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Explicitly disabled copy constructor and copy assignment operator.
|
||||||
|
dtNodeQueue(const dtNodeQueue&);
|
||||||
|
dtNodeQueue& operator=(const dtNodeQueue&);
|
||||||
|
|
||||||
|
void bubbleUp(int i, dtNode* node);
|
||||||
|
void trickleDown(int i, dtNode* node);
|
||||||
|
|
||||||
|
dtNode** m_heap;
|
||||||
|
const int m_capacity;
|
||||||
|
int m_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DETOURNODE_H
|
||||||
65
modules/detour/thirdparty/Detour/Include/DetourStatus.h
vendored
Normal file
65
modules/detour/thirdparty/Detour/Include/DetourStatus.h
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURSTATUS_H
|
||||||
|
#define DETOURSTATUS_H
|
||||||
|
|
||||||
|
typedef unsigned int dtStatus;
|
||||||
|
|
||||||
|
// High level status.
|
||||||
|
static const unsigned int DT_FAILURE = 1u << 31; // Operation failed.
|
||||||
|
static const unsigned int DT_SUCCESS = 1u << 30; // Operation succeed.
|
||||||
|
static const unsigned int DT_IN_PROGRESS = 1u << 29; // Operation still in progress.
|
||||||
|
|
||||||
|
// Detail information for status.
|
||||||
|
static const unsigned int DT_STATUS_DETAIL_MASK = 0x0ffffff;
|
||||||
|
static const unsigned int DT_WRONG_MAGIC = 1 << 0; // Input data is not recognized.
|
||||||
|
static const unsigned int DT_WRONG_VERSION = 1 << 1; // Input data is in wrong version.
|
||||||
|
static const unsigned int DT_OUT_OF_MEMORY = 1 << 2; // Operation ran out of memory.
|
||||||
|
static const unsigned int DT_INVALID_PARAM = 1 << 3; // An input parameter was invalid.
|
||||||
|
static const unsigned int DT_BUFFER_TOO_SMALL = 1 << 4; // Result buffer for the query was too small to store all results.
|
||||||
|
static const unsigned int DT_OUT_OF_NODES = 1 << 5; // Query ran out of nodes during search.
|
||||||
|
static const unsigned int DT_PARTIAL_RESULT = 1 << 6; // Query did not reach the end location, returning best guess.
|
||||||
|
static const unsigned int DT_ALREADY_OCCUPIED = 1 << 7; // A tile has already been assigned to the given x,y coordinate
|
||||||
|
|
||||||
|
|
||||||
|
// Returns true of status is success.
|
||||||
|
inline bool dtStatusSucceed(dtStatus status)
|
||||||
|
{
|
||||||
|
return (status & DT_SUCCESS) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true of status is failure.
|
||||||
|
inline bool dtStatusFailed(dtStatus status)
|
||||||
|
{
|
||||||
|
return (status & DT_FAILURE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true of status is in progress.
|
||||||
|
inline bool dtStatusInProgress(dtStatus status)
|
||||||
|
{
|
||||||
|
return (status & DT_IN_PROGRESS) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if specific detail is set.
|
||||||
|
inline bool dtStatusDetail(dtStatus status, unsigned int detail)
|
||||||
|
{
|
||||||
|
return (status & detail) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DETOURSTATUS_H
|
||||||
50
modules/detour/thirdparty/Detour/Source/DetourAlloc.cpp
vendored
Normal file
50
modules/detour/thirdparty/Detour/Source/DetourAlloc.cpp
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
|
||||||
|
static void *dtAllocDefault(size_t size, dtAllocHint)
|
||||||
|
{
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dtFreeDefault(void *ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dtAllocFunc* sAllocFunc = dtAllocDefault;
|
||||||
|
static dtFreeFunc* sFreeFunc = dtFreeDefault;
|
||||||
|
|
||||||
|
void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc)
|
||||||
|
{
|
||||||
|
sAllocFunc = allocFunc ? allocFunc : dtAllocDefault;
|
||||||
|
sFreeFunc = freeFunc ? freeFunc : dtFreeDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* dtAlloc(size_t size, dtAllocHint hint)
|
||||||
|
{
|
||||||
|
return sAllocFunc(size, hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtFree(void* ptr)
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
sFreeFunc(ptr);
|
||||||
|
}
|
||||||
BIN
modules/detour/thirdparty/Detour/Source/DetourAlloc.x11.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourAlloc.x11.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourAlloc.x11.opt.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourAlloc.x11.opt.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourAlloc.x11.opt.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourAlloc.x11.opt.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourAlloc.x11.opt.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourAlloc.x11.opt.tools.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourAlloc.x11.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourAlloc.x11.tools.64.o
vendored
Normal file
Binary file not shown.
35
modules/detour/thirdparty/Detour/Source/DetourAssert.cpp
vendored
Normal file
35
modules/detour/thirdparty/Detour/Source/DetourAssert.cpp
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "DetourAssert.h"
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
|
||||||
|
static dtAssertFailFunc* sAssertFailFunc = 0;
|
||||||
|
|
||||||
|
void dtAssertFailSetCustom(dtAssertFailFunc *assertFailFunc)
|
||||||
|
{
|
||||||
|
sAssertFailFunc = assertFailFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtAssertFailFunc* dtAssertFailGetCustom()
|
||||||
|
{
|
||||||
|
return sAssertFailFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
BIN
modules/detour/thirdparty/Detour/Source/DetourAssert.x11.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourAssert.x11.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourAssert.x11.opt.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourAssert.x11.opt.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourAssert.x11.opt.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourAssert.x11.opt.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourAssert.x11.opt.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourAssert.x11.opt.tools.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourAssert.x11.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourAssert.x11.tools.64.o
vendored
Normal file
Binary file not shown.
387
modules/detour/thirdparty/Detour/Source/DetourCommon.cpp
vendored
Normal file
387
modules/detour/thirdparty/Detour/Source/DetourCommon.cpp
vendored
Normal file
@@ -0,0 +1,387 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "DetourCommon.h"
|
||||||
|
#include "DetourMath.h"
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void dtClosestPtPointTriangle(float* closest, const float* p,
|
||||||
|
const float* a, const float* b, const float* c)
|
||||||
|
{
|
||||||
|
// Check if P in vertex region outside A
|
||||||
|
float ab[3], ac[3], ap[3];
|
||||||
|
dtVsub(ab, b, a);
|
||||||
|
dtVsub(ac, c, a);
|
||||||
|
dtVsub(ap, p, a);
|
||||||
|
float d1 = dtVdot(ab, ap);
|
||||||
|
float d2 = dtVdot(ac, ap);
|
||||||
|
if (d1 <= 0.0f && d2 <= 0.0f)
|
||||||
|
{
|
||||||
|
// barycentric coordinates (1,0,0)
|
||||||
|
dtVcopy(closest, a);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if P in vertex region outside B
|
||||||
|
float bp[3];
|
||||||
|
dtVsub(bp, p, b);
|
||||||
|
float d3 = dtVdot(ab, bp);
|
||||||
|
float d4 = dtVdot(ac, bp);
|
||||||
|
if (d3 >= 0.0f && d4 <= d3)
|
||||||
|
{
|
||||||
|
// barycentric coordinates (0,1,0)
|
||||||
|
dtVcopy(closest, b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if P in edge region of AB, if so return projection of P onto AB
|
||||||
|
float vc = d1*d4 - d3*d2;
|
||||||
|
if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f)
|
||||||
|
{
|
||||||
|
// barycentric coordinates (1-v,v,0)
|
||||||
|
float v = d1 / (d1 - d3);
|
||||||
|
closest[0] = a[0] + v * ab[0];
|
||||||
|
closest[1] = a[1] + v * ab[1];
|
||||||
|
closest[2] = a[2] + v * ab[2];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if P in vertex region outside C
|
||||||
|
float cp[3];
|
||||||
|
dtVsub(cp, p, c);
|
||||||
|
float d5 = dtVdot(ab, cp);
|
||||||
|
float d6 = dtVdot(ac, cp);
|
||||||
|
if (d6 >= 0.0f && d5 <= d6)
|
||||||
|
{
|
||||||
|
// barycentric coordinates (0,0,1)
|
||||||
|
dtVcopy(closest, c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if P in edge region of AC, if so return projection of P onto AC
|
||||||
|
float vb = d5*d2 - d1*d6;
|
||||||
|
if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f)
|
||||||
|
{
|
||||||
|
// barycentric coordinates (1-w,0,w)
|
||||||
|
float w = d2 / (d2 - d6);
|
||||||
|
closest[0] = a[0] + w * ac[0];
|
||||||
|
closest[1] = a[1] + w * ac[1];
|
||||||
|
closest[2] = a[2] + w * ac[2];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if P in edge region of BC, if so return projection of P onto BC
|
||||||
|
float va = d3*d6 - d5*d4;
|
||||||
|
if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f)
|
||||||
|
{
|
||||||
|
// barycentric coordinates (0,1-w,w)
|
||||||
|
float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
|
||||||
|
closest[0] = b[0] + w * (c[0] - b[0]);
|
||||||
|
closest[1] = b[1] + w * (c[1] - b[1]);
|
||||||
|
closest[2] = b[2] + w * (c[2] - b[2]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// P inside face region. Compute Q through its barycentric coordinates (u,v,w)
|
||||||
|
float denom = 1.0f / (va + vb + vc);
|
||||||
|
float v = vb * denom;
|
||||||
|
float w = vc * denom;
|
||||||
|
closest[0] = a[0] + ab[0] * v + ac[0] * w;
|
||||||
|
closest[1] = a[1] + ab[1] * v + ac[1] * w;
|
||||||
|
closest[2] = a[2] + ab[2] * v + ac[2] * w;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
|
||||||
|
const float* verts, int nverts,
|
||||||
|
float& tmin, float& tmax,
|
||||||
|
int& segMin, int& segMax)
|
||||||
|
{
|
||||||
|
static const float EPS = 0.00000001f;
|
||||||
|
|
||||||
|
tmin = 0;
|
||||||
|
tmax = 1;
|
||||||
|
segMin = -1;
|
||||||
|
segMax = -1;
|
||||||
|
|
||||||
|
float dir[3];
|
||||||
|
dtVsub(dir, p1, p0);
|
||||||
|
|
||||||
|
for (int i = 0, j = nverts-1; i < nverts; j=i++)
|
||||||
|
{
|
||||||
|
float edge[3], diff[3];
|
||||||
|
dtVsub(edge, &verts[i*3], &verts[j*3]);
|
||||||
|
dtVsub(diff, p0, &verts[j*3]);
|
||||||
|
const float n = dtVperp2D(edge, diff);
|
||||||
|
const float d = dtVperp2D(dir, edge);
|
||||||
|
if (fabsf(d) < EPS)
|
||||||
|
{
|
||||||
|
// S is nearly parallel to this edge
|
||||||
|
if (n < 0)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const float t = n / d;
|
||||||
|
if (d < 0)
|
||||||
|
{
|
||||||
|
// segment S is entering across this edge
|
||||||
|
if (t > tmin)
|
||||||
|
{
|
||||||
|
tmin = t;
|
||||||
|
segMin = j;
|
||||||
|
// S enters after leaving polygon
|
||||||
|
if (tmin > tmax)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// segment S is leaving across this edge
|
||||||
|
if (t < tmax)
|
||||||
|
{
|
||||||
|
tmax = t;
|
||||||
|
segMax = j;
|
||||||
|
// S leaves before entering polygon
|
||||||
|
if (tmax < tmin)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t)
|
||||||
|
{
|
||||||
|
float pqx = q[0] - p[0];
|
||||||
|
float pqz = q[2] - p[2];
|
||||||
|
float dx = pt[0] - p[0];
|
||||||
|
float dz = pt[2] - p[2];
|
||||||
|
float d = pqx*pqx + pqz*pqz;
|
||||||
|
t = pqx*dx + pqz*dz;
|
||||||
|
if (d > 0) t /= d;
|
||||||
|
if (t < 0) t = 0;
|
||||||
|
else if (t > 1) t = 1;
|
||||||
|
dx = p[0] + t*pqx - pt[0];
|
||||||
|
dz = p[2] + t*pqz - pt[2];
|
||||||
|
return dx*dx + dz*dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts)
|
||||||
|
{
|
||||||
|
tc[0] = 0.0f;
|
||||||
|
tc[1] = 0.0f;
|
||||||
|
tc[2] = 0.0f;
|
||||||
|
for (int j = 0; j < nidx; ++j)
|
||||||
|
{
|
||||||
|
const float* v = &verts[idx[j]*3];
|
||||||
|
tc[0] += v[0];
|
||||||
|
tc[1] += v[1];
|
||||||
|
tc[2] += v[2];
|
||||||
|
}
|
||||||
|
const float s = 1.0f / nidx;
|
||||||
|
tc[0] *= s;
|
||||||
|
tc[1] *= s;
|
||||||
|
tc[2] *= s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h)
|
||||||
|
{
|
||||||
|
const float EPS = 1e-6f;
|
||||||
|
float v0[3], v1[3], v2[3];
|
||||||
|
|
||||||
|
dtVsub(v0, c, a);
|
||||||
|
dtVsub(v1, b, a);
|
||||||
|
dtVsub(v2, p, a);
|
||||||
|
|
||||||
|
// Compute scaled barycentric coordinates
|
||||||
|
float denom = v0[0] * v1[2] - v0[2] * v1[0];
|
||||||
|
if (fabsf(denom) < EPS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float u = v1[2] * v2[0] - v1[0] * v2[2];
|
||||||
|
float v = v0[0] * v2[2] - v0[2] * v2[0];
|
||||||
|
|
||||||
|
if (denom < 0) {
|
||||||
|
denom = -denom;
|
||||||
|
u = -u;
|
||||||
|
v = -v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If point lies inside the triangle, return interpolated ycoord.
|
||||||
|
if (u >= 0.0f && v >= 0.0f && (u + v) <= denom) {
|
||||||
|
h = a[1] + (v0[1] * u + v1[1] * v) / denom;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// All points are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts)
|
||||||
|
{
|
||||||
|
// TODO: Replace pnpoly with triArea2D tests?
|
||||||
|
int i, j;
|
||||||
|
bool c = false;
|
||||||
|
for (i = 0, j = nverts-1; i < nverts; j = i++)
|
||||||
|
{
|
||||||
|
const float* vi = &verts[i*3];
|
||||||
|
const float* vj = &verts[j*3];
|
||||||
|
if (((vi[2] > pt[2]) != (vj[2] > pt[2])) &&
|
||||||
|
(pt[0] < (vj[0]-vi[0]) * (pt[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) )
|
||||||
|
c = !c;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
|
||||||
|
float* ed, float* et)
|
||||||
|
{
|
||||||
|
// TODO: Replace pnpoly with triArea2D tests?
|
||||||
|
int i, j;
|
||||||
|
bool c = false;
|
||||||
|
for (i = 0, j = nverts-1; i < nverts; j = i++)
|
||||||
|
{
|
||||||
|
const float* vi = &verts[i*3];
|
||||||
|
const float* vj = &verts[j*3];
|
||||||
|
if (((vi[2] > pt[2]) != (vj[2] > pt[2])) &&
|
||||||
|
(pt[0] < (vj[0]-vi[0]) * (pt[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) )
|
||||||
|
c = !c;
|
||||||
|
ed[j] = dtDistancePtSegSqr2D(pt, vj, vi, et[j]);
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void projectPoly(const float* axis, const float* poly, const int npoly,
|
||||||
|
float& rmin, float& rmax)
|
||||||
|
{
|
||||||
|
rmin = rmax = dtVdot2D(axis, &poly[0]);
|
||||||
|
for (int i = 1; i < npoly; ++i)
|
||||||
|
{
|
||||||
|
const float d = dtVdot2D(axis, &poly[i*3]);
|
||||||
|
rmin = dtMin(rmin, d);
|
||||||
|
rmax = dtMax(rmax, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool overlapRange(const float amin, const float amax,
|
||||||
|
const float bmin, const float bmax,
|
||||||
|
const float eps)
|
||||||
|
{
|
||||||
|
return ((amin+eps) > bmax || (amax-eps) < bmin) ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// All vertices are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
||||||
|
const float* polyb, const int npolyb)
|
||||||
|
{
|
||||||
|
const float eps = 1e-4f;
|
||||||
|
|
||||||
|
for (int i = 0, j = npolya-1; i < npolya; j=i++)
|
||||||
|
{
|
||||||
|
const float* va = &polya[j*3];
|
||||||
|
const float* vb = &polya[i*3];
|
||||||
|
const float n[3] = { vb[2]-va[2], 0, -(vb[0]-va[0]) };
|
||||||
|
float amin,amax,bmin,bmax;
|
||||||
|
projectPoly(n, polya, npolya, amin,amax);
|
||||||
|
projectPoly(n, polyb, npolyb, bmin,bmax);
|
||||||
|
if (!overlapRange(amin,amax, bmin,bmax, eps))
|
||||||
|
{
|
||||||
|
// Found separating axis
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0, j = npolyb-1; i < npolyb; j=i++)
|
||||||
|
{
|
||||||
|
const float* va = &polyb[j*3];
|
||||||
|
const float* vb = &polyb[i*3];
|
||||||
|
const float n[3] = { vb[2]-va[2], 0, -(vb[0]-va[0]) };
|
||||||
|
float amin,amax,bmin,bmax;
|
||||||
|
projectPoly(n, polya, npolya, amin,amax);
|
||||||
|
projectPoly(n, polyb, npolyb, bmin,bmax);
|
||||||
|
if (!overlapRange(amin,amax, bmin,bmax, eps))
|
||||||
|
{
|
||||||
|
// Found separating axis
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a random point in a convex polygon.
|
||||||
|
// Adapted from Graphics Gems article.
|
||||||
|
void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
|
||||||
|
const float s, const float t, float* out)
|
||||||
|
{
|
||||||
|
// Calc triangle araes
|
||||||
|
float areasum = 0.0f;
|
||||||
|
for (int i = 2; i < npts; i++) {
|
||||||
|
areas[i] = dtTriArea2D(&pts[0], &pts[(i-1)*3], &pts[i*3]);
|
||||||
|
areasum += dtMax(0.001f, areas[i]);
|
||||||
|
}
|
||||||
|
// Find sub triangle weighted by area.
|
||||||
|
const float thr = s*areasum;
|
||||||
|
float acc = 0.0f;
|
||||||
|
float u = 1.0f;
|
||||||
|
int tri = npts - 1;
|
||||||
|
for (int i = 2; i < npts; i++) {
|
||||||
|
const float dacc = areas[i];
|
||||||
|
if (thr >= acc && thr < (acc+dacc))
|
||||||
|
{
|
||||||
|
u = (thr - acc) / dacc;
|
||||||
|
tri = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
acc += dacc;
|
||||||
|
}
|
||||||
|
|
||||||
|
float v = dtMathSqrtf(t);
|
||||||
|
|
||||||
|
const float a = 1 - v;
|
||||||
|
const float b = (1 - u) * v;
|
||||||
|
const float c = u * v;
|
||||||
|
const float* pa = &pts[0];
|
||||||
|
const float* pb = &pts[(tri-1)*3];
|
||||||
|
const float* pc = &pts[tri*3];
|
||||||
|
|
||||||
|
out[0] = a*pa[0] + b*pb[0] + c*pc[0];
|
||||||
|
out[1] = a*pa[1] + b*pb[1] + c*pc[1];
|
||||||
|
out[2] = a*pa[2] + b*pb[2] + c*pc[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float vperpXZ(const float* a, const float* b) { return a[0]*b[2] - a[2]*b[0]; }
|
||||||
|
|
||||||
|
bool dtIntersectSegSeg2D(const float* ap, const float* aq,
|
||||||
|
const float* bp, const float* bq,
|
||||||
|
float& s, float& t)
|
||||||
|
{
|
||||||
|
float u[3], v[3], w[3];
|
||||||
|
dtVsub(u,aq,ap);
|
||||||
|
dtVsub(v,bq,bp);
|
||||||
|
dtVsub(w,ap,bp);
|
||||||
|
float d = vperpXZ(u,v);
|
||||||
|
if (fabsf(d) < 1e-6f) return false;
|
||||||
|
s = vperpXZ(v,w) / d;
|
||||||
|
t = vperpXZ(u,w) / d;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
BIN
modules/detour/thirdparty/Detour/Source/DetourCommon.x11.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourCommon.x11.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourCommon.x11.opt.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourCommon.x11.opt.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourCommon.x11.opt.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourCommon.x11.opt.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourCommon.x11.opt.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourCommon.x11.opt.tools.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourCommon.x11.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourCommon.x11.tools.64.o
vendored
Normal file
Binary file not shown.
1591
modules/detour/thirdparty/Detour/Source/DetourNavMesh.cpp
vendored
Normal file
1591
modules/detour/thirdparty/Detour/Source/DetourNavMesh.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMesh.x11.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMesh.x11.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMesh.x11.opt.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMesh.x11.opt.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMesh.x11.opt.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMesh.x11.opt.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMesh.x11.opt.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMesh.x11.opt.tools.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMesh.x11.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMesh.x11.tools.64.o
vendored
Normal file
Binary file not shown.
802
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.cpp
vendored
Normal file
802
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.cpp
vendored
Normal file
@@ -0,0 +1,802 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include "DetourNavMesh.h"
|
||||||
|
#include "DetourCommon.h"
|
||||||
|
#include "DetourMath.h"
|
||||||
|
#include "DetourNavMeshBuilder.h"
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
#include "DetourAssert.h"
|
||||||
|
|
||||||
|
static unsigned short MESH_NULL_IDX = 0xffff;
|
||||||
|
|
||||||
|
|
||||||
|
struct BVItem
|
||||||
|
{
|
||||||
|
unsigned short bmin[3];
|
||||||
|
unsigned short bmax[3];
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int compareItemX(const void* va, const void* vb)
|
||||||
|
{
|
||||||
|
const BVItem* a = (const BVItem*)va;
|
||||||
|
const BVItem* b = (const BVItem*)vb;
|
||||||
|
if (a->bmin[0] < b->bmin[0])
|
||||||
|
return -1;
|
||||||
|
if (a->bmin[0] > b->bmin[0])
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compareItemY(const void* va, const void* vb)
|
||||||
|
{
|
||||||
|
const BVItem* a = (const BVItem*)va;
|
||||||
|
const BVItem* b = (const BVItem*)vb;
|
||||||
|
if (a->bmin[1] < b->bmin[1])
|
||||||
|
return -1;
|
||||||
|
if (a->bmin[1] > b->bmin[1])
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compareItemZ(const void* va, const void* vb)
|
||||||
|
{
|
||||||
|
const BVItem* a = (const BVItem*)va;
|
||||||
|
const BVItem* b = (const BVItem*)vb;
|
||||||
|
if (a->bmin[2] < b->bmin[2])
|
||||||
|
return -1;
|
||||||
|
if (a->bmin[2] > b->bmin[2])
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calcExtends(BVItem* items, const int /*nitems*/, const int imin, const int imax,
|
||||||
|
unsigned short* bmin, unsigned short* bmax)
|
||||||
|
{
|
||||||
|
bmin[0] = items[imin].bmin[0];
|
||||||
|
bmin[1] = items[imin].bmin[1];
|
||||||
|
bmin[2] = items[imin].bmin[2];
|
||||||
|
|
||||||
|
bmax[0] = items[imin].bmax[0];
|
||||||
|
bmax[1] = items[imin].bmax[1];
|
||||||
|
bmax[2] = items[imin].bmax[2];
|
||||||
|
|
||||||
|
for (int i = imin+1; i < imax; ++i)
|
||||||
|
{
|
||||||
|
const BVItem& it = items[i];
|
||||||
|
if (it.bmin[0] < bmin[0]) bmin[0] = it.bmin[0];
|
||||||
|
if (it.bmin[1] < bmin[1]) bmin[1] = it.bmin[1];
|
||||||
|
if (it.bmin[2] < bmin[2]) bmin[2] = it.bmin[2];
|
||||||
|
|
||||||
|
if (it.bmax[0] > bmax[0]) bmax[0] = it.bmax[0];
|
||||||
|
if (it.bmax[1] > bmax[1]) bmax[1] = it.bmax[1];
|
||||||
|
if (it.bmax[2] > bmax[2]) bmax[2] = it.bmax[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int longestAxis(unsigned short x, unsigned short y, unsigned short z)
|
||||||
|
{
|
||||||
|
int axis = 0;
|
||||||
|
unsigned short maxVal = x;
|
||||||
|
if (y > maxVal)
|
||||||
|
{
|
||||||
|
axis = 1;
|
||||||
|
maxVal = y;
|
||||||
|
}
|
||||||
|
if (z > maxVal)
|
||||||
|
{
|
||||||
|
axis = 2;
|
||||||
|
}
|
||||||
|
return axis;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subdivide(BVItem* items, int nitems, int imin, int imax, int& curNode, dtBVNode* nodes)
|
||||||
|
{
|
||||||
|
int inum = imax - imin;
|
||||||
|
int icur = curNode;
|
||||||
|
|
||||||
|
dtBVNode& node = nodes[curNode++];
|
||||||
|
|
||||||
|
if (inum == 1)
|
||||||
|
{
|
||||||
|
// Leaf
|
||||||
|
node.bmin[0] = items[imin].bmin[0];
|
||||||
|
node.bmin[1] = items[imin].bmin[1];
|
||||||
|
node.bmin[2] = items[imin].bmin[2];
|
||||||
|
|
||||||
|
node.bmax[0] = items[imin].bmax[0];
|
||||||
|
node.bmax[1] = items[imin].bmax[1];
|
||||||
|
node.bmax[2] = items[imin].bmax[2];
|
||||||
|
|
||||||
|
node.i = items[imin].i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Split
|
||||||
|
calcExtends(items, nitems, imin, imax, node.bmin, node.bmax);
|
||||||
|
|
||||||
|
int axis = longestAxis(node.bmax[0] - node.bmin[0],
|
||||||
|
node.bmax[1] - node.bmin[1],
|
||||||
|
node.bmax[2] - node.bmin[2]);
|
||||||
|
|
||||||
|
if (axis == 0)
|
||||||
|
{
|
||||||
|
// Sort along x-axis
|
||||||
|
qsort(items+imin, inum, sizeof(BVItem), compareItemX);
|
||||||
|
}
|
||||||
|
else if (axis == 1)
|
||||||
|
{
|
||||||
|
// Sort along y-axis
|
||||||
|
qsort(items+imin, inum, sizeof(BVItem), compareItemY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Sort along z-axis
|
||||||
|
qsort(items+imin, inum, sizeof(BVItem), compareItemZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
int isplit = imin+inum/2;
|
||||||
|
|
||||||
|
// Left
|
||||||
|
subdivide(items, nitems, imin, isplit, curNode, nodes);
|
||||||
|
// Right
|
||||||
|
subdivide(items, nitems, isplit, imax, curNode, nodes);
|
||||||
|
|
||||||
|
int iescape = curNode - icur;
|
||||||
|
// Negative index means escape.
|
||||||
|
node.i = -iescape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int createBVTree(dtNavMeshCreateParams* params, dtBVNode* nodes, int /*nnodes*/)
|
||||||
|
{
|
||||||
|
// Build tree
|
||||||
|
float quantFactor = 1 / params->cs;
|
||||||
|
BVItem* items = (BVItem*)dtAlloc(sizeof(BVItem)*params->polyCount, DT_ALLOC_TEMP);
|
||||||
|
for (int i = 0; i < params->polyCount; i++)
|
||||||
|
{
|
||||||
|
BVItem& it = items[i];
|
||||||
|
it.i = i;
|
||||||
|
// Calc polygon bounds. Use detail meshes if available.
|
||||||
|
if (params->detailMeshes)
|
||||||
|
{
|
||||||
|
int vb = (int)params->detailMeshes[i*4+0];
|
||||||
|
int ndv = (int)params->detailMeshes[i*4+1];
|
||||||
|
float bmin[3];
|
||||||
|
float bmax[3];
|
||||||
|
|
||||||
|
const float* dv = ¶ms->detailVerts[vb*3];
|
||||||
|
dtVcopy(bmin, dv);
|
||||||
|
dtVcopy(bmax, dv);
|
||||||
|
|
||||||
|
for (int j = 1; j < ndv; j++)
|
||||||
|
{
|
||||||
|
dtVmin(bmin, &dv[j * 3]);
|
||||||
|
dtVmax(bmax, &dv[j * 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BV-tree uses cs for all dimensions
|
||||||
|
it.bmin[0] = (unsigned short)dtClamp((int)((bmin[0] - params->bmin[0])*quantFactor), 0, 0xffff);
|
||||||
|
it.bmin[1] = (unsigned short)dtClamp((int)((bmin[1] - params->bmin[1])*quantFactor), 0, 0xffff);
|
||||||
|
it.bmin[2] = (unsigned short)dtClamp((int)((bmin[2] - params->bmin[2])*quantFactor), 0, 0xffff);
|
||||||
|
|
||||||
|
it.bmax[0] = (unsigned short)dtClamp((int)((bmax[0] - params->bmin[0])*quantFactor), 0, 0xffff);
|
||||||
|
it.bmax[1] = (unsigned short)dtClamp((int)((bmax[1] - params->bmin[1])*quantFactor), 0, 0xffff);
|
||||||
|
it.bmax[2] = (unsigned short)dtClamp((int)((bmax[2] - params->bmin[2])*quantFactor), 0, 0xffff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const unsigned short* p = ¶ms->polys[i*params->nvp * 2];
|
||||||
|
it.bmin[0] = it.bmax[0] = params->verts[p[0] * 3 + 0];
|
||||||
|
it.bmin[1] = it.bmax[1] = params->verts[p[0] * 3 + 1];
|
||||||
|
it.bmin[2] = it.bmax[2] = params->verts[p[0] * 3 + 2];
|
||||||
|
|
||||||
|
for (int j = 1; j < params->nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == MESH_NULL_IDX) break;
|
||||||
|
unsigned short x = params->verts[p[j] * 3 + 0];
|
||||||
|
unsigned short y = params->verts[p[j] * 3 + 1];
|
||||||
|
unsigned short z = params->verts[p[j] * 3 + 2];
|
||||||
|
|
||||||
|
if (x < it.bmin[0]) it.bmin[0] = x;
|
||||||
|
if (y < it.bmin[1]) it.bmin[1] = y;
|
||||||
|
if (z < it.bmin[2]) it.bmin[2] = z;
|
||||||
|
|
||||||
|
if (x > it.bmax[0]) it.bmax[0] = x;
|
||||||
|
if (y > it.bmax[1]) it.bmax[1] = y;
|
||||||
|
if (z > it.bmax[2]) it.bmax[2] = z;
|
||||||
|
}
|
||||||
|
// Remap y
|
||||||
|
it.bmin[1] = (unsigned short)dtMathFloorf((float)it.bmin[1] * params->ch / params->cs);
|
||||||
|
it.bmax[1] = (unsigned short)dtMathCeilf((float)it.bmax[1] * params->ch / params->cs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int curNode = 0;
|
||||||
|
subdivide(items, params->polyCount, 0, params->polyCount, curNode, nodes);
|
||||||
|
|
||||||
|
dtFree(items);
|
||||||
|
|
||||||
|
return curNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char classifyOffMeshPoint(const float* pt, const float* bmin, const float* bmax)
|
||||||
|
{
|
||||||
|
static const unsigned char XP = 1<<0;
|
||||||
|
static const unsigned char ZP = 1<<1;
|
||||||
|
static const unsigned char XM = 1<<2;
|
||||||
|
static const unsigned char ZM = 1<<3;
|
||||||
|
|
||||||
|
unsigned char outcode = 0;
|
||||||
|
outcode |= (pt[0] >= bmax[0]) ? XP : 0;
|
||||||
|
outcode |= (pt[2] >= bmax[2]) ? ZP : 0;
|
||||||
|
outcode |= (pt[0] < bmin[0]) ? XM : 0;
|
||||||
|
outcode |= (pt[2] < bmin[2]) ? ZM : 0;
|
||||||
|
|
||||||
|
switch (outcode)
|
||||||
|
{
|
||||||
|
case XP: return 0;
|
||||||
|
case XP|ZP: return 1;
|
||||||
|
case ZP: return 2;
|
||||||
|
case XM|ZP: return 3;
|
||||||
|
case XM: return 4;
|
||||||
|
case XM|ZM: return 5;
|
||||||
|
case ZM: return 6;
|
||||||
|
case XP|ZM: return 7;
|
||||||
|
};
|
||||||
|
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Better error handling.
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The output data array is allocated using the detour allocator (dtAlloc()). The method
|
||||||
|
/// used to free the memory will be determined by how the tile is added to the navigation
|
||||||
|
/// mesh.
|
||||||
|
///
|
||||||
|
/// @see dtNavMesh, dtNavMesh::addTile()
|
||||||
|
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize)
|
||||||
|
{
|
||||||
|
if (params->nvp > DT_VERTS_PER_POLYGON)
|
||||||
|
return false;
|
||||||
|
if (params->vertCount >= 0xffff)
|
||||||
|
return false;
|
||||||
|
if (!params->vertCount || !params->verts)
|
||||||
|
return false;
|
||||||
|
if (!params->polyCount || !params->polys)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int nvp = params->nvp;
|
||||||
|
|
||||||
|
// Classify off-mesh connection points. We store only the connections
|
||||||
|
// whose start point is inside the tile.
|
||||||
|
unsigned char* offMeshConClass = 0;
|
||||||
|
int storedOffMeshConCount = 0;
|
||||||
|
int offMeshConLinkCount = 0;
|
||||||
|
|
||||||
|
if (params->offMeshConCount > 0)
|
||||||
|
{
|
||||||
|
offMeshConClass = (unsigned char*)dtAlloc(sizeof(unsigned char)*params->offMeshConCount*2, DT_ALLOC_TEMP);
|
||||||
|
if (!offMeshConClass)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Find tight heigh bounds, used for culling out off-mesh start locations.
|
||||||
|
float hmin = FLT_MAX;
|
||||||
|
float hmax = -FLT_MAX;
|
||||||
|
|
||||||
|
if (params->detailVerts && params->detailVertsCount)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < params->detailVertsCount; ++i)
|
||||||
|
{
|
||||||
|
const float h = params->detailVerts[i*3+1];
|
||||||
|
hmin = dtMin(hmin,h);
|
||||||
|
hmax = dtMax(hmax,h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < params->vertCount; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* iv = ¶ms->verts[i*3];
|
||||||
|
const float h = params->bmin[1] + iv[1] * params->ch;
|
||||||
|
hmin = dtMin(hmin,h);
|
||||||
|
hmax = dtMax(hmax,h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hmin -= params->walkableClimb;
|
||||||
|
hmax += params->walkableClimb;
|
||||||
|
float bmin[3], bmax[3];
|
||||||
|
dtVcopy(bmin, params->bmin);
|
||||||
|
dtVcopy(bmax, params->bmax);
|
||||||
|
bmin[1] = hmin;
|
||||||
|
bmax[1] = hmax;
|
||||||
|
|
||||||
|
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||||
|
{
|
||||||
|
const float* p0 = ¶ms->offMeshConVerts[(i*2+0)*3];
|
||||||
|
const float* p1 = ¶ms->offMeshConVerts[(i*2+1)*3];
|
||||||
|
offMeshConClass[i*2+0] = classifyOffMeshPoint(p0, bmin, bmax);
|
||||||
|
offMeshConClass[i*2+1] = classifyOffMeshPoint(p1, bmin, bmax);
|
||||||
|
|
||||||
|
// Zero out off-mesh start positions which are not even potentially touching the mesh.
|
||||||
|
if (offMeshConClass[i*2+0] == 0xff)
|
||||||
|
{
|
||||||
|
if (p0[1] < bmin[1] || p0[1] > bmax[1])
|
||||||
|
offMeshConClass[i*2+0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cound how many links should be allocated for off-mesh connections.
|
||||||
|
if (offMeshConClass[i*2+0] == 0xff)
|
||||||
|
offMeshConLinkCount++;
|
||||||
|
if (offMeshConClass[i*2+1] == 0xff)
|
||||||
|
offMeshConLinkCount++;
|
||||||
|
|
||||||
|
if (offMeshConClass[i*2+0] == 0xff)
|
||||||
|
storedOffMeshConCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Off-mesh connectionss are stored as polygons, adjust values.
|
||||||
|
const int totPolyCount = params->polyCount + storedOffMeshConCount;
|
||||||
|
const int totVertCount = params->vertCount + storedOffMeshConCount*2;
|
||||||
|
|
||||||
|
// Find portal edges which are at tile borders.
|
||||||
|
int edgeCount = 0;
|
||||||
|
int portalCount = 0;
|
||||||
|
for (int i = 0; i < params->polyCount; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* p = ¶ms->polys[i*2*nvp];
|
||||||
|
for (int j = 0; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == MESH_NULL_IDX) break;
|
||||||
|
edgeCount++;
|
||||||
|
|
||||||
|
if (p[nvp+j] & 0x8000)
|
||||||
|
{
|
||||||
|
unsigned short dir = p[nvp+j] & 0xf;
|
||||||
|
if (dir != 0xf)
|
||||||
|
portalCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int maxLinkCount = edgeCount + portalCount*2 + offMeshConLinkCount*2;
|
||||||
|
|
||||||
|
// Find unique detail vertices.
|
||||||
|
int uniqueDetailVertCount = 0;
|
||||||
|
int detailTriCount = 0;
|
||||||
|
if (params->detailMeshes)
|
||||||
|
{
|
||||||
|
// Has detail mesh, count unique detail vertex count and use input detail tri count.
|
||||||
|
detailTriCount = params->detailTriCount;
|
||||||
|
for (int i = 0; i < params->polyCount; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* p = ¶ms->polys[i*nvp*2];
|
||||||
|
int ndv = params->detailMeshes[i*4+1];
|
||||||
|
int nv = 0;
|
||||||
|
for (int j = 0; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == MESH_NULL_IDX) break;
|
||||||
|
nv++;
|
||||||
|
}
|
||||||
|
ndv -= nv;
|
||||||
|
uniqueDetailVertCount += ndv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No input detail mesh, build detail mesh from nav polys.
|
||||||
|
uniqueDetailVertCount = 0; // No extra detail verts.
|
||||||
|
detailTriCount = 0;
|
||||||
|
for (int i = 0; i < params->polyCount; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* p = ¶ms->polys[i*nvp*2];
|
||||||
|
int nv = 0;
|
||||||
|
for (int j = 0; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (p[j] == MESH_NULL_IDX) break;
|
||||||
|
nv++;
|
||||||
|
}
|
||||||
|
detailTriCount += nv-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate data size
|
||||||
|
const int headerSize = dtAlign4(sizeof(dtMeshHeader));
|
||||||
|
const int vertsSize = dtAlign4(sizeof(float)*3*totVertCount);
|
||||||
|
const int polysSize = dtAlign4(sizeof(dtPoly)*totPolyCount);
|
||||||
|
const int linksSize = dtAlign4(sizeof(dtLink)*maxLinkCount);
|
||||||
|
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*params->polyCount);
|
||||||
|
const int detailVertsSize = dtAlign4(sizeof(float)*3*uniqueDetailVertCount);
|
||||||
|
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*detailTriCount);
|
||||||
|
const int bvTreeSize = params->buildBvTree ? dtAlign4(sizeof(dtBVNode)*params->polyCount*2) : 0;
|
||||||
|
const int offMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection)*storedOffMeshConCount);
|
||||||
|
|
||||||
|
const int dataSize = headerSize + vertsSize + polysSize + linksSize +
|
||||||
|
detailMeshesSize + detailVertsSize + detailTrisSize +
|
||||||
|
bvTreeSize + offMeshConsSize;
|
||||||
|
|
||||||
|
unsigned char* data = (unsigned char*)dtAlloc(sizeof(unsigned char)*dataSize, DT_ALLOC_PERM);
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
dtFree(offMeshConClass);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(data, 0, dataSize);
|
||||||
|
|
||||||
|
unsigned char* d = data;
|
||||||
|
|
||||||
|
dtMeshHeader* header = dtGetThenAdvanceBufferPointer<dtMeshHeader>(d, headerSize);
|
||||||
|
float* navVerts = dtGetThenAdvanceBufferPointer<float>(d, vertsSize);
|
||||||
|
dtPoly* navPolys = dtGetThenAdvanceBufferPointer<dtPoly>(d, polysSize);
|
||||||
|
d += linksSize; // Ignore links; just leave enough space for them. They'll be created on load.
|
||||||
|
dtPolyDetail* navDMeshes = dtGetThenAdvanceBufferPointer<dtPolyDetail>(d, detailMeshesSize);
|
||||||
|
float* navDVerts = dtGetThenAdvanceBufferPointer<float>(d, detailVertsSize);
|
||||||
|
unsigned char* navDTris = dtGetThenAdvanceBufferPointer<unsigned char>(d, detailTrisSize);
|
||||||
|
dtBVNode* navBvtree = dtGetThenAdvanceBufferPointer<dtBVNode>(d, bvTreeSize);
|
||||||
|
dtOffMeshConnection* offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, offMeshConsSize);
|
||||||
|
|
||||||
|
|
||||||
|
// Store header
|
||||||
|
header->magic = DT_NAVMESH_MAGIC;
|
||||||
|
header->version = DT_NAVMESH_VERSION;
|
||||||
|
header->x = params->tileX;
|
||||||
|
header->y = params->tileY;
|
||||||
|
header->layer = params->tileLayer;
|
||||||
|
header->userId = params->userId;
|
||||||
|
header->polyCount = totPolyCount;
|
||||||
|
header->vertCount = totVertCount;
|
||||||
|
header->maxLinkCount = maxLinkCount;
|
||||||
|
dtVcopy(header->bmin, params->bmin);
|
||||||
|
dtVcopy(header->bmax, params->bmax);
|
||||||
|
header->detailMeshCount = params->polyCount;
|
||||||
|
header->detailVertCount = uniqueDetailVertCount;
|
||||||
|
header->detailTriCount = detailTriCount;
|
||||||
|
header->bvQuantFactor = 1.0f / params->cs;
|
||||||
|
header->offMeshBase = params->polyCount;
|
||||||
|
header->walkableHeight = params->walkableHeight;
|
||||||
|
header->walkableRadius = params->walkableRadius;
|
||||||
|
header->walkableClimb = params->walkableClimb;
|
||||||
|
header->offMeshConCount = storedOffMeshConCount;
|
||||||
|
header->bvNodeCount = params->buildBvTree ? params->polyCount*2 : 0;
|
||||||
|
|
||||||
|
const int offMeshVertsBase = params->vertCount;
|
||||||
|
const int offMeshPolyBase = params->polyCount;
|
||||||
|
|
||||||
|
// Store vertices
|
||||||
|
// Mesh vertices
|
||||||
|
for (int i = 0; i < params->vertCount; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* iv = ¶ms->verts[i*3];
|
||||||
|
float* v = &navVerts[i*3];
|
||||||
|
v[0] = params->bmin[0] + iv[0] * params->cs;
|
||||||
|
v[1] = params->bmin[1] + iv[1] * params->ch;
|
||||||
|
v[2] = params->bmin[2] + iv[2] * params->cs;
|
||||||
|
}
|
||||||
|
// Off-mesh link vertices.
|
||||||
|
int n = 0;
|
||||||
|
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||||
|
{
|
||||||
|
// Only store connections which start from this tile.
|
||||||
|
if (offMeshConClass[i*2+0] == 0xff)
|
||||||
|
{
|
||||||
|
const float* linkv = ¶ms->offMeshConVerts[i*2*3];
|
||||||
|
float* v = &navVerts[(offMeshVertsBase + n*2)*3];
|
||||||
|
dtVcopy(&v[0], &linkv[0]);
|
||||||
|
dtVcopy(&v[3], &linkv[3]);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store polygons
|
||||||
|
// Mesh polys
|
||||||
|
const unsigned short* src = params->polys;
|
||||||
|
for (int i = 0; i < params->polyCount; ++i)
|
||||||
|
{
|
||||||
|
dtPoly* p = &navPolys[i];
|
||||||
|
p->vertCount = 0;
|
||||||
|
p->flags = params->polyFlags[i];
|
||||||
|
p->setArea(params->polyAreas[i]);
|
||||||
|
p->setType(DT_POLYTYPE_GROUND);
|
||||||
|
for (int j = 0; j < nvp; ++j)
|
||||||
|
{
|
||||||
|
if (src[j] == MESH_NULL_IDX) break;
|
||||||
|
p->verts[j] = src[j];
|
||||||
|
if (src[nvp+j] & 0x8000)
|
||||||
|
{
|
||||||
|
// Border or portal edge.
|
||||||
|
unsigned short dir = src[nvp+j] & 0xf;
|
||||||
|
if (dir == 0xf) // Border
|
||||||
|
p->neis[j] = 0;
|
||||||
|
else if (dir == 0) // Portal x-
|
||||||
|
p->neis[j] = DT_EXT_LINK | 4;
|
||||||
|
else if (dir == 1) // Portal z+
|
||||||
|
p->neis[j] = DT_EXT_LINK | 2;
|
||||||
|
else if (dir == 2) // Portal x+
|
||||||
|
p->neis[j] = DT_EXT_LINK | 0;
|
||||||
|
else if (dir == 3) // Portal z-
|
||||||
|
p->neis[j] = DT_EXT_LINK | 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Normal connection
|
||||||
|
p->neis[j] = src[nvp+j]+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->vertCount++;
|
||||||
|
}
|
||||||
|
src += nvp*2;
|
||||||
|
}
|
||||||
|
// Off-mesh connection vertices.
|
||||||
|
n = 0;
|
||||||
|
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||||
|
{
|
||||||
|
// Only store connections which start from this tile.
|
||||||
|
if (offMeshConClass[i*2+0] == 0xff)
|
||||||
|
{
|
||||||
|
dtPoly* p = &navPolys[offMeshPolyBase+n];
|
||||||
|
p->vertCount = 2;
|
||||||
|
p->verts[0] = (unsigned short)(offMeshVertsBase + n*2+0);
|
||||||
|
p->verts[1] = (unsigned short)(offMeshVertsBase + n*2+1);
|
||||||
|
p->flags = params->offMeshConFlags[i];
|
||||||
|
p->setArea(params->offMeshConAreas[i]);
|
||||||
|
p->setType(DT_POLYTYPE_OFFMESH_CONNECTION);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store detail meshes and vertices.
|
||||||
|
// The nav polygon vertices are stored as the first vertices on each mesh.
|
||||||
|
// We compress the mesh data by skipping them and using the navmesh coordinates.
|
||||||
|
if (params->detailMeshes)
|
||||||
|
{
|
||||||
|
unsigned short vbase = 0;
|
||||||
|
for (int i = 0; i < params->polyCount; ++i)
|
||||||
|
{
|
||||||
|
dtPolyDetail& dtl = navDMeshes[i];
|
||||||
|
const int vb = (int)params->detailMeshes[i*4+0];
|
||||||
|
const int ndv = (int)params->detailMeshes[i*4+1];
|
||||||
|
const int nv = navPolys[i].vertCount;
|
||||||
|
dtl.vertBase = (unsigned int)vbase;
|
||||||
|
dtl.vertCount = (unsigned char)(ndv-nv);
|
||||||
|
dtl.triBase = (unsigned int)params->detailMeshes[i*4+2];
|
||||||
|
dtl.triCount = (unsigned char)params->detailMeshes[i*4+3];
|
||||||
|
// Copy vertices except the first 'nv' verts which are equal to nav poly verts.
|
||||||
|
if (ndv-nv)
|
||||||
|
{
|
||||||
|
memcpy(&navDVerts[vbase*3], ¶ms->detailVerts[(vb+nv)*3], sizeof(float)*3*(ndv-nv));
|
||||||
|
vbase += (unsigned short)(ndv-nv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Store triangles.
|
||||||
|
memcpy(navDTris, params->detailTris, sizeof(unsigned char)*4*params->detailTriCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create dummy detail mesh by triangulating polys.
|
||||||
|
int tbase = 0;
|
||||||
|
for (int i = 0; i < params->polyCount; ++i)
|
||||||
|
{
|
||||||
|
dtPolyDetail& dtl = navDMeshes[i];
|
||||||
|
const int nv = navPolys[i].vertCount;
|
||||||
|
dtl.vertBase = 0;
|
||||||
|
dtl.vertCount = 0;
|
||||||
|
dtl.triBase = (unsigned int)tbase;
|
||||||
|
dtl.triCount = (unsigned char)(nv-2);
|
||||||
|
// Triangulate polygon (local indices).
|
||||||
|
for (int j = 2; j < nv; ++j)
|
||||||
|
{
|
||||||
|
unsigned char* t = &navDTris[tbase*4];
|
||||||
|
t[0] = 0;
|
||||||
|
t[1] = (unsigned char)(j-1);
|
||||||
|
t[2] = (unsigned char)j;
|
||||||
|
// Bit for each edge that belongs to poly boundary.
|
||||||
|
t[3] = (1<<2);
|
||||||
|
if (j == 2) t[3] |= (1<<0);
|
||||||
|
if (j == nv-1) t[3] |= (1<<4);
|
||||||
|
tbase++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store and create BVtree.
|
||||||
|
if (params->buildBvTree)
|
||||||
|
{
|
||||||
|
createBVTree(params, navBvtree, 2*params->polyCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store Off-Mesh connections.
|
||||||
|
n = 0;
|
||||||
|
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||||
|
{
|
||||||
|
// Only store connections which start from this tile.
|
||||||
|
if (offMeshConClass[i*2+0] == 0xff)
|
||||||
|
{
|
||||||
|
dtOffMeshConnection* con = &offMeshCons[n];
|
||||||
|
con->poly = (unsigned short)(offMeshPolyBase + n);
|
||||||
|
// Copy connection end-points.
|
||||||
|
const float* endPts = ¶ms->offMeshConVerts[i*2*3];
|
||||||
|
dtVcopy(&con->pos[0], &endPts[0]);
|
||||||
|
dtVcopy(&con->pos[3], &endPts[3]);
|
||||||
|
con->rad = params->offMeshConRad[i];
|
||||||
|
con->flags = params->offMeshConDir[i] ? DT_OFFMESH_CON_BIDIR : 0;
|
||||||
|
con->side = offMeshConClass[i*2+1];
|
||||||
|
if (params->offMeshConUserID)
|
||||||
|
con->userId = params->offMeshConUserID[i];
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dtFree(offMeshConClass);
|
||||||
|
|
||||||
|
*outData = data;
|
||||||
|
*outDataSize = dataSize;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
|
{
|
||||||
|
dtMeshHeader* header = (dtMeshHeader*)data;
|
||||||
|
|
||||||
|
int swappedMagic = DT_NAVMESH_MAGIC;
|
||||||
|
int swappedVersion = DT_NAVMESH_VERSION;
|
||||||
|
dtSwapEndian(&swappedMagic);
|
||||||
|
dtSwapEndian(&swappedVersion);
|
||||||
|
|
||||||
|
if ((header->magic != DT_NAVMESH_MAGIC || header->version != DT_NAVMESH_VERSION) &&
|
||||||
|
(header->magic != swappedMagic || header->version != swappedVersion))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtSwapEndian(&header->magic);
|
||||||
|
dtSwapEndian(&header->version);
|
||||||
|
dtSwapEndian(&header->x);
|
||||||
|
dtSwapEndian(&header->y);
|
||||||
|
dtSwapEndian(&header->layer);
|
||||||
|
dtSwapEndian(&header->userId);
|
||||||
|
dtSwapEndian(&header->polyCount);
|
||||||
|
dtSwapEndian(&header->vertCount);
|
||||||
|
dtSwapEndian(&header->maxLinkCount);
|
||||||
|
dtSwapEndian(&header->detailMeshCount);
|
||||||
|
dtSwapEndian(&header->detailVertCount);
|
||||||
|
dtSwapEndian(&header->detailTriCount);
|
||||||
|
dtSwapEndian(&header->bvNodeCount);
|
||||||
|
dtSwapEndian(&header->offMeshConCount);
|
||||||
|
dtSwapEndian(&header->offMeshBase);
|
||||||
|
dtSwapEndian(&header->walkableHeight);
|
||||||
|
dtSwapEndian(&header->walkableRadius);
|
||||||
|
dtSwapEndian(&header->walkableClimb);
|
||||||
|
dtSwapEndian(&header->bmin[0]);
|
||||||
|
dtSwapEndian(&header->bmin[1]);
|
||||||
|
dtSwapEndian(&header->bmin[2]);
|
||||||
|
dtSwapEndian(&header->bmax[0]);
|
||||||
|
dtSwapEndian(&header->bmax[1]);
|
||||||
|
dtSwapEndian(&header->bmax[2]);
|
||||||
|
dtSwapEndian(&header->bvQuantFactor);
|
||||||
|
|
||||||
|
// Freelist index and pointers are updated when tile is added, no need to swap.
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// @warning This function assumes that the header is in the correct endianess already.
|
||||||
|
/// Call #dtNavMeshHeaderSwapEndian() first on the data if the data is expected to be in wrong endianess
|
||||||
|
/// to start with. Call #dtNavMeshHeaderSwapEndian() after the data has been swapped if converting from
|
||||||
|
/// native to foreign endianess.
|
||||||
|
bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
|
{
|
||||||
|
// Make sure the data is in right format.
|
||||||
|
dtMeshHeader* header = (dtMeshHeader*)data;
|
||||||
|
if (header->magic != DT_NAVMESH_MAGIC)
|
||||||
|
return false;
|
||||||
|
if (header->version != DT_NAVMESH_VERSION)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Patch header pointers.
|
||||||
|
const int headerSize = dtAlign4(sizeof(dtMeshHeader));
|
||||||
|
const int vertsSize = dtAlign4(sizeof(float)*3*header->vertCount);
|
||||||
|
const int polysSize = dtAlign4(sizeof(dtPoly)*header->polyCount);
|
||||||
|
const int linksSize = dtAlign4(sizeof(dtLink)*(header->maxLinkCount));
|
||||||
|
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*header->detailMeshCount);
|
||||||
|
const int detailVertsSize = dtAlign4(sizeof(float)*3*header->detailVertCount);
|
||||||
|
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*header->detailTriCount);
|
||||||
|
const int bvtreeSize = dtAlign4(sizeof(dtBVNode)*header->bvNodeCount);
|
||||||
|
const int offMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection)*header->offMeshConCount);
|
||||||
|
|
||||||
|
unsigned char* d = data + headerSize;
|
||||||
|
float* verts = dtGetThenAdvanceBufferPointer<float>(d, vertsSize);
|
||||||
|
dtPoly* polys = dtGetThenAdvanceBufferPointer<dtPoly>(d, polysSize);
|
||||||
|
d += linksSize; // Ignore links; they technically should be endian-swapped but all their data is overwritten on load anyway.
|
||||||
|
//dtLink* links = dtGetThenAdvanceBufferPointer<dtLink>(d, linksSize);
|
||||||
|
dtPolyDetail* detailMeshes = dtGetThenAdvanceBufferPointer<dtPolyDetail>(d, detailMeshesSize);
|
||||||
|
float* detailVerts = dtGetThenAdvanceBufferPointer<float>(d, detailVertsSize);
|
||||||
|
d += detailTrisSize; // Ignore detail tris; single bytes can't be endian-swapped.
|
||||||
|
//unsigned char* detailTris = dtGetThenAdvanceBufferPointer<unsigned char>(d, detailTrisSize);
|
||||||
|
dtBVNode* bvTree = dtGetThenAdvanceBufferPointer<dtBVNode>(d, bvtreeSize);
|
||||||
|
dtOffMeshConnection* offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, offMeshLinksSize);
|
||||||
|
|
||||||
|
// Vertices
|
||||||
|
for (int i = 0; i < header->vertCount*3; ++i)
|
||||||
|
{
|
||||||
|
dtSwapEndian(&verts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polys
|
||||||
|
for (int i = 0; i < header->polyCount; ++i)
|
||||||
|
{
|
||||||
|
dtPoly* p = &polys[i];
|
||||||
|
// poly->firstLink is update when tile is added, no need to swap.
|
||||||
|
for (int j = 0; j < DT_VERTS_PER_POLYGON; ++j)
|
||||||
|
{
|
||||||
|
dtSwapEndian(&p->verts[j]);
|
||||||
|
dtSwapEndian(&p->neis[j]);
|
||||||
|
}
|
||||||
|
dtSwapEndian(&p->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Links are rebuild when tile is added, no need to swap.
|
||||||
|
|
||||||
|
// Detail meshes
|
||||||
|
for (int i = 0; i < header->detailMeshCount; ++i)
|
||||||
|
{
|
||||||
|
dtPolyDetail* pd = &detailMeshes[i];
|
||||||
|
dtSwapEndian(&pd->vertBase);
|
||||||
|
dtSwapEndian(&pd->triBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detail verts
|
||||||
|
for (int i = 0; i < header->detailVertCount*3; ++i)
|
||||||
|
{
|
||||||
|
dtSwapEndian(&detailVerts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BV-tree
|
||||||
|
for (int i = 0; i < header->bvNodeCount; ++i)
|
||||||
|
{
|
||||||
|
dtBVNode* node = &bvTree[i];
|
||||||
|
for (int j = 0; j < 3; ++j)
|
||||||
|
{
|
||||||
|
dtSwapEndian(&node->bmin[j]);
|
||||||
|
dtSwapEndian(&node->bmax[j]);
|
||||||
|
}
|
||||||
|
dtSwapEndian(&node->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Off-mesh Connections.
|
||||||
|
for (int i = 0; i < header->offMeshConCount; ++i)
|
||||||
|
{
|
||||||
|
dtOffMeshConnection* con = &offMeshCons[i];
|
||||||
|
for (int j = 0; j < 6; ++j)
|
||||||
|
dtSwapEndian(&con->pos[j]);
|
||||||
|
dtSwapEndian(&con->rad);
|
||||||
|
dtSwapEndian(&con->poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.x11.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.x11.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.x11.opt.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.x11.opt.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.x11.opt.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.x11.opt.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.x11.opt.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.x11.opt.tools.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.x11.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshBuilder.x11.tools.64.o
vendored
Normal file
Binary file not shown.
3679
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.cpp
vendored
Normal file
3679
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.x11.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.x11.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.x11.opt.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.x11.opt.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.x11.opt.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.x11.opt.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.x11.opt.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.x11.opt.tools.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.x11.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNavMeshQuery.x11.tools.64.o
vendored
Normal file
Binary file not shown.
200
modules/detour/thirdparty/Detour/Source/DetourNode.cpp
vendored
Normal file
200
modules/detour/thirdparty/Detour/Source/DetourNode.cpp
vendored
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "DetourNode.h"
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
#include "DetourAssert.h"
|
||||||
|
#include "DetourCommon.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef DT_POLYREF64
|
||||||
|
// From Thomas Wang, https://gist.github.com/badboy/6267743
|
||||||
|
inline unsigned int dtHashRef(dtPolyRef a)
|
||||||
|
{
|
||||||
|
a = (~a) + (a << 18); // a = (a << 18) - a - 1;
|
||||||
|
a = a ^ (a >> 31);
|
||||||
|
a = a * 21; // a = (a + (a << 2)) + (a << 4);
|
||||||
|
a = a ^ (a >> 11);
|
||||||
|
a = a + (a << 6);
|
||||||
|
a = a ^ (a >> 22);
|
||||||
|
return (unsigned int)a;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
inline unsigned int dtHashRef(dtPolyRef a)
|
||||||
|
{
|
||||||
|
a += ~(a<<15);
|
||||||
|
a ^= (a>>10);
|
||||||
|
a += (a<<3);
|
||||||
|
a ^= (a>>6);
|
||||||
|
a += ~(a<<11);
|
||||||
|
a ^= (a>>16);
|
||||||
|
return (unsigned int)a;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
dtNodePool::dtNodePool(int maxNodes, int hashSize) :
|
||||||
|
m_nodes(0),
|
||||||
|
m_first(0),
|
||||||
|
m_next(0),
|
||||||
|
m_maxNodes(maxNodes),
|
||||||
|
m_hashSize(hashSize),
|
||||||
|
m_nodeCount(0)
|
||||||
|
{
|
||||||
|
dtAssert(dtNextPow2(m_hashSize) == (unsigned int)m_hashSize);
|
||||||
|
// pidx is special as 0 means "none" and 1 is the first node. For that reason
|
||||||
|
// we have 1 fewer nodes available than the number of values it can contain.
|
||||||
|
dtAssert(m_maxNodes > 0 && m_maxNodes <= DT_NULL_IDX && m_maxNodes <= (1 << DT_NODE_PARENT_BITS) - 1);
|
||||||
|
|
||||||
|
m_nodes = (dtNode*)dtAlloc(sizeof(dtNode)*m_maxNodes, DT_ALLOC_PERM);
|
||||||
|
m_next = (dtNodeIndex*)dtAlloc(sizeof(dtNodeIndex)*m_maxNodes, DT_ALLOC_PERM);
|
||||||
|
m_first = (dtNodeIndex*)dtAlloc(sizeof(dtNodeIndex)*hashSize, DT_ALLOC_PERM);
|
||||||
|
|
||||||
|
dtAssert(m_nodes);
|
||||||
|
dtAssert(m_next);
|
||||||
|
dtAssert(m_first);
|
||||||
|
|
||||||
|
memset(m_first, 0xff, sizeof(dtNodeIndex)*m_hashSize);
|
||||||
|
memset(m_next, 0xff, sizeof(dtNodeIndex)*m_maxNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtNodePool::~dtNodePool()
|
||||||
|
{
|
||||||
|
dtFree(m_nodes);
|
||||||
|
dtFree(m_next);
|
||||||
|
dtFree(m_first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtNodePool::clear()
|
||||||
|
{
|
||||||
|
memset(m_first, 0xff, sizeof(dtNodeIndex)*m_hashSize);
|
||||||
|
m_nodeCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int dtNodePool::findNodes(dtPolyRef id, dtNode** nodes, const int maxNodes)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
||||||
|
dtNodeIndex i = m_first[bucket];
|
||||||
|
while (i != DT_NULL_IDX)
|
||||||
|
{
|
||||||
|
if (m_nodes[i].id == id)
|
||||||
|
{
|
||||||
|
if (n >= maxNodes)
|
||||||
|
return n;
|
||||||
|
nodes[n++] = &m_nodes[i];
|
||||||
|
}
|
||||||
|
i = m_next[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtNode* dtNodePool::findNode(dtPolyRef id, unsigned char state)
|
||||||
|
{
|
||||||
|
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
||||||
|
dtNodeIndex i = m_first[bucket];
|
||||||
|
while (i != DT_NULL_IDX)
|
||||||
|
{
|
||||||
|
if (m_nodes[i].id == id && m_nodes[i].state == state)
|
||||||
|
return &m_nodes[i];
|
||||||
|
i = m_next[i];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtNode* dtNodePool::getNode(dtPolyRef id, unsigned char state)
|
||||||
|
{
|
||||||
|
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
||||||
|
dtNodeIndex i = m_first[bucket];
|
||||||
|
dtNode* node = 0;
|
||||||
|
while (i != DT_NULL_IDX)
|
||||||
|
{
|
||||||
|
if (m_nodes[i].id == id && m_nodes[i].state == state)
|
||||||
|
return &m_nodes[i];
|
||||||
|
i = m_next[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_nodeCount >= m_maxNodes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
i = (dtNodeIndex)m_nodeCount;
|
||||||
|
m_nodeCount++;
|
||||||
|
|
||||||
|
// Init node
|
||||||
|
node = &m_nodes[i];
|
||||||
|
node->pidx = 0;
|
||||||
|
node->cost = 0;
|
||||||
|
node->total = 0;
|
||||||
|
node->id = id;
|
||||||
|
node->state = state;
|
||||||
|
node->flags = 0;
|
||||||
|
|
||||||
|
m_next[i] = m_first[bucket];
|
||||||
|
m_first[bucket] = i;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
dtNodeQueue::dtNodeQueue(int n) :
|
||||||
|
m_heap(0),
|
||||||
|
m_capacity(n),
|
||||||
|
m_size(0)
|
||||||
|
{
|
||||||
|
dtAssert(m_capacity > 0);
|
||||||
|
|
||||||
|
m_heap = (dtNode**)dtAlloc(sizeof(dtNode*)*(m_capacity+1), DT_ALLOC_PERM);
|
||||||
|
dtAssert(m_heap);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtNodeQueue::~dtNodeQueue()
|
||||||
|
{
|
||||||
|
dtFree(m_heap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtNodeQueue::bubbleUp(int i, dtNode* node)
|
||||||
|
{
|
||||||
|
int parent = (i-1)/2;
|
||||||
|
// note: (index > 0) means there is a parent
|
||||||
|
while ((i > 0) && (m_heap[parent]->total > node->total))
|
||||||
|
{
|
||||||
|
m_heap[i] = m_heap[parent];
|
||||||
|
i = parent;
|
||||||
|
parent = (i-1)/2;
|
||||||
|
}
|
||||||
|
m_heap[i] = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtNodeQueue::trickleDown(int i, dtNode* node)
|
||||||
|
{
|
||||||
|
int child = (i*2)+1;
|
||||||
|
while (child < m_size)
|
||||||
|
{
|
||||||
|
if (((child+1) < m_size) &&
|
||||||
|
(m_heap[child]->total > m_heap[child+1]->total))
|
||||||
|
{
|
||||||
|
child++;
|
||||||
|
}
|
||||||
|
m_heap[i] = m_heap[child];
|
||||||
|
i = child;
|
||||||
|
child = (i*2)+1;
|
||||||
|
}
|
||||||
|
bubbleUp(i, node);
|
||||||
|
}
|
||||||
BIN
modules/detour/thirdparty/Detour/Source/DetourNode.x11.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNode.x11.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNode.x11.opt.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNode.x11.opt.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNode.x11.opt.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNode.x11.opt.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNode.x11.opt.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNode.x11.opt.tools.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/Detour/Source/DetourNode.x11.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/Detour/Source/DetourNode.x11.tools.64.o
vendored
Normal file
Binary file not shown.
460
modules/detour/thirdparty/DetourCrowd/Include/DetourCrowd.h
vendored
Normal file
460
modules/detour/thirdparty/DetourCrowd/Include/DetourCrowd.h
vendored
Normal file
@@ -0,0 +1,460 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURCROWD_H
|
||||||
|
#define DETOURCROWD_H
|
||||||
|
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
#include "DetourObstacleAvoidance.h"
|
||||||
|
#include "DetourLocalBoundary.h"
|
||||||
|
#include "DetourPathCorridor.h"
|
||||||
|
#include "DetourProximityGrid.h"
|
||||||
|
#include "DetourPathQueue.h"
|
||||||
|
|
||||||
|
/// The maximum number of neighbors that a crowd agent can take into account
|
||||||
|
/// for steering decisions.
|
||||||
|
/// @ingroup crowd
|
||||||
|
static const int DT_CROWDAGENT_MAX_NEIGHBOURS = 6;
|
||||||
|
|
||||||
|
/// The maximum number of corners a crowd agent will look ahead in the path.
|
||||||
|
/// This value is used for sizing the crowd agent corner buffers.
|
||||||
|
/// Due to the behavior of the crowd manager, the actual number of useful
|
||||||
|
/// corners will be one less than this number.
|
||||||
|
/// @ingroup crowd
|
||||||
|
static const int DT_CROWDAGENT_MAX_CORNERS = 4;
|
||||||
|
|
||||||
|
/// The maximum number of crowd avoidance configurations supported by the
|
||||||
|
/// crowd manager.
|
||||||
|
/// @ingroup crowd
|
||||||
|
/// @see dtObstacleAvoidanceParams, dtCrowd::setObstacleAvoidanceParams(), dtCrowd::getObstacleAvoidanceParams(),
|
||||||
|
/// dtCrowdAgentParams::obstacleAvoidanceType
|
||||||
|
static const int DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS = 8;
|
||||||
|
|
||||||
|
/// The maximum number of query filter types supported by the crowd manager.
|
||||||
|
/// @ingroup crowd
|
||||||
|
/// @see dtQueryFilter, dtCrowd::getFilter() dtCrowd::getEditableFilter(),
|
||||||
|
/// dtCrowdAgentParams::queryFilterType
|
||||||
|
static const int DT_CROWD_MAX_QUERY_FILTER_TYPE = 16;
|
||||||
|
|
||||||
|
/// Provides neighbor data for agents managed by the crowd.
|
||||||
|
/// @ingroup crowd
|
||||||
|
/// @see dtCrowdAgent::neis, dtCrowd
|
||||||
|
struct dtCrowdNeighbour
|
||||||
|
{
|
||||||
|
int idx; ///< The index of the neighbor in the crowd.
|
||||||
|
float dist; ///< The distance between the current agent and the neighbor.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The type of navigation mesh polygon the agent is currently traversing.
|
||||||
|
/// @ingroup crowd
|
||||||
|
enum CrowdAgentState
|
||||||
|
{
|
||||||
|
DT_CROWDAGENT_STATE_INVALID, ///< The agent is not in a valid state.
|
||||||
|
DT_CROWDAGENT_STATE_WALKING, ///< The agent is traversing a normal navigation mesh polygon.
|
||||||
|
DT_CROWDAGENT_STATE_OFFMESH, ///< The agent is traversing an off-mesh connection.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Configuration parameters for a crowd agent.
|
||||||
|
/// @ingroup crowd
|
||||||
|
struct dtCrowdAgentParams
|
||||||
|
{
|
||||||
|
float radius; ///< Agent radius. [Limit: >= 0]
|
||||||
|
float height; ///< Agent height. [Limit: > 0]
|
||||||
|
float maxAcceleration; ///< Maximum allowed acceleration. [Limit: >= 0]
|
||||||
|
float maxSpeed; ///< Maximum allowed speed. [Limit: >= 0]
|
||||||
|
|
||||||
|
/// Defines how close a collision element must be before it is considered for steering behaviors. [Limits: > 0]
|
||||||
|
float collisionQueryRange;
|
||||||
|
|
||||||
|
float pathOptimizationRange; ///< The path visibility optimization range. [Limit: > 0]
|
||||||
|
|
||||||
|
/// How aggresive the agent manager should be at avoiding collisions with this agent. [Limit: >= 0]
|
||||||
|
float separationWeight;
|
||||||
|
|
||||||
|
/// Flags that impact steering behavior. (See: #UpdateFlags)
|
||||||
|
unsigned char updateFlags;
|
||||||
|
|
||||||
|
/// The index of the avoidance configuration to use for the agent.
|
||||||
|
/// [Limits: 0 <= value <= #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
|
||||||
|
unsigned char obstacleAvoidanceType;
|
||||||
|
|
||||||
|
/// The index of the query filter used by this agent.
|
||||||
|
unsigned char queryFilterType;
|
||||||
|
|
||||||
|
/// User defined data attached to the agent.
|
||||||
|
void* userData;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MoveRequestState
|
||||||
|
{
|
||||||
|
DT_CROWDAGENT_TARGET_NONE = 0,
|
||||||
|
DT_CROWDAGENT_TARGET_FAILED,
|
||||||
|
DT_CROWDAGENT_TARGET_VALID,
|
||||||
|
DT_CROWDAGENT_TARGET_REQUESTING,
|
||||||
|
DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE,
|
||||||
|
DT_CROWDAGENT_TARGET_WAITING_FOR_PATH,
|
||||||
|
DT_CROWDAGENT_TARGET_VELOCITY,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Represents an agent managed by a #dtCrowd object.
|
||||||
|
/// @ingroup crowd
|
||||||
|
struct dtCrowdAgent
|
||||||
|
{
|
||||||
|
/// True if the agent is active, false if the agent is in an unused slot in the agent pool.
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
/// The type of mesh polygon the agent is traversing. (See: #CrowdAgentState)
|
||||||
|
unsigned char state;
|
||||||
|
|
||||||
|
/// True if the agent has valid path (targetState == DT_CROWDAGENT_TARGET_VALID) and the path does not lead to the requested position, else false.
|
||||||
|
bool partial;
|
||||||
|
|
||||||
|
/// The path corridor the agent is using.
|
||||||
|
dtPathCorridor corridor;
|
||||||
|
|
||||||
|
/// The local boundary data for the agent.
|
||||||
|
dtLocalBoundary boundary;
|
||||||
|
|
||||||
|
/// Time since the agent's path corridor was optimized.
|
||||||
|
float topologyOptTime;
|
||||||
|
|
||||||
|
/// The known neighbors of the agent.
|
||||||
|
dtCrowdNeighbour neis[DT_CROWDAGENT_MAX_NEIGHBOURS];
|
||||||
|
|
||||||
|
/// The number of neighbors.
|
||||||
|
int nneis;
|
||||||
|
|
||||||
|
/// The desired speed.
|
||||||
|
float desiredSpeed;
|
||||||
|
|
||||||
|
float npos[3]; ///< The current agent position. [(x, y, z)]
|
||||||
|
float disp[3]; ///< A temporary value used to accumulate agent displacement during iterative collision resolution. [(x, y, z)]
|
||||||
|
float dvel[3]; ///< The desired velocity of the agent. Based on the current path, calculated from scratch each frame. [(x, y, z)]
|
||||||
|
float nvel[3]; ///< The desired velocity adjusted by obstacle avoidance, calculated from scratch each frame. [(x, y, z)]
|
||||||
|
float vel[3]; ///< The actual velocity of the agent. The change from nvel -> vel is constrained by max acceleration. [(x, y, z)]
|
||||||
|
|
||||||
|
/// The agent's configuration parameters.
|
||||||
|
dtCrowdAgentParams params;
|
||||||
|
|
||||||
|
/// The local path corridor corners for the agent. (Staight path.) [(x, y, z) * #ncorners]
|
||||||
|
float cornerVerts[DT_CROWDAGENT_MAX_CORNERS*3];
|
||||||
|
|
||||||
|
/// The local path corridor corner flags. (See: #dtStraightPathFlags) [(flags) * #ncorners]
|
||||||
|
unsigned char cornerFlags[DT_CROWDAGENT_MAX_CORNERS];
|
||||||
|
|
||||||
|
/// The reference id of the polygon being entered at the corner. [(polyRef) * #ncorners]
|
||||||
|
dtPolyRef cornerPolys[DT_CROWDAGENT_MAX_CORNERS];
|
||||||
|
|
||||||
|
/// The number of corners.
|
||||||
|
int ncorners;
|
||||||
|
|
||||||
|
unsigned char targetState; ///< State of the movement request.
|
||||||
|
dtPolyRef targetRef; ///< Target polyref of the movement request.
|
||||||
|
float targetPos[3]; ///< Target position of the movement request (or velocity in case of DT_CROWDAGENT_TARGET_VELOCITY).
|
||||||
|
dtPathQueueRef targetPathqRef; ///< Path finder ref.
|
||||||
|
bool targetReplan; ///< Flag indicating that the current path is being replanned.
|
||||||
|
float targetReplanTime; /// <Time since the agent's target was replanned.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtCrowdAgentAnimation
|
||||||
|
{
|
||||||
|
bool active;
|
||||||
|
float initPos[3], startPos[3], endPos[3];
|
||||||
|
dtPolyRef polyRef;
|
||||||
|
float t, tmax;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Crowd agent update flags.
|
||||||
|
/// @ingroup crowd
|
||||||
|
/// @see dtCrowdAgentParams::updateFlags
|
||||||
|
enum UpdateFlags
|
||||||
|
{
|
||||||
|
DT_CROWD_ANTICIPATE_TURNS = 1,
|
||||||
|
DT_CROWD_OBSTACLE_AVOIDANCE = 2,
|
||||||
|
DT_CROWD_SEPARATION = 4,
|
||||||
|
DT_CROWD_OPTIMIZE_VIS = 8, ///< Use #dtPathCorridor::optimizePathVisibility() to optimize the agent path.
|
||||||
|
DT_CROWD_OPTIMIZE_TOPO = 16, ///< Use dtPathCorridor::optimizePathTopology() to optimize the agent path.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtCrowdAgentDebugInfo
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
float optStart[3], optEnd[3];
|
||||||
|
dtObstacleAvoidanceDebugData* vod;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides local steering behaviors for a group of agents.
|
||||||
|
/// @ingroup crowd
|
||||||
|
class dtCrowd
|
||||||
|
{
|
||||||
|
int m_maxAgents;
|
||||||
|
dtCrowdAgent* m_agents;
|
||||||
|
dtCrowdAgent** m_activeAgents;
|
||||||
|
dtCrowdAgentAnimation* m_agentAnims;
|
||||||
|
|
||||||
|
dtPathQueue m_pathq;
|
||||||
|
|
||||||
|
dtObstacleAvoidanceParams m_obstacleQueryParams[DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS];
|
||||||
|
dtObstacleAvoidanceQuery* m_obstacleQuery;
|
||||||
|
|
||||||
|
dtProximityGrid* m_grid;
|
||||||
|
|
||||||
|
dtPolyRef* m_pathResult;
|
||||||
|
int m_maxPathResult;
|
||||||
|
|
||||||
|
float m_agentPlacementHalfExtents[3];
|
||||||
|
|
||||||
|
dtQueryFilter m_filters[DT_CROWD_MAX_QUERY_FILTER_TYPE];
|
||||||
|
|
||||||
|
float m_maxAgentRadius;
|
||||||
|
|
||||||
|
int m_velocitySampleCount;
|
||||||
|
|
||||||
|
dtNavMeshQuery* m_navquery;
|
||||||
|
|
||||||
|
void updateTopologyOptimization(dtCrowdAgent** agents, const int nagents, const float dt);
|
||||||
|
void updateMoveRequest(const float dt);
|
||||||
|
void checkPathValidity(dtCrowdAgent** agents, const int nagents, const float dt);
|
||||||
|
|
||||||
|
inline int getAgentIndex(const dtCrowdAgent* agent) const { return (int)(agent - m_agents); }
|
||||||
|
|
||||||
|
bool requestMoveTargetReplan(const int idx, dtPolyRef ref, const float* pos);
|
||||||
|
|
||||||
|
void purge();
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtCrowd();
|
||||||
|
~dtCrowd();
|
||||||
|
|
||||||
|
/// Initializes the crowd.
|
||||||
|
/// @param[in] maxAgents The maximum number of agents the crowd can manage. [Limit: >= 1]
|
||||||
|
/// @param[in] maxAgentRadius The maximum radius of any agent that will be added to the crowd. [Limit: > 0]
|
||||||
|
/// @param[in] nav The navigation mesh to use for planning.
|
||||||
|
/// @return True if the initialization succeeded.
|
||||||
|
bool init(const int maxAgents, const float maxAgentRadius, dtNavMesh* nav);
|
||||||
|
|
||||||
|
/// Sets the shared avoidance configuration for the specified index.
|
||||||
|
/// @param[in] idx The index. [Limits: 0 <= value < #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
|
||||||
|
/// @param[in] params The new configuration.
|
||||||
|
void setObstacleAvoidanceParams(const int idx, const dtObstacleAvoidanceParams* params);
|
||||||
|
|
||||||
|
/// Gets the shared avoidance configuration for the specified index.
|
||||||
|
/// @param[in] idx The index of the configuration to retreive.
|
||||||
|
/// [Limits: 0 <= value < #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
|
||||||
|
/// @return The requested configuration.
|
||||||
|
const dtObstacleAvoidanceParams* getObstacleAvoidanceParams(const int idx) const;
|
||||||
|
|
||||||
|
/// Gets the specified agent from the pool.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @return The requested agent.
|
||||||
|
const dtCrowdAgent* getAgent(const int idx);
|
||||||
|
|
||||||
|
/// Gets the specified agent from the pool.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @return The requested agent.
|
||||||
|
dtCrowdAgent* getEditableAgent(const int idx);
|
||||||
|
|
||||||
|
/// The maximum number of agents that can be managed by the object.
|
||||||
|
/// @return The maximum number of agents.
|
||||||
|
int getAgentCount() const;
|
||||||
|
|
||||||
|
/// Adds a new agent to the crowd.
|
||||||
|
/// @param[in] pos The requested position of the agent. [(x, y, z)]
|
||||||
|
/// @param[in] params The configutation of the agent.
|
||||||
|
/// @return The index of the agent in the agent pool. Or -1 if the agent could not be added.
|
||||||
|
int addAgent(const float* pos, const dtCrowdAgentParams* params);
|
||||||
|
|
||||||
|
/// Updates the specified agent's configuration.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @param[in] params The new agent configuration.
|
||||||
|
void updateAgentParameters(const int idx, const dtCrowdAgentParams* params);
|
||||||
|
|
||||||
|
/// Removes the agent from the crowd.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
void removeAgent(const int idx);
|
||||||
|
|
||||||
|
/// Submits a new move request for the specified agent.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @param[in] ref The position's polygon reference.
|
||||||
|
/// @param[in] pos The position within the polygon. [(x, y, z)]
|
||||||
|
/// @return True if the request was successfully submitted.
|
||||||
|
bool requestMoveTarget(const int idx, dtPolyRef ref, const float* pos);
|
||||||
|
|
||||||
|
/// Submits a new move request for the specified agent.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @param[in] vel The movement velocity. [(x, y, z)]
|
||||||
|
/// @return True if the request was successfully submitted.
|
||||||
|
bool requestMoveVelocity(const int idx, const float* vel);
|
||||||
|
|
||||||
|
/// Resets any request for the specified agent.
|
||||||
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
|
||||||
|
/// @return True if the request was successfully reseted.
|
||||||
|
bool resetMoveTarget(const int idx);
|
||||||
|
|
||||||
|
/// Gets the active agents int the agent pool.
|
||||||
|
/// @param[out] agents An array of agent pointers. [(#dtCrowdAgent *) * maxAgents]
|
||||||
|
/// @param[in] maxAgents The size of the crowd agent array.
|
||||||
|
/// @return The number of agents returned in @p agents.
|
||||||
|
int getActiveAgents(dtCrowdAgent** agents, const int maxAgents);
|
||||||
|
|
||||||
|
/// Updates the steering and positions of all agents.
|
||||||
|
/// @param[in] dt The time, in seconds, to update the simulation. [Limit: > 0]
|
||||||
|
/// @param[out] debug A debug object to load with debug information. [Opt]
|
||||||
|
void update(const float dt, dtCrowdAgentDebugInfo* debug);
|
||||||
|
|
||||||
|
/// Gets the filter used by the crowd.
|
||||||
|
/// @return The filter used by the crowd.
|
||||||
|
inline const dtQueryFilter* getFilter(const int i) const { return (i >= 0 && i < DT_CROWD_MAX_QUERY_FILTER_TYPE) ? &m_filters[i] : 0; }
|
||||||
|
|
||||||
|
/// Gets the filter used by the crowd.
|
||||||
|
/// @return The filter used by the crowd.
|
||||||
|
inline dtQueryFilter* getEditableFilter(const int i) { return (i >= 0 && i < DT_CROWD_MAX_QUERY_FILTER_TYPE) ? &m_filters[i] : 0; }
|
||||||
|
|
||||||
|
/// Gets the search halfExtents [(x, y, z)] used by the crowd for query operations.
|
||||||
|
/// @return The search halfExtents used by the crowd. [(x, y, z)]
|
||||||
|
const float* getQueryHalfExtents() const { return m_agentPlacementHalfExtents; }
|
||||||
|
|
||||||
|
/// Same as getQueryHalfExtents. Left to maintain backwards compatibility.
|
||||||
|
/// @return The search halfExtents used by the crowd. [(x, y, z)]
|
||||||
|
const float* getQueryExtents() const { return m_agentPlacementHalfExtents; }
|
||||||
|
|
||||||
|
/// Gets the velocity sample count.
|
||||||
|
/// @return The velocity sample count.
|
||||||
|
inline int getVelocitySampleCount() const { return m_velocitySampleCount; }
|
||||||
|
|
||||||
|
/// Gets the crowd's proximity grid.
|
||||||
|
/// @return The crowd's proximity grid.
|
||||||
|
const dtProximityGrid* getGrid() const { return m_grid; }
|
||||||
|
|
||||||
|
/// Gets the crowd's path request queue.
|
||||||
|
/// @return The crowd's path request queue.
|
||||||
|
const dtPathQueue* getPathQueue() const { return &m_pathq; }
|
||||||
|
|
||||||
|
/// Gets the query object used by the crowd.
|
||||||
|
const dtNavMeshQuery* getNavMeshQuery() const { return m_navquery; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Explicitly disabled copy constructor and copy assignment operator.
|
||||||
|
dtCrowd(const dtCrowd&);
|
||||||
|
dtCrowd& operator=(const dtCrowd&);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Allocates a crowd object using the Detour allocator.
|
||||||
|
/// @return A crowd object that is ready for initialization, or null on failure.
|
||||||
|
/// @ingroup crowd
|
||||||
|
dtCrowd* dtAllocCrowd();
|
||||||
|
|
||||||
|
/// Frees the specified crowd object using the Detour allocator.
|
||||||
|
/// @param[in] ptr A crowd object allocated using #dtAllocCrowd
|
||||||
|
/// @ingroup crowd
|
||||||
|
void dtFreeCrowd(dtCrowd* ptr);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DETOURCROWD_H
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// This section contains detailed documentation for members that don't have
|
||||||
|
// a source file. It reduces clutter in the main section of the header.
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
@defgroup crowd Crowd
|
||||||
|
|
||||||
|
Members in this module implement local steering and dynamic avoidance features.
|
||||||
|
|
||||||
|
The crowd is the big beast of the navigation features. It not only handles a
|
||||||
|
lot of the path management for you, but also local steering and dynamic
|
||||||
|
avoidance between members of the crowd. I.e. It can keep your agents from
|
||||||
|
running into each other.
|
||||||
|
|
||||||
|
Main class: #dtCrowd
|
||||||
|
|
||||||
|
The #dtNavMeshQuery and #dtPathCorridor classes provide perfectly good, easy
|
||||||
|
to use path planning features. But in the end they only give you points that
|
||||||
|
your navigation client should be moving toward. When it comes to deciding things
|
||||||
|
like agent velocity and steering to avoid other agents, that is up to you to
|
||||||
|
implement. Unless, of course, you decide to use #dtCrowd.
|
||||||
|
|
||||||
|
Basically, you add an agent to the crowd, providing various configuration
|
||||||
|
settings such as maximum speed and acceleration. You also provide a local
|
||||||
|
target to more toward. The crowd manager then provides, with every update, the
|
||||||
|
new agent position and velocity for the frame. The movement will be
|
||||||
|
constrained to the navigation mesh, and steering will be applied to ensure
|
||||||
|
agents managed by the crowd do not collide with each other.
|
||||||
|
|
||||||
|
This is very powerful feature set. But it comes with limitations.
|
||||||
|
|
||||||
|
The biggest limitation is that you must give control of the agent's position
|
||||||
|
completely over to the crowd manager. You can update things like maximum speed
|
||||||
|
and acceleration. But in order for the crowd manager to do its thing, it can't
|
||||||
|
allow you to constantly be giving it overrides to position and velocity. So
|
||||||
|
you give up direct control of the agent's movement. It belongs to the crowd.
|
||||||
|
|
||||||
|
The second biggest limitation revolves around the fact that the crowd manager
|
||||||
|
deals with local planning. So the agent's target should never be more than
|
||||||
|
256 polygons aways from its current position. If it is, you risk
|
||||||
|
your agent failing to reach its target. So you may still need to do long
|
||||||
|
distance planning and provide the crowd manager with intermediate targets.
|
||||||
|
|
||||||
|
Other significant limitations:
|
||||||
|
|
||||||
|
- All agents using the crowd manager will use the same #dtQueryFilter.
|
||||||
|
- Crowd management is relatively expensive. The maximum agents under crowd
|
||||||
|
management at any one time is between 20 and 30. A good place to start
|
||||||
|
is a maximum of 25 agents for 0.5ms per frame.
|
||||||
|
|
||||||
|
@note This is a summary list of members. Use the index or search
|
||||||
|
feature to find minor members.
|
||||||
|
|
||||||
|
@struct dtCrowdAgentParams
|
||||||
|
@see dtCrowdAgent, dtCrowd::addAgent(), dtCrowd::updateAgentParameters()
|
||||||
|
|
||||||
|
@var dtCrowdAgentParams::obstacleAvoidanceType
|
||||||
|
@par
|
||||||
|
|
||||||
|
#dtCrowd permits agents to use different avoidance configurations. This value
|
||||||
|
is the index of the #dtObstacleAvoidanceParams within the crowd.
|
||||||
|
|
||||||
|
@see dtObstacleAvoidanceParams, dtCrowd::setObstacleAvoidanceParams(),
|
||||||
|
dtCrowd::getObstacleAvoidanceParams()
|
||||||
|
|
||||||
|
@var dtCrowdAgentParams::collisionQueryRange
|
||||||
|
@par
|
||||||
|
|
||||||
|
Collision elements include other agents and navigation mesh boundaries.
|
||||||
|
|
||||||
|
This value is often based on the agent radius and/or maximum speed. E.g. radius * 8
|
||||||
|
|
||||||
|
@var dtCrowdAgentParams::pathOptimizationRange
|
||||||
|
@par
|
||||||
|
|
||||||
|
Only applicalbe if #updateFlags includes the #DT_CROWD_OPTIMIZE_VIS flag.
|
||||||
|
|
||||||
|
This value is often based on the agent radius. E.g. radius * 30
|
||||||
|
|
||||||
|
@see dtPathCorridor::optimizePathVisibility()
|
||||||
|
|
||||||
|
@var dtCrowdAgentParams::separationWeight
|
||||||
|
@par
|
||||||
|
|
||||||
|
A higher value will result in agents trying to stay farther away from each other at
|
||||||
|
the cost of more difficult steering in tight spaces.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
66
modules/detour/thirdparty/DetourCrowd/Include/DetourLocalBoundary.h
vendored
Normal file
66
modules/detour/thirdparty/DetourCrowd/Include/DetourLocalBoundary.h
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURLOCALBOUNDARY_H
|
||||||
|
#define DETOURLOCALBOUNDARY_H
|
||||||
|
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
|
||||||
|
|
||||||
|
class dtLocalBoundary
|
||||||
|
{
|
||||||
|
static const int MAX_LOCAL_SEGS = 8;
|
||||||
|
static const int MAX_LOCAL_POLYS = 16;
|
||||||
|
|
||||||
|
struct Segment
|
||||||
|
{
|
||||||
|
float s[6]; ///< Segment start/end
|
||||||
|
float d; ///< Distance for pruning.
|
||||||
|
};
|
||||||
|
|
||||||
|
float m_center[3];
|
||||||
|
Segment m_segs[MAX_LOCAL_SEGS];
|
||||||
|
int m_nsegs;
|
||||||
|
|
||||||
|
dtPolyRef m_polys[MAX_LOCAL_POLYS];
|
||||||
|
int m_npolys;
|
||||||
|
|
||||||
|
void addSegment(const float dist, const float* s);
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtLocalBoundary();
|
||||||
|
~dtLocalBoundary();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void update(dtPolyRef ref, const float* pos, const float collisionQueryRange,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
bool isValid(dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
inline const float* getCenter() const { return m_center; }
|
||||||
|
inline int getSegmentCount() const { return m_nsegs; }
|
||||||
|
inline const float* getSegment(int i) const { return m_segs[i].s; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Explicitly disabled copy constructor and copy assignment operator.
|
||||||
|
dtLocalBoundary(const dtLocalBoundary&);
|
||||||
|
dtLocalBoundary& operator=(const dtLocalBoundary&);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DETOURLOCALBOUNDARY_H
|
||||||
159
modules/detour/thirdparty/DetourCrowd/Include/DetourObstacleAvoidance.h
vendored
Normal file
159
modules/detour/thirdparty/DetourCrowd/Include/DetourObstacleAvoidance.h
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOUROBSTACLEAVOIDANCE_H
|
||||||
|
#define DETOUROBSTACLEAVOIDANCE_H
|
||||||
|
|
||||||
|
struct dtObstacleCircle
|
||||||
|
{
|
||||||
|
float p[3]; ///< Position of the obstacle
|
||||||
|
float vel[3]; ///< Velocity of the obstacle
|
||||||
|
float dvel[3]; ///< Velocity of the obstacle
|
||||||
|
float rad; ///< Radius of the obstacle
|
||||||
|
float dp[3], np[3]; ///< Use for side selection during sampling.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dtObstacleSegment
|
||||||
|
{
|
||||||
|
float p[3], q[3]; ///< End points of the obstacle segment
|
||||||
|
bool touch;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class dtObstacleAvoidanceDebugData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dtObstacleAvoidanceDebugData();
|
||||||
|
~dtObstacleAvoidanceDebugData();
|
||||||
|
|
||||||
|
bool init(const int maxSamples);
|
||||||
|
void reset();
|
||||||
|
void addSample(const float* vel, const float ssize, const float pen,
|
||||||
|
const float vpen, const float vcpen, const float spen, const float tpen);
|
||||||
|
|
||||||
|
void normalizeSamples();
|
||||||
|
|
||||||
|
inline int getSampleCount() const { return m_nsamples; }
|
||||||
|
inline const float* getSampleVelocity(const int i) const { return &m_vel[i*3]; }
|
||||||
|
inline float getSampleSize(const int i) const { return m_ssize[i]; }
|
||||||
|
inline float getSamplePenalty(const int i) const { return m_pen[i]; }
|
||||||
|
inline float getSampleDesiredVelocityPenalty(const int i) const { return m_vpen[i]; }
|
||||||
|
inline float getSampleCurrentVelocityPenalty(const int i) const { return m_vcpen[i]; }
|
||||||
|
inline float getSamplePreferredSidePenalty(const int i) const { return m_spen[i]; }
|
||||||
|
inline float getSampleCollisionTimePenalty(const int i) const { return m_tpen[i]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Explicitly disabled copy constructor and copy assignment operator.
|
||||||
|
dtObstacleAvoidanceDebugData(const dtObstacleAvoidanceDebugData&);
|
||||||
|
dtObstacleAvoidanceDebugData& operator=(const dtObstacleAvoidanceDebugData&);
|
||||||
|
|
||||||
|
int m_nsamples;
|
||||||
|
int m_maxSamples;
|
||||||
|
float* m_vel;
|
||||||
|
float* m_ssize;
|
||||||
|
float* m_pen;
|
||||||
|
float* m_vpen;
|
||||||
|
float* m_vcpen;
|
||||||
|
float* m_spen;
|
||||||
|
float* m_tpen;
|
||||||
|
};
|
||||||
|
|
||||||
|
dtObstacleAvoidanceDebugData* dtAllocObstacleAvoidanceDebugData();
|
||||||
|
void dtFreeObstacleAvoidanceDebugData(dtObstacleAvoidanceDebugData* ptr);
|
||||||
|
|
||||||
|
|
||||||
|
static const int DT_MAX_PATTERN_DIVS = 32; ///< Max numver of adaptive divs.
|
||||||
|
static const int DT_MAX_PATTERN_RINGS = 4; ///< Max number of adaptive rings.
|
||||||
|
|
||||||
|
struct dtObstacleAvoidanceParams
|
||||||
|
{
|
||||||
|
float velBias;
|
||||||
|
float weightDesVel;
|
||||||
|
float weightCurVel;
|
||||||
|
float weightSide;
|
||||||
|
float weightToi;
|
||||||
|
float horizTime;
|
||||||
|
unsigned char gridSize; ///< grid
|
||||||
|
unsigned char adaptiveDivs; ///< adaptive
|
||||||
|
unsigned char adaptiveRings; ///< adaptive
|
||||||
|
unsigned char adaptiveDepth; ///< adaptive
|
||||||
|
};
|
||||||
|
|
||||||
|
class dtObstacleAvoidanceQuery
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dtObstacleAvoidanceQuery();
|
||||||
|
~dtObstacleAvoidanceQuery();
|
||||||
|
|
||||||
|
bool init(const int maxCircles, const int maxSegments);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void addCircle(const float* pos, const float rad,
|
||||||
|
const float* vel, const float* dvel);
|
||||||
|
|
||||||
|
void addSegment(const float* p, const float* q);
|
||||||
|
|
||||||
|
int sampleVelocityGrid(const float* pos, const float rad, const float vmax,
|
||||||
|
const float* vel, const float* dvel, float* nvel,
|
||||||
|
const dtObstacleAvoidanceParams* params,
|
||||||
|
dtObstacleAvoidanceDebugData* debug = 0);
|
||||||
|
|
||||||
|
int sampleVelocityAdaptive(const float* pos, const float rad, const float vmax,
|
||||||
|
const float* vel, const float* dvel, float* nvel,
|
||||||
|
const dtObstacleAvoidanceParams* params,
|
||||||
|
dtObstacleAvoidanceDebugData* debug = 0);
|
||||||
|
|
||||||
|
inline int getObstacleCircleCount() const { return m_ncircles; }
|
||||||
|
const dtObstacleCircle* getObstacleCircle(const int i) { return &m_circles[i]; }
|
||||||
|
|
||||||
|
inline int getObstacleSegmentCount() const { return m_nsegments; }
|
||||||
|
const dtObstacleSegment* getObstacleSegment(const int i) { return &m_segments[i]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Explicitly disabled copy constructor and copy assignment operator.
|
||||||
|
dtObstacleAvoidanceQuery(const dtObstacleAvoidanceQuery&);
|
||||||
|
dtObstacleAvoidanceQuery& operator=(const dtObstacleAvoidanceQuery&);
|
||||||
|
|
||||||
|
void prepare(const float* pos, const float* dvel);
|
||||||
|
|
||||||
|
float processSample(const float* vcand, const float cs,
|
||||||
|
const float* pos, const float rad,
|
||||||
|
const float* vel, const float* dvel,
|
||||||
|
const float minPenalty,
|
||||||
|
dtObstacleAvoidanceDebugData* debug);
|
||||||
|
|
||||||
|
dtObstacleAvoidanceParams m_params;
|
||||||
|
float m_invHorizTime;
|
||||||
|
float m_vmax;
|
||||||
|
float m_invVmax;
|
||||||
|
|
||||||
|
int m_maxCircles;
|
||||||
|
dtObstacleCircle* m_circles;
|
||||||
|
int m_ncircles;
|
||||||
|
|
||||||
|
int m_maxSegments;
|
||||||
|
dtObstacleSegment* m_segments;
|
||||||
|
int m_nsegments;
|
||||||
|
};
|
||||||
|
|
||||||
|
dtObstacleAvoidanceQuery* dtAllocObstacleAvoidanceQuery();
|
||||||
|
void dtFreeObstacleAvoidanceQuery(dtObstacleAvoidanceQuery* ptr);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DETOUROBSTACLEAVOIDANCE_H
|
||||||
151
modules/detour/thirdparty/DetourCrowd/Include/DetourPathCorridor.h
vendored
Normal file
151
modules/detour/thirdparty/DetourCrowd/Include/DetourPathCorridor.h
vendored
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOUTPATHCORRIDOR_H
|
||||||
|
#define DETOUTPATHCORRIDOR_H
|
||||||
|
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
|
||||||
|
/// Represents a dynamic polygon corridor used to plan agent movement.
|
||||||
|
/// @ingroup crowd, detour
|
||||||
|
class dtPathCorridor
|
||||||
|
{
|
||||||
|
float m_pos[3];
|
||||||
|
float m_target[3];
|
||||||
|
|
||||||
|
dtPolyRef* m_path;
|
||||||
|
int m_npath;
|
||||||
|
int m_maxPath;
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtPathCorridor();
|
||||||
|
~dtPathCorridor();
|
||||||
|
|
||||||
|
/// Allocates the corridor's path buffer.
|
||||||
|
/// @param[in] maxPath The maximum path size the corridor can handle.
|
||||||
|
/// @return True if the initialization succeeded.
|
||||||
|
bool init(const int maxPath);
|
||||||
|
|
||||||
|
/// Resets the path corridor to the specified position.
|
||||||
|
/// @param[in] ref The polygon reference containing the position.
|
||||||
|
/// @param[in] pos The new position in the corridor. [(x, y, z)]
|
||||||
|
void reset(dtPolyRef ref, const float* pos);
|
||||||
|
|
||||||
|
/// Finds the corners in the corridor from the position toward the target. (The straightened path.)
|
||||||
|
/// @param[out] cornerVerts The corner vertices. [(x, y, z) * cornerCount] [Size: <= maxCorners]
|
||||||
|
/// @param[out] cornerFlags The flag for each corner. [(flag) * cornerCount] [Size: <= maxCorners]
|
||||||
|
/// @param[out] cornerPolys The polygon reference for each corner. [(polyRef) * cornerCount]
|
||||||
|
/// [Size: <= @p maxCorners]
|
||||||
|
/// @param[in] maxCorners The maximum number of corners the buffers can hold.
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
/// @return The number of corners returned in the corner buffers. [0 <= value <= @p maxCorners]
|
||||||
|
int findCorners(float* cornerVerts, unsigned char* cornerFlags,
|
||||||
|
dtPolyRef* cornerPolys, const int maxCorners,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Attempts to optimize the path if the specified point is visible from the current position.
|
||||||
|
/// @param[in] next The point to search toward. [(x, y, z])
|
||||||
|
/// @param[in] pathOptimizationRange The maximum range to search. [Limit: > 0]
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
void optimizePathVisibility(const float* next, const float pathOptimizationRange,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Attempts to optimize the path using a local area search. (Partial replanning.)
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
bool optimizePathTopology(dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
bool moveOverOffmeshConnection(dtPolyRef offMeshConRef, dtPolyRef* refs,
|
||||||
|
float* startPos, float* endPos,
|
||||||
|
dtNavMeshQuery* navquery);
|
||||||
|
|
||||||
|
bool fixPathStart(dtPolyRef safeRef, const float* safePos);
|
||||||
|
|
||||||
|
bool trimInvalidPath(dtPolyRef safeRef, const float* safePos,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Checks the current corridor path to see if its polygon references remain valid.
|
||||||
|
/// @param[in] maxLookAhead The number of polygons from the beginning of the corridor to search.
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
bool isValid(const int maxLookAhead, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Moves the position from the current location to the desired location, adjusting the corridor
|
||||||
|
/// as needed to reflect the change.
|
||||||
|
/// @param[in] npos The desired new position. [(x, y, z)]
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
/// @return Returns true if move succeeded.
|
||||||
|
bool movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Moves the target from the curent location to the desired location, adjusting the corridor
|
||||||
|
/// as needed to reflect the change.
|
||||||
|
/// @param[in] npos The desired new target position. [(x, y, z)]
|
||||||
|
/// @param[in] navquery The query object used to build the corridor.
|
||||||
|
/// @param[in] filter The filter to apply to the operation.
|
||||||
|
/// @return Returns true if move succeeded.
|
||||||
|
bool moveTargetPosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
/// Loads a new path and target into the corridor.
|
||||||
|
/// @param[in] target The target location within the last polygon of the path. [(x, y, z)]
|
||||||
|
/// @param[in] path The path corridor. [(polyRef) * @p npolys]
|
||||||
|
/// @param[in] npath The number of polygons in the path.
|
||||||
|
void setCorridor(const float* target, const dtPolyRef* polys, const int npath);
|
||||||
|
|
||||||
|
/// Gets the current position within the corridor. (In the first polygon.)
|
||||||
|
/// @return The current position within the corridor.
|
||||||
|
inline const float* getPos() const { return m_pos; }
|
||||||
|
|
||||||
|
/// Gets the current target within the corridor. (In the last polygon.)
|
||||||
|
/// @return The current target within the corridor.
|
||||||
|
inline const float* getTarget() const { return m_target; }
|
||||||
|
|
||||||
|
/// The polygon reference id of the first polygon in the corridor, the polygon containing the position.
|
||||||
|
/// @return The polygon reference id of the first polygon in the corridor. (Or zero if there is no path.)
|
||||||
|
inline dtPolyRef getFirstPoly() const { return m_npath ? m_path[0] : 0; }
|
||||||
|
|
||||||
|
/// The polygon reference id of the last polygon in the corridor, the polygon containing the target.
|
||||||
|
/// @return The polygon reference id of the last polygon in the corridor. (Or zero if there is no path.)
|
||||||
|
inline dtPolyRef getLastPoly() const { return m_npath ? m_path[m_npath-1] : 0; }
|
||||||
|
|
||||||
|
/// The corridor's path.
|
||||||
|
/// @return The corridor's path. [(polyRef) * #getPathCount()]
|
||||||
|
inline const dtPolyRef* getPath() const { return m_path; }
|
||||||
|
|
||||||
|
/// The number of polygons in the current corridor path.
|
||||||
|
/// @return The number of polygons in the current corridor path.
|
||||||
|
inline int getPathCount() const { return m_npath; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Explicitly disabled copy constructor and copy assignment operator.
|
||||||
|
dtPathCorridor(const dtPathCorridor&);
|
||||||
|
dtPathCorridor& operator=(const dtPathCorridor&);
|
||||||
|
};
|
||||||
|
|
||||||
|
int dtMergeCorridorStartMoved(dtPolyRef* path, const int npath, const int maxPath,
|
||||||
|
const dtPolyRef* visited, const int nvisited);
|
||||||
|
|
||||||
|
int dtMergeCorridorEndMoved(dtPolyRef* path, const int npath, const int maxPath,
|
||||||
|
const dtPolyRef* visited, const int nvisited);
|
||||||
|
|
||||||
|
int dtMergeCorridorStartShortcut(dtPolyRef* path, const int npath, const int maxPath,
|
||||||
|
const dtPolyRef* visited, const int nvisited);
|
||||||
|
|
||||||
|
#endif // DETOUTPATHCORRIDOR_H
|
||||||
79
modules/detour/thirdparty/DetourCrowd/Include/DetourPathQueue.h
vendored
Normal file
79
modules/detour/thirdparty/DetourCrowd/Include/DetourPathQueue.h
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURPATHQUEUE_H
|
||||||
|
#define DETOURPATHQUEUE_H
|
||||||
|
|
||||||
|
#include "DetourNavMesh.h"
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
|
||||||
|
static const unsigned int DT_PATHQ_INVALID = 0;
|
||||||
|
|
||||||
|
typedef unsigned int dtPathQueueRef;
|
||||||
|
|
||||||
|
class dtPathQueue
|
||||||
|
{
|
||||||
|
struct PathQuery
|
||||||
|
{
|
||||||
|
dtPathQueueRef ref;
|
||||||
|
/// Path find start and end location.
|
||||||
|
float startPos[3], endPos[3];
|
||||||
|
dtPolyRef startRef, endRef;
|
||||||
|
/// Result.
|
||||||
|
dtPolyRef* path;
|
||||||
|
int npath;
|
||||||
|
/// State.
|
||||||
|
dtStatus status;
|
||||||
|
int keepAlive;
|
||||||
|
const dtQueryFilter* filter; ///< TODO: This is potentially dangerous!
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int MAX_QUEUE = 8;
|
||||||
|
PathQuery m_queue[MAX_QUEUE];
|
||||||
|
dtPathQueueRef m_nextHandle;
|
||||||
|
int m_maxPathSize;
|
||||||
|
int m_queueHead;
|
||||||
|
dtNavMeshQuery* m_navquery;
|
||||||
|
|
||||||
|
void purge();
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtPathQueue();
|
||||||
|
~dtPathQueue();
|
||||||
|
|
||||||
|
bool init(const int maxPathSize, const int maxSearchNodeCount, dtNavMesh* nav);
|
||||||
|
|
||||||
|
void update(const int maxIters);
|
||||||
|
|
||||||
|
dtPathQueueRef request(dtPolyRef startRef, dtPolyRef endRef,
|
||||||
|
const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter);
|
||||||
|
|
||||||
|
dtStatus getRequestStatus(dtPathQueueRef ref) const;
|
||||||
|
|
||||||
|
dtStatus getPathResult(dtPathQueueRef ref, dtPolyRef* path, int* pathSize, const int maxPath);
|
||||||
|
|
||||||
|
inline const dtNavMeshQuery* getNavQuery() const { return m_navquery; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Explicitly disabled copy constructor and copy assignment operator.
|
||||||
|
dtPathQueue(const dtPathQueue&);
|
||||||
|
dtPathQueue& operator=(const dtPathQueue&);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DETOURPATHQUEUE_H
|
||||||
74
modules/detour/thirdparty/DetourCrowd/Include/DetourProximityGrid.h
vendored
Normal file
74
modules/detour/thirdparty/DetourCrowd/Include/DetourProximityGrid.h
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURPROXIMITYGRID_H
|
||||||
|
#define DETOURPROXIMITYGRID_H
|
||||||
|
|
||||||
|
class dtProximityGrid
|
||||||
|
{
|
||||||
|
float m_cellSize;
|
||||||
|
float m_invCellSize;
|
||||||
|
|
||||||
|
struct Item
|
||||||
|
{
|
||||||
|
unsigned short id;
|
||||||
|
short x,y;
|
||||||
|
unsigned short next;
|
||||||
|
};
|
||||||
|
Item* m_pool;
|
||||||
|
int m_poolHead;
|
||||||
|
int m_poolSize;
|
||||||
|
|
||||||
|
unsigned short* m_buckets;
|
||||||
|
int m_bucketsSize;
|
||||||
|
|
||||||
|
int m_bounds[4];
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtProximityGrid();
|
||||||
|
~dtProximityGrid();
|
||||||
|
|
||||||
|
bool init(const int poolSize, const float cellSize);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void addItem(const unsigned short id,
|
||||||
|
const float minx, const float miny,
|
||||||
|
const float maxx, const float maxy);
|
||||||
|
|
||||||
|
int queryItems(const float minx, const float miny,
|
||||||
|
const float maxx, const float maxy,
|
||||||
|
unsigned short* ids, const int maxIds) const;
|
||||||
|
|
||||||
|
int getItemCountAt(const int x, const int y) const;
|
||||||
|
|
||||||
|
inline const int* getBounds() const { return m_bounds; }
|
||||||
|
inline float getCellSize() const { return m_cellSize; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Explicitly disabled copy constructor and copy assignment operator.
|
||||||
|
dtProximityGrid(const dtProximityGrid&);
|
||||||
|
dtProximityGrid& operator=(const dtProximityGrid&);
|
||||||
|
};
|
||||||
|
|
||||||
|
dtProximityGrid* dtAllocProximityGrid();
|
||||||
|
void dtFreeProximityGrid(dtProximityGrid* ptr);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DETOURPROXIMITYGRID_H
|
||||||
|
|
||||||
1454
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.cpp
vendored
Normal file
1454
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.x11.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.x11.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.x11.opt.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.x11.opt.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.x11.opt.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.x11.opt.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.x11.opt.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.x11.opt.tools.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.x11.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourCrowd.x11.tools.64.o
vendored
Normal file
Binary file not shown.
137
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.cpp
vendored
Normal file
137
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.cpp
vendored
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <float.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "DetourLocalBoundary.h"
|
||||||
|
#include "DetourNavMeshQuery.h"
|
||||||
|
#include "DetourCommon.h"
|
||||||
|
#include "DetourAssert.h"
|
||||||
|
|
||||||
|
|
||||||
|
dtLocalBoundary::dtLocalBoundary() :
|
||||||
|
m_nsegs(0),
|
||||||
|
m_npolys(0)
|
||||||
|
{
|
||||||
|
dtVset(m_center, FLT_MAX,FLT_MAX,FLT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtLocalBoundary::~dtLocalBoundary()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtLocalBoundary::reset()
|
||||||
|
{
|
||||||
|
dtVset(m_center, FLT_MAX,FLT_MAX,FLT_MAX);
|
||||||
|
m_npolys = 0;
|
||||||
|
m_nsegs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtLocalBoundary::addSegment(const float dist, const float* s)
|
||||||
|
{
|
||||||
|
// Insert neighbour based on the distance.
|
||||||
|
Segment* seg = 0;
|
||||||
|
if (!m_nsegs)
|
||||||
|
{
|
||||||
|
// First, trivial accept.
|
||||||
|
seg = &m_segs[0];
|
||||||
|
}
|
||||||
|
else if (dist >= m_segs[m_nsegs-1].d)
|
||||||
|
{
|
||||||
|
// Further than the last segment, skip.
|
||||||
|
if (m_nsegs >= MAX_LOCAL_SEGS)
|
||||||
|
return;
|
||||||
|
// Last, trivial accept.
|
||||||
|
seg = &m_segs[m_nsegs];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Insert inbetween.
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < m_nsegs; ++i)
|
||||||
|
if (dist <= m_segs[i].d)
|
||||||
|
break;
|
||||||
|
const int tgt = i+1;
|
||||||
|
const int n = dtMin(m_nsegs-i, MAX_LOCAL_SEGS-tgt);
|
||||||
|
dtAssert(tgt+n <= MAX_LOCAL_SEGS);
|
||||||
|
if (n > 0)
|
||||||
|
memmove(&m_segs[tgt], &m_segs[i], sizeof(Segment)*n);
|
||||||
|
seg = &m_segs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
seg->d = dist;
|
||||||
|
memcpy(seg->s, s, sizeof(float)*6);
|
||||||
|
|
||||||
|
if (m_nsegs < MAX_LOCAL_SEGS)
|
||||||
|
m_nsegs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtLocalBoundary::update(dtPolyRef ref, const float* pos, const float collisionQueryRange,
|
||||||
|
dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
|
{
|
||||||
|
static const int MAX_SEGS_PER_POLY = DT_VERTS_PER_POLYGON*3;
|
||||||
|
|
||||||
|
if (!ref)
|
||||||
|
{
|
||||||
|
dtVset(m_center, FLT_MAX,FLT_MAX,FLT_MAX);
|
||||||
|
m_nsegs = 0;
|
||||||
|
m_npolys = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtVcopy(m_center, pos);
|
||||||
|
|
||||||
|
// First query non-overlapping polygons.
|
||||||
|
navquery->findLocalNeighbourhood(ref, pos, collisionQueryRange,
|
||||||
|
filter, m_polys, 0, &m_npolys, MAX_LOCAL_POLYS);
|
||||||
|
|
||||||
|
// Secondly, store all polygon edges.
|
||||||
|
m_nsegs = 0;
|
||||||
|
float segs[MAX_SEGS_PER_POLY*6];
|
||||||
|
int nsegs = 0;
|
||||||
|
for (int j = 0; j < m_npolys; ++j)
|
||||||
|
{
|
||||||
|
navquery->getPolyWallSegments(m_polys[j], filter, segs, 0, &nsegs, MAX_SEGS_PER_POLY);
|
||||||
|
for (int k = 0; k < nsegs; ++k)
|
||||||
|
{
|
||||||
|
const float* s = &segs[k*6];
|
||||||
|
// Skip too distant segments.
|
||||||
|
float tseg;
|
||||||
|
const float distSqr = dtDistancePtSegSqr2D(pos, s, s+3, tseg);
|
||||||
|
if (distSqr > dtSqr(collisionQueryRange))
|
||||||
|
continue;
|
||||||
|
addSegment(distSqr, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtLocalBoundary::isValid(dtNavMeshQuery* navquery, const dtQueryFilter* filter)
|
||||||
|
{
|
||||||
|
if (!m_npolys)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check that all polygons still pass query filter.
|
||||||
|
for (int i = 0; i < m_npolys; ++i)
|
||||||
|
{
|
||||||
|
if (!navquery->isValidPolyRef(m_polys[i], filter))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.x11.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.x11.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.x11.opt.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.x11.opt.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.x11.opt.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.x11.opt.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.x11.opt.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.x11.opt.tools.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.x11.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourLocalBoundary.x11.tools.64.o
vendored
Normal file
Binary file not shown.
619
modules/detour/thirdparty/DetourCrowd/Source/DetourObstacleAvoidance.cpp
vendored
Normal file
619
modules/detour/thirdparty/DetourCrowd/Source/DetourObstacleAvoidance.cpp
vendored
Normal file
@@ -0,0 +1,619 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "DetourObstacleAvoidance.h"
|
||||||
|
#include "DetourCommon.h"
|
||||||
|
#include "DetourMath.h"
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
#include "DetourAssert.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
static const float DT_PI = 3.14159265f;
|
||||||
|
|
||||||
|
static int sweepCircleCircle(const float* c0, const float r0, const float* v,
|
||||||
|
const float* c1, const float r1,
|
||||||
|
float& tmin, float& tmax)
|
||||||
|
{
|
||||||
|
static const float EPS = 0.0001f;
|
||||||
|
float s[3];
|
||||||
|
dtVsub(s,c1,c0);
|
||||||
|
float r = r0+r1;
|
||||||
|
float c = dtVdot2D(s,s) - r*r;
|
||||||
|
float a = dtVdot2D(v,v);
|
||||||
|
if (a < EPS) return 0; // not moving
|
||||||
|
|
||||||
|
// Overlap, calc time to exit.
|
||||||
|
float b = dtVdot2D(v,s);
|
||||||
|
float d = b*b - a*c;
|
||||||
|
if (d < 0.0f) return 0; // no intersection.
|
||||||
|
a = 1.0f / a;
|
||||||
|
const float rd = dtMathSqrtf(d);
|
||||||
|
tmin = (b - rd) * a;
|
||||||
|
tmax = (b + rd) * a;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int isectRaySeg(const float* ap, const float* u,
|
||||||
|
const float* bp, const float* bq,
|
||||||
|
float& t)
|
||||||
|
{
|
||||||
|
float v[3], w[3];
|
||||||
|
dtVsub(v,bq,bp);
|
||||||
|
dtVsub(w,ap,bp);
|
||||||
|
float d = dtVperp2D(u,v);
|
||||||
|
if (dtMathFabsf(d) < 1e-6f) return 0;
|
||||||
|
d = 1.0f/d;
|
||||||
|
t = dtVperp2D(v,w) * d;
|
||||||
|
if (t < 0 || t > 1) return 0;
|
||||||
|
float s = dtVperp2D(u,w) * d;
|
||||||
|
if (s < 0 || s > 1) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
dtObstacleAvoidanceDebugData* dtAllocObstacleAvoidanceDebugData()
|
||||||
|
{
|
||||||
|
void* mem = dtAlloc(sizeof(dtObstacleAvoidanceDebugData), DT_ALLOC_PERM);
|
||||||
|
if (!mem) return 0;
|
||||||
|
return new(mem) dtObstacleAvoidanceDebugData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtFreeObstacleAvoidanceDebugData(dtObstacleAvoidanceDebugData* ptr)
|
||||||
|
{
|
||||||
|
if (!ptr) return;
|
||||||
|
ptr->~dtObstacleAvoidanceDebugData();
|
||||||
|
dtFree(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dtObstacleAvoidanceDebugData::dtObstacleAvoidanceDebugData() :
|
||||||
|
m_nsamples(0),
|
||||||
|
m_maxSamples(0),
|
||||||
|
m_vel(0),
|
||||||
|
m_ssize(0),
|
||||||
|
m_pen(0),
|
||||||
|
m_vpen(0),
|
||||||
|
m_vcpen(0),
|
||||||
|
m_spen(0),
|
||||||
|
m_tpen(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
dtObstacleAvoidanceDebugData::~dtObstacleAvoidanceDebugData()
|
||||||
|
{
|
||||||
|
dtFree(m_vel);
|
||||||
|
dtFree(m_ssize);
|
||||||
|
dtFree(m_pen);
|
||||||
|
dtFree(m_vpen);
|
||||||
|
dtFree(m_vcpen);
|
||||||
|
dtFree(m_spen);
|
||||||
|
dtFree(m_tpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtObstacleAvoidanceDebugData::init(const int maxSamples)
|
||||||
|
{
|
||||||
|
dtAssert(maxSamples);
|
||||||
|
m_maxSamples = maxSamples;
|
||||||
|
|
||||||
|
m_vel = (float*)dtAlloc(sizeof(float)*3*m_maxSamples, DT_ALLOC_PERM);
|
||||||
|
if (!m_vel)
|
||||||
|
return false;
|
||||||
|
m_pen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
||||||
|
if (!m_pen)
|
||||||
|
return false;
|
||||||
|
m_ssize = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
||||||
|
if (!m_ssize)
|
||||||
|
return false;
|
||||||
|
m_vpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
||||||
|
if (!m_vpen)
|
||||||
|
return false;
|
||||||
|
m_vcpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
||||||
|
if (!m_vcpen)
|
||||||
|
return false;
|
||||||
|
m_spen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
||||||
|
if (!m_spen)
|
||||||
|
return false;
|
||||||
|
m_tpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
||||||
|
if (!m_tpen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtObstacleAvoidanceDebugData::reset()
|
||||||
|
{
|
||||||
|
m_nsamples = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtObstacleAvoidanceDebugData::addSample(const float* vel, const float ssize, const float pen,
|
||||||
|
const float vpen, const float vcpen, const float spen, const float tpen)
|
||||||
|
{
|
||||||
|
if (m_nsamples >= m_maxSamples)
|
||||||
|
return;
|
||||||
|
dtAssert(m_vel);
|
||||||
|
dtAssert(m_ssize);
|
||||||
|
dtAssert(m_pen);
|
||||||
|
dtAssert(m_vpen);
|
||||||
|
dtAssert(m_vcpen);
|
||||||
|
dtAssert(m_spen);
|
||||||
|
dtAssert(m_tpen);
|
||||||
|
dtVcopy(&m_vel[m_nsamples*3], vel);
|
||||||
|
m_ssize[m_nsamples] = ssize;
|
||||||
|
m_pen[m_nsamples] = pen;
|
||||||
|
m_vpen[m_nsamples] = vpen;
|
||||||
|
m_vcpen[m_nsamples] = vcpen;
|
||||||
|
m_spen[m_nsamples] = spen;
|
||||||
|
m_tpen[m_nsamples] = tpen;
|
||||||
|
m_nsamples++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void normalizeArray(float* arr, const int n)
|
||||||
|
{
|
||||||
|
// Normalize penaly range.
|
||||||
|
float minPen = FLT_MAX;
|
||||||
|
float maxPen = -FLT_MAX;
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
minPen = dtMin(minPen, arr[i]);
|
||||||
|
maxPen = dtMax(maxPen, arr[i]);
|
||||||
|
}
|
||||||
|
const float penRange = maxPen-minPen;
|
||||||
|
const float s = penRange > 0.001f ? (1.0f / penRange) : 1;
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
arr[i] = dtClamp((arr[i]-minPen)*s, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtObstacleAvoidanceDebugData::normalizeSamples()
|
||||||
|
{
|
||||||
|
normalizeArray(m_pen, m_nsamples);
|
||||||
|
normalizeArray(m_vpen, m_nsamples);
|
||||||
|
normalizeArray(m_vcpen, m_nsamples);
|
||||||
|
normalizeArray(m_spen, m_nsamples);
|
||||||
|
normalizeArray(m_tpen, m_nsamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dtObstacleAvoidanceQuery* dtAllocObstacleAvoidanceQuery()
|
||||||
|
{
|
||||||
|
void* mem = dtAlloc(sizeof(dtObstacleAvoidanceQuery), DT_ALLOC_PERM);
|
||||||
|
if (!mem) return 0;
|
||||||
|
return new(mem) dtObstacleAvoidanceQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtFreeObstacleAvoidanceQuery(dtObstacleAvoidanceQuery* ptr)
|
||||||
|
{
|
||||||
|
if (!ptr) return;
|
||||||
|
ptr->~dtObstacleAvoidanceQuery();
|
||||||
|
dtFree(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dtObstacleAvoidanceQuery::dtObstacleAvoidanceQuery() :
|
||||||
|
m_invHorizTime(0),
|
||||||
|
m_vmax(0),
|
||||||
|
m_invVmax(0),
|
||||||
|
m_maxCircles(0),
|
||||||
|
m_circles(0),
|
||||||
|
m_ncircles(0),
|
||||||
|
m_maxSegments(0),
|
||||||
|
m_segments(0),
|
||||||
|
m_nsegments(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
dtObstacleAvoidanceQuery::~dtObstacleAvoidanceQuery()
|
||||||
|
{
|
||||||
|
dtFree(m_circles);
|
||||||
|
dtFree(m_segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dtObstacleAvoidanceQuery::init(const int maxCircles, const int maxSegments)
|
||||||
|
{
|
||||||
|
m_maxCircles = maxCircles;
|
||||||
|
m_ncircles = 0;
|
||||||
|
m_circles = (dtObstacleCircle*)dtAlloc(sizeof(dtObstacleCircle)*m_maxCircles, DT_ALLOC_PERM);
|
||||||
|
if (!m_circles)
|
||||||
|
return false;
|
||||||
|
memset(m_circles, 0, sizeof(dtObstacleCircle)*m_maxCircles);
|
||||||
|
|
||||||
|
m_maxSegments = maxSegments;
|
||||||
|
m_nsegments = 0;
|
||||||
|
m_segments = (dtObstacleSegment*)dtAlloc(sizeof(dtObstacleSegment)*m_maxSegments, DT_ALLOC_PERM);
|
||||||
|
if (!m_segments)
|
||||||
|
return false;
|
||||||
|
memset(m_segments, 0, sizeof(dtObstacleSegment)*m_maxSegments);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtObstacleAvoidanceQuery::reset()
|
||||||
|
{
|
||||||
|
m_ncircles = 0;
|
||||||
|
m_nsegments = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtObstacleAvoidanceQuery::addCircle(const float* pos, const float rad,
|
||||||
|
const float* vel, const float* dvel)
|
||||||
|
{
|
||||||
|
if (m_ncircles >= m_maxCircles)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dtObstacleCircle* cir = &m_circles[m_ncircles++];
|
||||||
|
dtVcopy(cir->p, pos);
|
||||||
|
cir->rad = rad;
|
||||||
|
dtVcopy(cir->vel, vel);
|
||||||
|
dtVcopy(cir->dvel, dvel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtObstacleAvoidanceQuery::addSegment(const float* p, const float* q)
|
||||||
|
{
|
||||||
|
if (m_nsegments >= m_maxSegments)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dtObstacleSegment* seg = &m_segments[m_nsegments++];
|
||||||
|
dtVcopy(seg->p, p);
|
||||||
|
dtVcopy(seg->q, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtObstacleAvoidanceQuery::prepare(const float* pos, const float* dvel)
|
||||||
|
{
|
||||||
|
// Prepare obstacles
|
||||||
|
for (int i = 0; i < m_ncircles; ++i)
|
||||||
|
{
|
||||||
|
dtObstacleCircle* cir = &m_circles[i];
|
||||||
|
|
||||||
|
// Side
|
||||||
|
const float* pa = pos;
|
||||||
|
const float* pb = cir->p;
|
||||||
|
|
||||||
|
const float orig[3] = {0,0,0};
|
||||||
|
float dv[3];
|
||||||
|
dtVsub(cir->dp,pb,pa);
|
||||||
|
dtVnormalize(cir->dp);
|
||||||
|
dtVsub(dv, cir->dvel, dvel);
|
||||||
|
|
||||||
|
const float a = dtTriArea2D(orig, cir->dp,dv);
|
||||||
|
if (a < 0.01f)
|
||||||
|
{
|
||||||
|
cir->np[0] = -cir->dp[2];
|
||||||
|
cir->np[2] = cir->dp[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cir->np[0] = cir->dp[2];
|
||||||
|
cir->np[2] = -cir->dp[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_nsegments; ++i)
|
||||||
|
{
|
||||||
|
dtObstacleSegment* seg = &m_segments[i];
|
||||||
|
|
||||||
|
// Precalc if the agent is really close to the segment.
|
||||||
|
const float r = 0.01f;
|
||||||
|
float t;
|
||||||
|
seg->touch = dtDistancePtSegSqr2D(pos, seg->p, seg->q, t) < dtSqr(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Calculate the collision penalty for a given velocity vector
|
||||||
|
*
|
||||||
|
* @param vcand sampled velocity
|
||||||
|
* @param dvel desired velocity
|
||||||
|
* @param minPenalty threshold penalty for early out
|
||||||
|
*/
|
||||||
|
float dtObstacleAvoidanceQuery::processSample(const float* vcand, const float cs,
|
||||||
|
const float* pos, const float rad,
|
||||||
|
const float* vel, const float* dvel,
|
||||||
|
const float minPenalty,
|
||||||
|
dtObstacleAvoidanceDebugData* debug)
|
||||||
|
{
|
||||||
|
// penalty for straying away from the desired and current velocities
|
||||||
|
const float vpen = m_params.weightDesVel * (dtVdist2D(vcand, dvel) * m_invVmax);
|
||||||
|
const float vcpen = m_params.weightCurVel * (dtVdist2D(vcand, vel) * m_invVmax);
|
||||||
|
|
||||||
|
// find the threshold hit time to bail out based on the early out penalty
|
||||||
|
// (see how the penalty is calculated below to understnad)
|
||||||
|
float minPen = minPenalty - vpen - vcpen;
|
||||||
|
float tThresold = (m_params.weightToi / minPen - 0.1f) * m_params.horizTime;
|
||||||
|
if (tThresold - m_params.horizTime > -FLT_EPSILON)
|
||||||
|
return minPenalty; // already too much
|
||||||
|
|
||||||
|
// Find min time of impact and exit amongst all obstacles.
|
||||||
|
float tmin = m_params.horizTime;
|
||||||
|
float side = 0;
|
||||||
|
int nside = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < m_ncircles; ++i)
|
||||||
|
{
|
||||||
|
const dtObstacleCircle* cir = &m_circles[i];
|
||||||
|
|
||||||
|
// RVO
|
||||||
|
float vab[3];
|
||||||
|
dtVscale(vab, vcand, 2);
|
||||||
|
dtVsub(vab, vab, vel);
|
||||||
|
dtVsub(vab, vab, cir->vel);
|
||||||
|
|
||||||
|
// Side
|
||||||
|
side += dtClamp(dtMin(dtVdot2D(cir->dp,vab)*0.5f+0.5f, dtVdot2D(cir->np,vab)*2), 0.0f, 1.0f);
|
||||||
|
nside++;
|
||||||
|
|
||||||
|
float htmin = 0, htmax = 0;
|
||||||
|
if (!sweepCircleCircle(pos,rad, vab, cir->p,cir->rad, htmin, htmax))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Handle overlapping obstacles.
|
||||||
|
if (htmin < 0.0f && htmax > 0.0f)
|
||||||
|
{
|
||||||
|
// Avoid more when overlapped.
|
||||||
|
htmin = -htmin * 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (htmin >= 0.0f)
|
||||||
|
{
|
||||||
|
// The closest obstacle is somewhere ahead of us, keep track of nearest obstacle.
|
||||||
|
if (htmin < tmin)
|
||||||
|
{
|
||||||
|
tmin = htmin;
|
||||||
|
if (tmin < tThresold)
|
||||||
|
return minPenalty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_nsegments; ++i)
|
||||||
|
{
|
||||||
|
const dtObstacleSegment* seg = &m_segments[i];
|
||||||
|
float htmin = 0;
|
||||||
|
|
||||||
|
if (seg->touch)
|
||||||
|
{
|
||||||
|
// Special case when the agent is very close to the segment.
|
||||||
|
float sdir[3], snorm[3];
|
||||||
|
dtVsub(sdir, seg->q, seg->p);
|
||||||
|
snorm[0] = -sdir[2];
|
||||||
|
snorm[2] = sdir[0];
|
||||||
|
// If the velocity is pointing towards the segment, no collision.
|
||||||
|
if (dtVdot2D(snorm, vcand) < 0.0f)
|
||||||
|
continue;
|
||||||
|
// Else immediate collision.
|
||||||
|
htmin = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!isectRaySeg(pos, vcand, seg->p, seg->q, htmin))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid less when facing walls.
|
||||||
|
htmin *= 2.0f;
|
||||||
|
|
||||||
|
// The closest obstacle is somewhere ahead of us, keep track of nearest obstacle.
|
||||||
|
if (htmin < tmin)
|
||||||
|
{
|
||||||
|
tmin = htmin;
|
||||||
|
if (tmin < tThresold)
|
||||||
|
return minPenalty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize side bias, to prevent it dominating too much.
|
||||||
|
if (nside)
|
||||||
|
side /= nside;
|
||||||
|
|
||||||
|
const float spen = m_params.weightSide * side;
|
||||||
|
const float tpen = m_params.weightToi * (1.0f/(0.1f+tmin*m_invHorizTime));
|
||||||
|
|
||||||
|
const float penalty = vpen + vcpen + spen + tpen;
|
||||||
|
|
||||||
|
// Store different penalties for debug viewing
|
||||||
|
if (debug)
|
||||||
|
debug->addSample(vcand, cs, penalty, vpen, vcpen, spen, tpen);
|
||||||
|
|
||||||
|
return penalty;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dtObstacleAvoidanceQuery::sampleVelocityGrid(const float* pos, const float rad, const float vmax,
|
||||||
|
const float* vel, const float* dvel, float* nvel,
|
||||||
|
const dtObstacleAvoidanceParams* params,
|
||||||
|
dtObstacleAvoidanceDebugData* debug)
|
||||||
|
{
|
||||||
|
prepare(pos, dvel);
|
||||||
|
|
||||||
|
memcpy(&m_params, params, sizeof(dtObstacleAvoidanceParams));
|
||||||
|
m_invHorizTime = 1.0f / m_params.horizTime;
|
||||||
|
m_vmax = vmax;
|
||||||
|
m_invVmax = vmax > 0 ? 1.0f / vmax : FLT_MAX;
|
||||||
|
|
||||||
|
dtVset(nvel, 0,0,0);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
debug->reset();
|
||||||
|
|
||||||
|
const float cvx = dvel[0] * m_params.velBias;
|
||||||
|
const float cvz = dvel[2] * m_params.velBias;
|
||||||
|
const float cs = vmax * 2 * (1 - m_params.velBias) / (float)(m_params.gridSize-1);
|
||||||
|
const float half = (m_params.gridSize-1)*cs*0.5f;
|
||||||
|
|
||||||
|
float minPenalty = FLT_MAX;
|
||||||
|
int ns = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < m_params.gridSize; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < m_params.gridSize; ++x)
|
||||||
|
{
|
||||||
|
float vcand[3];
|
||||||
|
vcand[0] = cvx + x*cs - half;
|
||||||
|
vcand[1] = 0;
|
||||||
|
vcand[2] = cvz + y*cs - half;
|
||||||
|
|
||||||
|
if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+cs/2)) continue;
|
||||||
|
|
||||||
|
const float penalty = processSample(vcand, cs, pos,rad,vel,dvel, minPenalty, debug);
|
||||||
|
ns++;
|
||||||
|
if (penalty < minPenalty)
|
||||||
|
{
|
||||||
|
minPenalty = penalty;
|
||||||
|
dtVcopy(nvel, vcand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// vector normalization that ignores the y-component.
|
||||||
|
inline void dtNormalize2D(float* v)
|
||||||
|
{
|
||||||
|
float d = dtMathSqrtf(v[0] * v[0] + v[2] * v[2]);
|
||||||
|
if (d==0)
|
||||||
|
return;
|
||||||
|
d = 1.0f / d;
|
||||||
|
v[0] *= d;
|
||||||
|
v[2] *= d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vector normalization that ignores the y-component.
|
||||||
|
inline void dtRorate2D(float* dest, const float* v, float ang)
|
||||||
|
{
|
||||||
|
float c = cosf(ang);
|
||||||
|
float s = sinf(ang);
|
||||||
|
dest[0] = v[0]*c - v[2]*s;
|
||||||
|
dest[2] = v[0]*s + v[2]*c;
|
||||||
|
dest[1] = v[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int dtObstacleAvoidanceQuery::sampleVelocityAdaptive(const float* pos, const float rad, const float vmax,
|
||||||
|
const float* vel, const float* dvel, float* nvel,
|
||||||
|
const dtObstacleAvoidanceParams* params,
|
||||||
|
dtObstacleAvoidanceDebugData* debug)
|
||||||
|
{
|
||||||
|
prepare(pos, dvel);
|
||||||
|
|
||||||
|
memcpy(&m_params, params, sizeof(dtObstacleAvoidanceParams));
|
||||||
|
m_invHorizTime = 1.0f / m_params.horizTime;
|
||||||
|
m_vmax = vmax;
|
||||||
|
m_invVmax = vmax > 0 ? 1.0f / vmax : FLT_MAX;
|
||||||
|
|
||||||
|
dtVset(nvel, 0,0,0);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
debug->reset();
|
||||||
|
|
||||||
|
// Build sampling pattern aligned to desired velocity.
|
||||||
|
float pat[(DT_MAX_PATTERN_DIVS*DT_MAX_PATTERN_RINGS+1)*2];
|
||||||
|
int npat = 0;
|
||||||
|
|
||||||
|
const int ndivs = (int)m_params.adaptiveDivs;
|
||||||
|
const int nrings= (int)m_params.adaptiveRings;
|
||||||
|
const int depth = (int)m_params.adaptiveDepth;
|
||||||
|
|
||||||
|
const int nd = dtClamp(ndivs, 1, DT_MAX_PATTERN_DIVS);
|
||||||
|
const int nr = dtClamp(nrings, 1, DT_MAX_PATTERN_RINGS);
|
||||||
|
const float da = (1.0f/nd) * DT_PI*2;
|
||||||
|
const float ca = cosf(da);
|
||||||
|
const float sa = sinf(da);
|
||||||
|
|
||||||
|
// desired direction
|
||||||
|
float ddir[6];
|
||||||
|
dtVcopy(ddir, dvel);
|
||||||
|
dtNormalize2D(ddir);
|
||||||
|
dtRorate2D (ddir+3, ddir, da*0.5f); // rotated by da/2
|
||||||
|
|
||||||
|
// Always add sample at zero
|
||||||
|
pat[npat*2+0] = 0;
|
||||||
|
pat[npat*2+1] = 0;
|
||||||
|
npat++;
|
||||||
|
|
||||||
|
for (int j = 0; j < nr; ++j)
|
||||||
|
{
|
||||||
|
const float r = (float)(nr-j)/(float)nr;
|
||||||
|
pat[npat*2+0] = ddir[(j%2)*3] * r;
|
||||||
|
pat[npat*2+1] = ddir[(j%2)*3+2] * r;
|
||||||
|
float* last1 = pat + npat*2;
|
||||||
|
float* last2 = last1;
|
||||||
|
npat++;
|
||||||
|
|
||||||
|
for (int i = 1; i < nd-1; i+=2)
|
||||||
|
{
|
||||||
|
// get next point on the "right" (rotate CW)
|
||||||
|
pat[npat*2+0] = last1[0]*ca + last1[1]*sa;
|
||||||
|
pat[npat*2+1] = -last1[0]*sa + last1[1]*ca;
|
||||||
|
// get next point on the "left" (rotate CCW)
|
||||||
|
pat[npat*2+2] = last2[0]*ca - last2[1]*sa;
|
||||||
|
pat[npat*2+3] = last2[0]*sa + last2[1]*ca;
|
||||||
|
|
||||||
|
last1 = pat + npat*2;
|
||||||
|
last2 = last1 + 2;
|
||||||
|
npat += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((nd&1) == 0)
|
||||||
|
{
|
||||||
|
pat[npat*2+2] = last2[0]*ca - last2[1]*sa;
|
||||||
|
pat[npat*2+3] = last2[0]*sa + last2[1]*ca;
|
||||||
|
npat++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Start sampling.
|
||||||
|
float cr = vmax * (1.0f - m_params.velBias);
|
||||||
|
float res[3];
|
||||||
|
dtVset(res, dvel[0] * m_params.velBias, 0, dvel[2] * m_params.velBias);
|
||||||
|
int ns = 0;
|
||||||
|
|
||||||
|
for (int k = 0; k < depth; ++k)
|
||||||
|
{
|
||||||
|
float minPenalty = FLT_MAX;
|
||||||
|
float bvel[3];
|
||||||
|
dtVset(bvel, 0,0,0);
|
||||||
|
|
||||||
|
for (int i = 0; i < npat; ++i)
|
||||||
|
{
|
||||||
|
float vcand[3];
|
||||||
|
vcand[0] = res[0] + pat[i*2+0]*cr;
|
||||||
|
vcand[1] = 0;
|
||||||
|
vcand[2] = res[2] + pat[i*2+1]*cr;
|
||||||
|
|
||||||
|
if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+0.001f)) continue;
|
||||||
|
|
||||||
|
const float penalty = processSample(vcand,cr/10, pos,rad,vel,dvel, minPenalty, debug);
|
||||||
|
ns++;
|
||||||
|
if (penalty < minPenalty)
|
||||||
|
{
|
||||||
|
minPenalty = penalty;
|
||||||
|
dtVcopy(bvel, vcand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dtVcopy(res, bvel);
|
||||||
|
|
||||||
|
cr *= 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtVcopy(nvel, res);
|
||||||
|
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourObstacleAvoidance.x11.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourObstacleAvoidance.x11.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourObstacleAvoidance.x11.opt.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourObstacleAvoidance.x11.opt.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourObstacleAvoidance.x11.opt.debug.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourObstacleAvoidance.x11.opt.debug.64.o
vendored
Normal file
Binary file not shown.
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourObstacleAvoidance.x11.opt.tools.64.o
vendored
Normal file
BIN
modules/detour/thirdparty/DetourCrowd/Source/DetourObstacleAvoidance.x11.opt.tools.64.o
vendored
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user