1447 lines
47 KiB
C++
1447 lines
47 KiB
C++
#include "precompile.h"
|
|
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
#include <f8/udplog.h>
|
|
|
|
#include <glm/gtx/intersect.hpp>
|
|
|
|
#include "DetourCommon.h"
|
|
|
|
#include "mapinstance.h"
|
|
#include "mapservice.h"
|
|
#include "gridservice.h"
|
|
#include "obstacle.h"
|
|
#include "loot.h"
|
|
#include "mapmgr.h"
|
|
#include "room.h"
|
|
#include "entityfactory.h"
|
|
#include "creature.h"
|
|
#include "glmhelper.h"
|
|
#include "debugcmd.h"
|
|
|
|
#include "mt/MetaMgr.h"
|
|
#include "mt/Param.h"
|
|
#include "mt/Map.h"
|
|
#include "mt/MapArea.h"
|
|
#include "mt/MapCollider.h"
|
|
|
|
#include "roommgr.h"
|
|
|
|
#include "navmesh.pb.h"
|
|
|
|
static const int NAV_ERROR_NEARESTPOLY = -2;
|
|
|
|
static const int NAV_ERROR = -1;
|
|
|
|
static const long RCN_NAVMESH_VERSION = 1;
|
|
static const int INVALID_NAVMESH_POLYREF = 0;
|
|
|
|
const int MAP_GRID_WIDTH = 64;
|
|
|
|
static const int NAVMESHSET_MAGIC = 'M'<<24 | 'S'<<16 | 'E'<<8 | 'T'; //'MSET';
|
|
static const int NAVMESHSET_VERSION = 1;
|
|
|
|
struct NavMeshSetHeader
|
|
{
|
|
int magic;
|
|
int version;
|
|
int numTiles;
|
|
dtNavMeshParams params;
|
|
};
|
|
|
|
struct NavMeshTileHeader
|
|
{
|
|
dtTileRef tileRef;
|
|
int dataSize;
|
|
};
|
|
|
|
static float frand()
|
|
{
|
|
return (float)rand()/(float)RAND_MAX;
|
|
}
|
|
|
|
static void TraverseMapColliderNode(std::shared_ptr<mc::ColliderNode> node,
|
|
std::function<void (std::shared_ptr<mc::ColliderNode>)> cb)
|
|
{
|
|
for (auto& pair : node->childs) {
|
|
cb(pair.second);
|
|
if (!pair.second->childs.empty()) {
|
|
TraverseMapColliderNode(pair.second, cb);
|
|
}
|
|
}
|
|
}
|
|
|
|
class ConnectableQueryFilter : public dtQueryFilter
|
|
{
|
|
public:
|
|
MapInstance* map_instance = nullptr;
|
|
|
|
virtual bool passFilter(const dtPolyRef ref,
|
|
const dtMeshTile* tile,
|
|
const dtPoly* poly) const override
|
|
{
|
|
return map_instance->IsConnectablePoly(ref);
|
|
}
|
|
|
|
};
|
|
|
|
void MapInstance::Init()
|
|
{
|
|
map_meta_ = mt::Map::GetById(map_id);
|
|
if (!map_meta_) {
|
|
A8_ABORT();
|
|
}
|
|
if (map_meta_->map_width() < 1) {
|
|
A8_ABORT();
|
|
}
|
|
if (map_meta_->map_height() < 1) {
|
|
A8_ABORT();
|
|
}
|
|
map_service_ = std::make_shared<MapService>();
|
|
grid_service_ = std::make_shared<GridService>();
|
|
if (map_meta_->is_moba()) {
|
|
grid_service_->Init(map_meta_->map_width(),
|
|
map_meta_->map_height(),
|
|
std::max(map_meta_->map_width(), map_meta_->map_height()) + 0);
|
|
} else {
|
|
grid_service_->Init(map_meta_->map_width(),
|
|
map_meta_->map_height(),
|
|
mt::Param::s().map_cell_width);
|
|
}
|
|
map_service_->Init(map_meta_->map_width() / MAP_GRID_WIDTH,
|
|
map_meta_->map_height() / MAP_GRID_WIDTH,
|
|
MAP_GRID_WIDTH);
|
|
{
|
|
navmesh_ = dtAllocNavMesh();
|
|
std::string navmesh_file = map_meta_->navmesh_file();
|
|
FILE *fp = fopen((mt::MetaMgr::Instance()->GetResDir() + navmesh_file).c_str(), "rb");
|
|
if(fp){
|
|
//fseek(fp, 0, SEEK_END);
|
|
//int file_size = ftell(fp);
|
|
int file_size = 1;
|
|
if(file_size){
|
|
NavMeshSetHeader header;
|
|
size_t readLen = fread(&header, sizeof(NavMeshSetHeader), 1, fp);
|
|
if (readLen != 1) {
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
if (header.magic != NAVMESHSET_MAGIC) {
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
if (header.version != NAVMESHSET_VERSION) {
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
dtStatus status = navmesh_->init(&header.params);
|
|
if (dtStatusFailed(status)) {
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
#ifdef MYDEBUG
|
|
a8::XPrintf("orig:%f,%f,%f tileWidth:%f tileHeight:%f maxTiles:%d maxPolys:%d\n",
|
|
{
|
|
header.params.orig[0],
|
|
header.params.orig[1],
|
|
header.params.orig[2],
|
|
header.params.tileWidth,
|
|
header.params.tileHeight,
|
|
header.params.maxTiles,
|
|
header.params.maxPolys,
|
|
});
|
|
#endif
|
|
{
|
|
// Read tiles.
|
|
for (int i = 0; i < header.numTiles; ++i) {
|
|
NavMeshTileHeader tileHeader;
|
|
readLen = fread(&tileHeader, sizeof(tileHeader), 1, fp);
|
|
if (readLen != 1) {
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
|
|
if (!tileHeader.tileRef || !tileHeader.dataSize) {
|
|
abort();
|
|
break;
|
|
}
|
|
|
|
unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize,
|
|
DT_ALLOC_PERM);
|
|
if (!data) {
|
|
abort();
|
|
break;
|
|
}
|
|
memset(data, 0, tileHeader.dataSize);
|
|
readLen = fread(data, tileHeader.dataSize, 1, fp);
|
|
if (readLen != 1) {
|
|
dtFree(data);
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
navmesh_->addTile(data,
|
|
tileHeader.dataSize,
|
|
DT_TILE_FREE_DATA,
|
|
tileHeader.tileRef,
|
|
0);
|
|
}
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
}
|
|
navmesh_query_ = std::make_shared<dtNavMeshQuery>();
|
|
navmesh_query_->init(navmesh_, 1024);
|
|
MarkMapAreaPolys();
|
|
MarkConnectablePolys();
|
|
LoadHouse();
|
|
f8::UdpLog::Instance()->Info
|
|
("map_id:%d connectable_polys:%d",
|
|
{
|
|
map_id,
|
|
connectable_polys_.size()
|
|
});
|
|
}
|
|
|
|
void MapInstance::UnInit()
|
|
{
|
|
navmesh_query_ = nullptr;
|
|
dtFreeNavMesh(navmesh_);
|
|
navmesh_ = nullptr;
|
|
|
|
map_service_->UnInit();
|
|
grid_service_->UnInit();
|
|
map_service_ = nullptr;
|
|
grid_service_ = nullptr;
|
|
}
|
|
|
|
void MapInstance::AttachRoom(Room* room, RoomInitInfo& init_info)
|
|
{
|
|
init_info.map_meta = map_meta_;
|
|
init_info.grid_service = grid_service_;
|
|
init_info.map_service = map_service_;
|
|
init_info.map_instance = shared_from_this();
|
|
}
|
|
|
|
int MapInstance::FindStraightPath(
|
|
const glm::vec3& start,
|
|
const glm::vec3& end,
|
|
std::vector<MovePathPoint>& paths)
|
|
{
|
|
float spos[3];
|
|
spos[0] = start.x;
|
|
spos[1] = start.y;
|
|
spos[2] = start.z;
|
|
|
|
float epos[3];
|
|
epos[0] = end.x;
|
|
epos[1] = end.y;
|
|
epos[2] = end.z;
|
|
|
|
dtQueryFilter filter;
|
|
filter.setIncludeFlags(GetMoveIncludeFlags());
|
|
filter.setExcludeFlags(GetMoveExcludeFlags());
|
|
|
|
const float extents[3] = {2.f, 4.f, 2.f};
|
|
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
dtPolyRef endRef = INVALID_NAVMESH_POLYREF;
|
|
|
|
float startNearestPt[3];
|
|
float endNearestPt[3];
|
|
navmesh_query_->findNearestPoly(spos, extents, &filter, &startRef, startNearestPt);
|
|
navmesh_query_->findNearestPoly(epos, extents, &filter, &endRef, endNearestPt);
|
|
|
|
if (!startRef || !endRef) {
|
|
return NAV_ERROR_NEARESTPOLY;
|
|
}
|
|
|
|
int npolys;
|
|
float straightPath[MAX_POLYS * 3];
|
|
unsigned char straightPathFlags[MAX_POLYS];
|
|
dtPolyRef straightPathPolys[MAX_POLYS];
|
|
int nstraightPath;
|
|
|
|
navmesh_query_->findPath
|
|
(startRef,
|
|
endRef,
|
|
startNearestPt,
|
|
endNearestPt,
|
|
&filter,
|
|
polys_,
|
|
&npolys,
|
|
MAX_POLYS);
|
|
nstraightPath = 0;
|
|
|
|
if (npolys) {
|
|
|
|
float epos1[3];
|
|
dtVcopy(epos1, endNearestPt);
|
|
|
|
if (polys_[npolys-1] != endRef) {
|
|
navmesh_query_->closestPointOnPoly(polys_[npolys-1], endNearestPt, epos1, 0);
|
|
}
|
|
|
|
navmesh_query_->findStraightPath(startNearestPt,
|
|
endNearestPt,
|
|
polys_,
|
|
npolys,
|
|
straightPath,
|
|
straightPathFlags,
|
|
straightPathPolys,
|
|
&nstraightPath,
|
|
MAX_POLYS);
|
|
glm::vec3 last_pos = start;
|
|
UnScale(last_pos);
|
|
int last_poly_pos = 0;
|
|
int path_index = 0;
|
|
for(int i = 0; i < nstraightPath * 3; ) {
|
|
glm::vec3 pos;
|
|
pos.x = straightPath[i++];
|
|
pos.y = straightPath[i++];
|
|
pos.z = straightPath[i++];
|
|
UnScale(pos);
|
|
if (!GlmHelper::IsEqual2D(pos, last_pos)) {
|
|
glm::vec3 dir = pos - last_pos;
|
|
GlmHelper::Normalize(dir);
|
|
MovePathPoint point;
|
|
point.src_pos.FromGlmVec3(last_pos);
|
|
point.curr_pos.FromGlmVec3(last_pos);
|
|
point.dir.x = dir.x;
|
|
point.dir.y = dir.y;
|
|
point.dir.z = dir.z;
|
|
point.distance = GlmHelper::Norm2D(pos - last_pos);
|
|
point.tar_pos.FromGlmVec3(pos);
|
|
if (i > 0 && last_poly_pos < npolys && path_index > 0) {
|
|
dtPolyRef poly_ref = straightPathPolys[path_index];
|
|
int found_pos = -1;
|
|
bool is_same_flags = true;
|
|
unsigned short last_flags = 0;
|
|
for (int ii = last_poly_pos; ii < npolys; ++ii) {
|
|
dtPolyRef curr_poly_ref = polys_[ii];
|
|
if (curr_poly_ref != poly_ref) {
|
|
unsigned short flags = 0;
|
|
auto status = navmesh_->getPolyFlags(curr_poly_ref, &flags);
|
|
if (!dtStatusSucceed(status)) {
|
|
abort();
|
|
}
|
|
if (flags) {
|
|
point.spec_polys.push_back(curr_poly_ref);
|
|
}
|
|
if (last_flags && last_flags != flags) {
|
|
is_same_flags = false;
|
|
}
|
|
last_flags = flags;
|
|
} else {
|
|
found_pos = ii;
|
|
break;
|
|
}
|
|
}
|
|
if (found_pos > -1) {
|
|
last_poly_pos = found_pos;
|
|
} else {
|
|
#ifdef MYDEBUG1
|
|
abort();
|
|
#endif
|
|
}
|
|
if (is_same_flags) {
|
|
point.same_polys_flags = last_flags;
|
|
}
|
|
}
|
|
paths.push_back(point);
|
|
|
|
last_pos = pos;
|
|
}//end if
|
|
++path_index;
|
|
}
|
|
}
|
|
|
|
return paths.size();
|
|
}
|
|
|
|
bool MapInstance::RandPoint(const glm::vec3& center, float range, glm::vec3& out_point)
|
|
{
|
|
glm::vec3 hit_point;
|
|
bool hit_result = false;
|
|
|
|
glm::vec3 start = center;
|
|
glm::vec3 dir = GlmHelper::UP;
|
|
GlmHelper::RotateY(dir, glm::radians(1.0f + (float)(rand() % 360)));
|
|
GlmHelper::Normalize(dir);
|
|
glm::vec3 end = center + dir * (float)(rand() % (int)std::max(1.0f, range));
|
|
|
|
out_point = end;
|
|
#ifdef MYDEBUG
|
|
a8::XPrintf("MapInstance::RandPoint:%f %f %f\n",
|
|
{
|
|
out_point.x,
|
|
out_point.y,
|
|
out_point.z,
|
|
});
|
|
#endif
|
|
return true;
|
|
Scale(start);
|
|
Scale(end);
|
|
if (Raycast
|
|
(
|
|
start,
|
|
end,
|
|
hit_point,
|
|
hit_result,
|
|
GetMoveIncludeFlags(),
|
|
GetMoveExcludeFlags()
|
|
)) {
|
|
UnScale(hit_point);
|
|
out_point = hit_point;
|
|
return true;
|
|
} else {
|
|
out_point = center;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool MapInstance::FindRandomPointAroundCircle(const glm::vec3& center_pos,
|
|
float max_radius,
|
|
glm::vec3& random_pt)
|
|
{
|
|
ConnectableQueryFilter filter;
|
|
filter.map_instance = this;
|
|
filter.setIncludeFlags(GetMoveIncludeFlags());
|
|
filter.setExcludeFlags(GetMoveExcludeFlags());
|
|
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
|
|
const float extents[3] = {2.f/10.0f, 4.f, 2.f/10.f};
|
|
float nearestPt[3];
|
|
|
|
float center[3];
|
|
center[0] = center_pos.x;
|
|
center[1] = center_pos.y;
|
|
center[2] = center_pos.z;
|
|
|
|
navmesh_query_->findNearestPoly(center, extents, &filter, &startRef, nearestPt);
|
|
if (!startRef) {
|
|
return false;
|
|
}
|
|
|
|
dtPolyRef randomRef = INVALID_NAVMESH_POLYREF;
|
|
float randomPt[3];
|
|
dtStatus status = navmesh_query_->findRandomPointAroundCircle
|
|
(startRef,
|
|
//center,
|
|
nearestPt,
|
|
max_radius,
|
|
&filter,
|
|
frand,
|
|
&randomRef,
|
|
randomPt);
|
|
|
|
if (dtStatusSucceed(status)) {
|
|
random_pt.x = randomPt[0];
|
|
random_pt.y = randomPt[1];
|
|
random_pt.z = randomPt[2];
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool MapInstance::Raycast(const glm::vec3& start, const glm::vec3& end,
|
|
glm::vec3& hit_point, bool& hit_result,
|
|
unsigned short includeFlags,
|
|
unsigned short excludeFlags)
|
|
{
|
|
float spos[3];
|
|
spos[0] = start.x;
|
|
spos[1] = start.y;
|
|
spos[2] = start.z;
|
|
|
|
float epos[3];
|
|
epos[0] = end.x;
|
|
epos[1] = end.y;
|
|
epos[2] = end.z;
|
|
|
|
dtStatus status = 0;
|
|
dtQueryFilter filter;
|
|
filter.setIncludeFlags(includeFlags);
|
|
filter.setExcludeFlags(excludeFlags);
|
|
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
{
|
|
const float extents[3] = {2.f/10, 4.f, 2.f/10};
|
|
float nearestPt[3];
|
|
status = navmesh_query_->findNearestPoly(spos, extents, &filter, &startRef, nearestPt);
|
|
if (startRef == INVALID_NAVMESH_POLYREF) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
float t = 0;
|
|
int npolys;
|
|
memset(hit_normal_, 0, sizeof(hit_normal_));
|
|
#if 1
|
|
status = navmesh_query_->newRaycast(666, startRef, spos, epos, &filter, &t, hit_normal_, polys_, &npolys, MAX_POLYS);
|
|
#else
|
|
status = navmesh_query_->raycast(startRef, spos, epos, &filter, &t, hit_normal_, polys_, &npolys, MAX_POLYS);
|
|
#endif
|
|
if (!dtStatusSucceed(status)) {
|
|
#ifdef MYDEBUG
|
|
abort();
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
if (npolys <= 0) {
|
|
return false;
|
|
}
|
|
|
|
if (t > 1) {
|
|
// No Hit
|
|
hit_pos_[0] = epos[0];
|
|
hit_pos_[1] = epos[1];
|
|
hit_pos_[2] = epos[2];
|
|
hit_result = false;
|
|
} else {
|
|
if (t < 0.00001f) {
|
|
return false;
|
|
}
|
|
//需要处理spos == epos的情况!!!!
|
|
// Hit
|
|
dtVlerp(hit_pos_, spos, epos, t);
|
|
hit_result = true;
|
|
}
|
|
|
|
{
|
|
float closest[3];
|
|
bool pos_over_poly = false;
|
|
status = navmesh_query_->closestPointOnPoly(polys_[npolys - 1], hit_pos_, closest, &pos_over_poly);
|
|
if (!dtStatusSucceed(status)) {
|
|
abort();
|
|
}
|
|
hit_pos_[1] = closest[1];
|
|
}
|
|
|
|
hit_point.x = hit_pos_[0];
|
|
hit_point.y = hit_pos_[1];
|
|
hit_point.z = hit_pos_[2];
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MapInstance::FindNearestPoint(const glm::vec3& center, float radius, glm::vec3& nearest_pt)
|
|
{
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
|
|
dtQueryFilter filter;
|
|
filter.setIncludeFlags(GetMoveIncludeFlags());
|
|
filter.setExcludeFlags(GetMoveExcludeFlags());
|
|
|
|
const float extents[3] = {radius, 10.0f, radius};
|
|
float nearestPt[3];
|
|
|
|
float pos[3];
|
|
pos[0] = center.x;
|
|
pos[1] = center.y;
|
|
pos[2] = center.z;
|
|
|
|
navmesh_query_->findNearestPoly(pos, extents, &filter, &startRef, nearestPt);
|
|
if (!startRef) {
|
|
return false;
|
|
}
|
|
|
|
nearest_pt.x = nearestPt[0];
|
|
nearest_pt.y = nearestPt[1];
|
|
nearest_pt.z = nearestPt[2];
|
|
return true;
|
|
}
|
|
|
|
bool MapInstance::FindConnectableNearestPoint(const glm::vec3& center, float radius, glm::vec3& nearest_pt)
|
|
{
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
|
|
ConnectableQueryFilter filter;
|
|
filter.map_instance = this;
|
|
filter.setIncludeFlags(GetMoveIncludeFlags());
|
|
filter.setExcludeFlags(GetMoveExcludeFlags());
|
|
|
|
const float extents[3] = {radius, 10.0f, radius};
|
|
float nearestPt[3];
|
|
|
|
float pos[3];
|
|
pos[0] = center.x;
|
|
pos[1] = center.y;
|
|
pos[2] = center.z;
|
|
|
|
navmesh_query_->findNearestPoly(pos, extents, &filter, &startRef, nearestPt);
|
|
if (!startRef) {
|
|
return false;
|
|
}
|
|
|
|
nearest_pt.x = nearestPt[0];
|
|
nearest_pt.y = nearestPt[1];
|
|
nearest_pt.z = nearestPt[2];
|
|
return true;
|
|
}
|
|
|
|
bool MapInstance::GetPosHeight(const Position& pos, float& out_height)
|
|
{
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
|
|
dtQueryFilter filter;
|
|
filter.setIncludeFlags(GetMoveIncludeFlags());
|
|
filter.setExcludeFlags(GetMoveExcludeFlags());
|
|
|
|
const float extents[3] = {2.f, 4.f, 2.f};
|
|
float nearestPt[3];
|
|
|
|
float center[3];
|
|
center[0] = pos.GetX() * GetMapMeta()->scale();
|
|
center[1] = pos.GetY();
|
|
center[2] = pos.GetZ() * GetMapMeta()->scale();
|
|
|
|
bool isOverPoly;
|
|
navmesh_query_->findNearestPoly(center, extents, &filter, &startRef, nearestPt, &isOverPoly);
|
|
if (!startRef) {
|
|
return false;
|
|
}
|
|
|
|
auto ret = navmesh_query_->getPolyHeight(startRef, nearestPt, &out_height);
|
|
#if 0
|
|
assert(ret == DT_SUCCESS);
|
|
#endif
|
|
if (ret != DT_SUCCESS) {
|
|
out_height = pos.GetY();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void MapInstance::Scale(glm::vec3& v)
|
|
{
|
|
float old_y = v.y;
|
|
v *= GetMapMeta()->scale();
|
|
v.y = old_y;
|
|
}
|
|
|
|
void MapInstance::UnScale(glm::vec3& v)
|
|
{
|
|
float old_y = v.y;
|
|
v /= GetMapMeta()->scale();
|
|
v.y = old_y;
|
|
}
|
|
|
|
glm::vec3 MapInstance::UnScaleEx(const glm::vec3& v)
|
|
{
|
|
glm::vec3 result = v;
|
|
UnScale(result);
|
|
return result;
|
|
}
|
|
|
|
dtPoly* MapInstance::GetPoly(glm::vec3 pos, int& poly_idx)
|
|
{
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
|
|
dtQueryFilter filter;
|
|
filter.setIncludeFlags(GetMoveIncludeFlags());
|
|
filter.setExcludeFlags(GetMoveExcludeFlags());
|
|
|
|
const float extents[3] = {2.f, 4.f, 2.f};
|
|
float nearestPt[3];
|
|
|
|
Scale(pos);
|
|
|
|
float pos1[3];
|
|
pos1[0] = pos.x;
|
|
pos1[1] = pos.y;
|
|
pos1[2] = pos.z;
|
|
|
|
const dtMeshTile* tile = navmesh_->getTileAt(0, 0, 0);
|
|
assert(tile);
|
|
navmesh_query_->findNearestPoly(pos1, extents, &filter, &startRef, nearestPt);
|
|
if (startRef) {
|
|
unsigned int slat = 0;
|
|
unsigned int it = 0;
|
|
unsigned int ip = 0;
|
|
navmesh_->decodePolyId(startRef, slat, it, ip);
|
|
poly_idx = ip;
|
|
return &tile->polys[ip];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void MapInstance::MarkMapAreaPolys()
|
|
{
|
|
const dtMeshTile* tile = navmesh_->getTileAt(0, 0, 0);
|
|
if (!tile) {
|
|
abort();
|
|
}
|
|
poly_ext_datas_.reserve(tile->header->polyCount);
|
|
for (int i = 0; i < tile->header->polyCount; ++i) {
|
|
int ext_flag = 0;
|
|
dtPoly* poly = &tile->polys[i];
|
|
if ((poly->flags & SAMPLE_POLYFLAGS_SWIM) == SAMPLE_POLYFLAGS_SWIM) {
|
|
#if 0
|
|
const mt::MapArea* last_area_meta = nullptr;
|
|
for (int ii = 0; ii < poly->vertCount; ++ii) {
|
|
const float* vc = &tile->verts[poly->verts[ii]*3];
|
|
const mt::MapArea* area_meta = mt::MapArea::GetAreaByPoint
|
|
(map_meta_->map_id(),
|
|
vc[0] / GetMapMeta()->scale(),
|
|
vc[1],
|
|
vc[2] / GetMapMeta()->scale());
|
|
if (!area_meta) {
|
|
abort();
|
|
}
|
|
if (last_area_meta && last_area_meta != area_meta) {
|
|
abort();
|
|
}
|
|
last_area_meta = area_meta;
|
|
}
|
|
if (!last_area_meta) {
|
|
abort();
|
|
}
|
|
if (last_area_meta->area_type() != 1) {
|
|
abort();
|
|
}
|
|
switch (last_area_meta->area_subtype()) {
|
|
case 1:
|
|
{
|
|
a8::SetBitFlag(ext_flag, kWater1ExtFlag);
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
a8::SetBitFlag(ext_flag, kWater2ExtFlag);
|
|
}
|
|
break;
|
|
case 3:
|
|
{
|
|
a8::SetBitFlag(ext_flag, kWater3ExtFlag);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
abort();
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
} else if ((poly->flags & SAMPLE_POLYFLAGS_GLASS) == SAMPLE_POLYFLAGS_GLASS) {
|
|
for (int ii = 0; ii < poly->vertCount; ++ii) {
|
|
const float* vc = &tile->verts[poly->verts[ii]*3];
|
|
grass_pos_hash_.push_back
|
|
(glm::vec3(vc[0] / GetMapMeta()->scale(),
|
|
vc[1],
|
|
vc[2] / GetMapMeta()->scale()
|
|
));
|
|
}
|
|
}
|
|
poly_ext_datas_.push_back(ext_flag);
|
|
}
|
|
}
|
|
|
|
bool MapInstance::RaycastEx(const glm::vec3& start, const glm::vec3& end,
|
|
glm::vec3& hit_point, bool& hit_result,
|
|
int& same_polys_flags, std::vector<dtPolyRef>& spec_polys,
|
|
unsigned short exclude_flags)
|
|
{
|
|
same_polys_flags = 0;
|
|
|
|
float spos[3];
|
|
spos[0] = start.x;
|
|
spos[1] = start.y;
|
|
spos[2] = start.z;
|
|
|
|
float epos[3];
|
|
epos[0] = end.x;
|
|
epos[1] = end.y;
|
|
epos[2] = end.z;
|
|
|
|
dtStatus status = 0;
|
|
dtQueryFilter filter;
|
|
filter.setIncludeFlags(GetMoveIncludeFlags());
|
|
filter.setExcludeFlags(exclude_flags);
|
|
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
{
|
|
const float extents[3] = {2.f/10, 4.f, 2.f/10};
|
|
float nearestPt[3];
|
|
status = navmesh_query_->findNearestPoly(spos, extents, &filter, &startRef, nearestPt);
|
|
if (startRef == INVALID_NAVMESH_POLYREF) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
float t = 0;
|
|
int npolys;
|
|
memset(hit_normal_, 0, sizeof(hit_normal_));
|
|
#if 1
|
|
status = navmesh_query_->newRaycast(666, startRef, spos, epos, &filter, &t, hit_normal_, polys_, &npolys, MAX_POLYS);
|
|
#else
|
|
status = navmesh_query_->raycast(startRef, spos, epos, &filter, &t, hit_normal_, polys_, &npolys, MAX_POLYS);
|
|
#endif
|
|
if (!dtStatusSucceed(status)) {
|
|
#ifdef MYDEBUG
|
|
abort();
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
if (npolys <= 0) {
|
|
return false;
|
|
}
|
|
|
|
if (t > 1) {
|
|
// No Hit
|
|
hit_pos_[0] = epos[0];
|
|
hit_pos_[1] = epos[1];
|
|
hit_pos_[2] = epos[2];
|
|
hit_result = false;
|
|
} else {
|
|
if (t < 0.00001f) {
|
|
return false;
|
|
}
|
|
//需要处理spos == epos的情况!!!!
|
|
// Hit
|
|
dtVlerp(hit_pos_, spos, epos, t);
|
|
hit_result = true;
|
|
}
|
|
|
|
{
|
|
float closest[3];
|
|
bool pos_over_poly = false;
|
|
status = navmesh_query_->closestPointOnPoly(polys_[npolys - 1], hit_pos_, closest, &pos_over_poly);
|
|
if (!dtStatusSucceed(status)) {
|
|
abort();
|
|
}
|
|
hit_pos_[1] = closest[1];
|
|
}
|
|
{
|
|
bool is_same_flags = true;
|
|
unsigned short last_flags = 0;
|
|
spec_polys.reserve(npolys);
|
|
for (int i = 0; i < npolys; ++i) {
|
|
unsigned short flags = 0;
|
|
status = navmesh_->getPolyFlags(polys_[i], &flags);
|
|
if (!dtStatusSucceed(status)) {
|
|
abort();
|
|
}
|
|
if (flags) {
|
|
spec_polys.push_back(polys_[i]);
|
|
}
|
|
if (last_flags && last_flags != flags) {
|
|
is_same_flags = false;
|
|
}
|
|
last_flags = flags;
|
|
}
|
|
if (is_same_flags) {
|
|
same_polys_flags = last_flags;
|
|
}
|
|
}
|
|
|
|
hit_point.x = hit_pos_[0];
|
|
hit_point.y = hit_pos_[1];
|
|
hit_point.z = hit_pos_[2];
|
|
|
|
return true;
|
|
}
|
|
|
|
void MapInstance::CheckTerrain(Creature* c, int same_poly_flags, const std::vector<dtPolyRef>& spec_polys)
|
|
{
|
|
if (same_poly_flags) {
|
|
c->CheckSpecObject(same_poly_flags);
|
|
} else {
|
|
if (spec_polys.empty()) {
|
|
c->CheckSpecObject(0);
|
|
} else {
|
|
float pos[3];
|
|
pos[0] = c->GetPos().GetX() * GetMapMeta()->scale();
|
|
pos[1] = c->GetPos().GetY();
|
|
pos[2] = c->GetPos().GetZ() * GetMapMeta()->scale();
|
|
float closest[3];
|
|
bool found = false;
|
|
for (auto& poly_ref : spec_polys) {
|
|
dtStatus status = navmesh_query_->closestPointOnPolyBoundary(poly_ref, pos, closest);
|
|
if (dtStatusSucceed(status) &&
|
|
std::fabs(closest[0] - c->GetPos().GetX() * GetMapMeta()->scale()) <= 0.1f &&
|
|
std::fabs(closest[2] - c->GetPos().GetZ() * GetMapMeta()->scale()) <= 0.1f) {
|
|
unsigned short flags = 0;
|
|
if (dtStatusSucceed(navmesh_->getPolyFlags(poly_ref, &flags))) {
|
|
c->CheckSpecObject(flags);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!found) {
|
|
c->CheckSpecObject(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MapInstance::TraverseHouseList(std::function<void (HouseInfo*)> func)
|
|
{
|
|
|
|
}
|
|
|
|
bool MapInstance::PtInHouse(const glm::vec3& pt, glm::vec3& nearest_pt)
|
|
{
|
|
float fpt[3];
|
|
fpt[0] = pt.x;
|
|
fpt[1] = pt.y;
|
|
fpt[2] = pt.z;
|
|
float closest[3];
|
|
|
|
float edged[DT_VERTS_PER_POLYGON];
|
|
float edget[DT_VERTS_PER_POLYGON];
|
|
for (auto& house : houses_) {
|
|
if (house.verts.empty()) {
|
|
continue;
|
|
}
|
|
float* verts = &(house.verts[0]);
|
|
int nv = house.verts.size() / 3;
|
|
if (!dtPointInPolygon(fpt, verts, nv)) {
|
|
continue;
|
|
}
|
|
if (dtDistancePtPolyEdgesSqr(fpt, verts, nv, edged, edget)) {
|
|
float dmin = edged[0];
|
|
int imin = 0;
|
|
for (size_t i = 1; i < nv; ++i) {
|
|
if (edged[i] < dmin) {
|
|
dmin = edged[i];
|
|
imin = i;
|
|
}
|
|
}
|
|
const float* va = &verts[imin*3];
|
|
const float* vb = &verts[((imin+1)%nv)*3];
|
|
dtVlerp(closest, va, vb, edget[imin]);
|
|
nearest_pt.x = closest[0];
|
|
nearest_pt.y = closest[1];
|
|
nearest_pt.z = closest[2];
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MapInstance::LoadHouse()
|
|
{
|
|
if (GetMapMeta()->collider_info) {
|
|
std::shared_ptr<mc::ColliderNode> building_root = GetMapMeta()->collider_info->GetNode("building");
|
|
if (building_root) {
|
|
for (auto& pair : building_root->childs) {
|
|
auto node = pair.second;
|
|
std::vector<glm::vec3> old_points;
|
|
std::vector<glm::vec3> new_points;
|
|
{
|
|
mc::RotateBounds(node->bounds.center,
|
|
node->bounds.size + glm::vec3(10.0f, 0, 10.f),
|
|
glm::quat_identity<float, glm::qualifier::defaultp>(),
|
|
old_points
|
|
);
|
|
|
|
mc::RotateBounds(node->bounds.center,
|
|
node->bounds.size + glm::vec3(10.0f, 0, 10.f),
|
|
node->transform.local_rotation,
|
|
new_points
|
|
);
|
|
}
|
|
#ifdef MYDEBUG1
|
|
{
|
|
std::string data = "old: " + node->name + " ";
|
|
for (auto& point : old_points) {
|
|
data += a8::Format("%f,%f,%f ", {point.x, point.y, point.z});
|
|
}
|
|
data += "\nnew:";
|
|
for (auto& point : new_points) {
|
|
data += a8::Format("%f,%f,%f ", {point.x, point.y, point.z});
|
|
}
|
|
a8::XPrintf("%s\n", {data});
|
|
}
|
|
#endif
|
|
|
|
HouseInfo p;
|
|
p.node = node;
|
|
{
|
|
for (size_t i = 0; i < new_points.size(); ++i) {
|
|
const auto& point = new_points[i];
|
|
if (i >= 4) {
|
|
p.verts.push_back(point.x);
|
|
p.verts.push_back(point.y);
|
|
p.verts.push_back(point.z);
|
|
}
|
|
}
|
|
if (p.verts.size() != 3 * 4) {
|
|
abort();
|
|
}
|
|
}
|
|
houses_.push_back(p);
|
|
}
|
|
}
|
|
{
|
|
int box_tri_arr[12][3] = {
|
|
{0, 1, 2},
|
|
{0, 3, 2},
|
|
|
|
{0, 1, 5},
|
|
{0, 4, 5},
|
|
|
|
{0, 3, 7},
|
|
{0, 4, 7},
|
|
|
|
{6, 5, 4},
|
|
{6, 7, 4},
|
|
|
|
{6, 7, 3},
|
|
{6, 2, 3},
|
|
|
|
{6, 2, 1},
|
|
{6, 5, 1}
|
|
|
|
};
|
|
//求三角形min_y max_y
|
|
things_.reserve(1024 * 10);
|
|
auto cb =
|
|
[this, box_tri_arr] (std::shared_ptr<mc::ColliderNode> node)
|
|
{
|
|
if (!node->colliders.empty()) {
|
|
for (auto c : node->colliders) {
|
|
if (c->type == mc::kMeshCollider) {
|
|
mc::MeshCollider* mesh_collider = (mc::MeshCollider*)c.get();
|
|
mesh_collider->mesh.triangles.reserve(mesh_collider->mesh.raw_triangles.size() / 3);
|
|
for (int i = 0; i < mesh_collider->mesh.raw_triangles.size(); i += 3) {
|
|
auto& tri = a8::FastAppend(mesh_collider->mesh.triangles);
|
|
tri.node = node.get();
|
|
int v0 = mesh_collider->mesh.raw_triangles[i + 0];
|
|
int v1 = mesh_collider->mesh.raw_triangles[i + 1];
|
|
int v2 = mesh_collider->mesh.raw_triangles[i + 2];
|
|
tri.vert0 = mesh_collider->mesh.vertices[v0];
|
|
tri.vert1 = mesh_collider->mesh.vertices[v1];
|
|
tri.vert2 = mesh_collider->mesh.vertices[v2];
|
|
tri.min_y = tri.vert0.y;
|
|
tri.max_y = tri.vert0.y;
|
|
for (int ii = 1; ii < 3; ++ii) {
|
|
int vp = mesh_collider->mesh.raw_triangles[i + ii];
|
|
float y = mesh_collider->mesh.vertices.at(vp).y;
|
|
if (y < tri.min_y) {
|
|
tri.min_y = y;
|
|
}
|
|
if (y > tri.max_y) {
|
|
tri.max_y = y;
|
|
}
|
|
}//end for ii
|
|
tri.min_y -= 1.0f;
|
|
tri.max_y += 1.0f;
|
|
map_service_->AddTriangle(&tri);
|
|
}//end for i
|
|
} else if (c->type == mc::kBoxCollider) {
|
|
mc::BoxCollider* box_collider = (mc::BoxCollider*)c.get();
|
|
#if 0
|
|
if (node->name == "Wall2_1 (18)") {
|
|
printf("node->name %s %f,%f,%f %f,%f,%f\n",
|
|
node->name.c_str(),
|
|
box_collider->center.x,
|
|
box_collider->center.y,
|
|
box_collider->center.z,
|
|
box_collider->size.x,
|
|
box_collider->size.y,
|
|
box_collider->size.z
|
|
);
|
|
}
|
|
#endif
|
|
std::vector<glm::vec3> new_points;
|
|
mc::RotateBounds(box_collider->center,
|
|
box_collider->size,
|
|
node->transform.local_rotation,
|
|
new_points
|
|
);
|
|
box_collider->triangles.reserve(2 * 6);
|
|
for (int i = 0; i < 12; ++i) {
|
|
auto& tri = a8::FastAppend(box_collider->triangles);
|
|
tri.node = node.get();
|
|
tri.vert0 = new_points[box_tri_arr[i][0]];
|
|
tri.vert1 = new_points[box_tri_arr[i][1]];
|
|
tri.vert2 = new_points[box_tri_arr[i][2]];
|
|
tri.min_y = tri.vert0.y;
|
|
tri.max_y = tri.vert0.y;
|
|
for (int ii = 1; ii < 3; ++ii) {
|
|
float y = new_points[box_tri_arr[i][ii]].y;
|
|
if (y < tri.min_y) {
|
|
tri.min_y = y;
|
|
}
|
|
if (y > tri.max_y) {
|
|
tri.max_y = y;
|
|
}
|
|
} //endif ii
|
|
tri.min_y -= 1.0f;
|
|
tri.max_y += 1.0f;
|
|
map_service_->AddTriangle(&tri);
|
|
#if 0
|
|
if (node->name == "Wall2_1 (18)") {
|
|
printf("node->name %s %f,%f,%f %f,%f,%f min_y:%f max_y:%f %f,%f,%f %f,%f,%f %f,%f,%f %d:%d:%d\n",
|
|
node->name.c_str(),
|
|
box_collider->center.x,
|
|
box_collider->center.y,
|
|
box_collider->center.z,
|
|
box_collider->size.x,
|
|
box_collider->size.y,
|
|
box_collider->size.z,
|
|
tri.min_y,
|
|
tri.max_y,
|
|
#if 1
|
|
tri.vert0.x,
|
|
tri.vert0.y,
|
|
tri.vert0.z,
|
|
|
|
tri.vert1.x,
|
|
tri.vert1.y,
|
|
tri.vert1.z,
|
|
|
|
tri.vert2.x,
|
|
tri.vert2.y,
|
|
tri.vert2.z
|
|
#else
|
|
tri.vert0.x - box_collider->center.x,
|
|
tri.vert0.y - box_collider->center.y,
|
|
tri.vert0.z - box_collider->center.z,
|
|
|
|
tri.vert1.x - box_collider->center.x,
|
|
tri.vert1.y - box_collider->center.y,
|
|
tri.vert1.z - box_collider->center.z,
|
|
|
|
tri.vert2.x - box_collider->center.x,
|
|
tri.vert2.y - box_collider->center.y,
|
|
tri.vert2.z - box_collider->center.z
|
|
#endif
|
|
,box_tri_arr[i][0],
|
|
box_tri_arr[i][1],
|
|
box_tri_arr[i][2]
|
|
);
|
|
}
|
|
#endif
|
|
}//endif i
|
|
}//end forc
|
|
}
|
|
things_.push_back(node);
|
|
}
|
|
};
|
|
for (auto& pair : GetMapMeta()->collider_info->GetNodes()) {
|
|
#ifdef MYDEBUG1
|
|
printf("node->name %s childs:%d colliders:%d\n",
|
|
pair.second->name.c_str(),
|
|
(int)pair.second->childs.size(),
|
|
(int)pair.second->colliders.size());
|
|
#endif
|
|
cb(pair.second);
|
|
TraverseMapColliderNode(pair.second, cb);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool MapInstance::SceneRaycast(const glm::vec3& orig,
|
|
const glm::vec3& dir,
|
|
float max_distance,
|
|
glm::vec3& hit_pos,
|
|
float& ray_length)
|
|
{
|
|
if (max_distance <= 0.001f) {
|
|
return false;
|
|
}
|
|
float nearest_distance = 0.0f;
|
|
CellNode* nearest_node = nullptr;
|
|
glm::vec3 nearest_pt(0.0f, 0.0f, 0.0f);
|
|
int raycast_index = MapMgr::Instance()->IncCurrRaycastIndex();
|
|
float len = 0.0f;
|
|
bool result = false;
|
|
bool end = false;
|
|
int tri_count = 0;
|
|
do {
|
|
glm::vec3 curr_pos = orig + dir * len;
|
|
if (len > max_distance) {
|
|
len = max_distance;
|
|
curr_pos = orig + dir * len;
|
|
end = true;
|
|
}
|
|
int grid_id = map_service_->GetGridId(curr_pos.x, curr_pos.z);
|
|
list_head* grid_list[9];
|
|
int grid_count = 0;
|
|
map_service_->GetGridList(grid_id, grid_list, grid_count);
|
|
for (int i = 0; i < grid_count; ++i){
|
|
list_head* head = grid_list[i];
|
|
if (list_empty(head)) {
|
|
continue;
|
|
}
|
|
|
|
CellNode *node, *tmp;
|
|
list_for_each_entry_safe(node, tmp, head, entry) {
|
|
if (node->tri->check_flag != raycast_index) {
|
|
glm::vec2 bary_position;
|
|
float distance;
|
|
bool hit = glm::intersectRayTriangle
|
|
(orig,
|
|
dir,
|
|
node->tri->vert0,
|
|
node->tri->vert1,
|
|
node->tri->vert2,
|
|
bary_position,
|
|
distance
|
|
);
|
|
#if 0
|
|
a8::XPrintf("rayname:%s hit:%d distance:%f orig:%f,%f,%f %f,%f,%f %f,%f,%f %f,%f,%fn\n",
|
|
{node->tri->node->name, hit, distance, orig.x, orig.y, orig.z,
|
|
|
|
node->tri->vert0.x,
|
|
node->tri->vert0.y,
|
|
node->tri->vert0.z,
|
|
|
|
node->tri->vert1.x,
|
|
node->tri->vert1.y,
|
|
node->tri->vert1.z,
|
|
|
|
node->tri->vert2.x,
|
|
node->tri->vert2.y,
|
|
node->tri->vert2.z,
|
|
|
|
});
|
|
#endif
|
|
node->tri->check_flag = raycast_index;
|
|
++tri_count;
|
|
if (hit && distance > 0.00001f) {
|
|
if (nearest_node) {
|
|
if (distance < nearest_distance) {
|
|
nearest_node = node;
|
|
nearest_distance = distance;
|
|
nearest_pt = orig + dir * distance;
|
|
}
|
|
} else if (distance <= max_distance) {
|
|
nearest_node = node;
|
|
nearest_distance = distance;
|
|
nearest_pt = orig + dir * distance;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (nearest_node && nearest_distance <= len) {
|
|
result = true;
|
|
end = true;
|
|
} else {
|
|
len += 5.0f;
|
|
}
|
|
} while (!end);
|
|
|
|
if (result) {
|
|
#ifdef MYDEBUG1
|
|
if (DebugCmd::Enable()) {
|
|
a8::XPrintf("nearest_node:%s tri_count:%d nearest_distance:%f\n",
|
|
{nearest_node->tri->node->name,
|
|
tri_count,
|
|
nearest_distance});
|
|
}
|
|
#endif
|
|
hit_pos = nearest_pt;
|
|
ray_length = nearest_distance;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool MapInstance::GetNearestGrass(const glm::vec3& center, glm::vec3& out_pt)
|
|
{
|
|
float nearest_distance = FLT_MAX;
|
|
glm::vec3* nearest_pt = nullptr;
|
|
for (auto& pt : grass_pos_hash_) {
|
|
float distance = std::fabs(pt.x - center.x) + std::fabs(pt.z - center.z);
|
|
if (distance < nearest_distance) {
|
|
nearest_distance = distance;
|
|
nearest_pt = & pt;
|
|
}
|
|
}
|
|
if (nearest_pt) {
|
|
out_pt = *nearest_pt;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MapInstance::AdjustOnLandPoint(glm::vec3& point)
|
|
{
|
|
float center[3];
|
|
center[0] = point.x;
|
|
center[1] = point.y;
|
|
center[2] = point.z;
|
|
|
|
const float extents[3] = {4.0f/10.0f, 100.0f, 4.0f/10.0f};
|
|
|
|
ConnectableQueryFilter filter;
|
|
filter.map_instance = this;
|
|
filter.setIncludeFlags(GetMoveIncludeFlags());
|
|
filter.setExcludeFlags(GetMoveExcludeFlags());
|
|
|
|
int poly_count = 0;
|
|
dtStatus status = navmesh_query_->queryPolygons(center,
|
|
extents,
|
|
&filter,
|
|
polys_,
|
|
&poly_count,
|
|
MAX_POLYS);
|
|
if (dtStatusFailed(status) || poly_count <= 0) {
|
|
return;
|
|
}
|
|
|
|
glm::vec3 orig = glm::vec3(point.x, 100.0f, point.z);;
|
|
glm::vec3 dir = glm::vec3(0.0f, -1.0f, 0.0f);
|
|
const dtPoly* nearest_poly = nullptr;
|
|
float nearest_distance = 0.0f;
|
|
|
|
for (int i = 0; i < poly_count; ++i) {
|
|
unsigned int slat = 0;
|
|
unsigned int it = 0;
|
|
unsigned int ip = 0;
|
|
navmesh_->decodePolyId(polys_[i], slat, it, ip);
|
|
|
|
const dtMeshTile* tile = navmesh_->getTileByRef(polys_[i]);
|
|
if (!tile) {
|
|
abort();
|
|
}
|
|
if (ip >= tile->header->polyCount) {
|
|
abort();
|
|
}
|
|
const dtPoly* poly = &tile->polys[ip];
|
|
for (int ii = 2; ii < poly->vertCount; ++ii) {
|
|
const float* va = &tile->verts[poly->verts[0]*3];
|
|
const float* vb = &tile->verts[poly->verts[ii-1]*3];
|
|
const float* vc = &tile->verts[poly->verts[ii]*3];
|
|
|
|
glm::vec3 v0 = glm::vec3(va[0], va[1], va[2]);
|
|
glm::vec3 v1 = glm::vec3(vb[0], vb[1], vb[2]);
|
|
glm::vec3 v2 = glm::vec3(vc[0], vc[1], vc[2]);
|
|
|
|
glm::vec2 bary_position;
|
|
float distance;
|
|
|
|
bool hit = glm::intersectRayTriangle
|
|
(orig,
|
|
dir,
|
|
v0,
|
|
v1,
|
|
v2,
|
|
bary_position,
|
|
distance
|
|
);
|
|
if (hit && distance > 0.00001f) {
|
|
if (nearest_poly) {
|
|
if (distance < nearest_distance) {
|
|
nearest_poly = poly;
|
|
nearest_distance = distance;
|
|
}
|
|
} else {
|
|
nearest_poly = poly;
|
|
nearest_distance = distance;
|
|
}
|
|
}
|
|
}//end for ii
|
|
}//end for i;
|
|
if (!nearest_poly) {
|
|
return;
|
|
}
|
|
glm::vec3 nearest_pt = orig + dir * nearest_distance;
|
|
point.y = nearest_pt.y;
|
|
}
|
|
|
|
void MapInstance::MarkConnectablePolys()
|
|
{
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
{
|
|
glm::vec3 pos = map_meta_->GroundSamplingPos();
|
|
|
|
dtQueryFilter filter;
|
|
filter.setIncludeFlags(GetMoveIncludeFlags());
|
|
filter.setExcludeFlags(GetMoveExcludeFlags());
|
|
|
|
const float extents[3] = {2.f, 4.f, 2.f};
|
|
float nearestPt[3];
|
|
|
|
Scale(pos);
|
|
|
|
float pos1[3];
|
|
pos1[0] = pos.x;
|
|
pos1[1] = pos.y;
|
|
pos1[2] = pos.z;
|
|
|
|
navmesh_query_->findNearestPoly(pos1, extents, &filter, &startRef, nearestPt);
|
|
}
|
|
if (!startRef) {
|
|
abort();
|
|
}
|
|
|
|
std::list<dtPolyRef> queue;
|
|
queue.push_back(startRef);
|
|
connectable_polys_.insert(startRef);
|
|
while (!queue.empty()) {
|
|
dtPolyRef poly_ref = queue.front();
|
|
queue.pop_front();
|
|
|
|
const dtPoly* poly = nullptr;
|
|
const dtMeshTile* tile = 0;
|
|
navmesh_->getTileAndPolyByRefUnsafe(poly_ref, &tile, &poly);
|
|
for (unsigned int i = poly->firstLink; i != DT_NULL_LINK; i = tile->links[i].next) {
|
|
dtPolyRef neighbour_ref = tile->links[i].ref;
|
|
if (!neighbour_ref) {
|
|
continue;
|
|
}
|
|
if (connectable_polys_.find(neighbour_ref) !=
|
|
connectable_polys_.end()) {
|
|
continue;
|
|
}
|
|
queue.push_back(neighbour_ref);
|
|
connectable_polys_.insert(neighbour_ref);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool MapInstance::IsConnectablePoly(dtPolyRef poly_ref)
|
|
{
|
|
return connectable_polys_.find(poly_ref) != connectable_polys_.end();
|
|
}
|
|
|
|
bool MapInstance::IsValidPos(const glm::vec3& point)
|
|
{
|
|
if (point.x >= GetMapMeta()->map_width()) {
|
|
return false;
|
|
}
|
|
if (point.x <= 0) {
|
|
return false;
|
|
}
|
|
if (point.z >= GetMapMeta()->map_height()) {
|
|
return false;
|
|
}
|
|
if (point.z <= 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
unsigned short MapInstance::GetMoveIncludeFlags()
|
|
{
|
|
return 0xffff;
|
|
}
|
|
|
|
unsigned short MapInstance::GetMoveExcludeFlags()
|
|
{
|
|
return SAMPLE_POLYFLAGS_HOP;
|
|
}
|
|
|
|
unsigned short MapInstance::GetBulletIncludeFlags()
|
|
{
|
|
return 0xffff;
|
|
}
|
|
|
|
unsigned short MapInstance::GetBulletExcludeFlags()
|
|
{
|
|
return 0;
|
|
}
|