mirror of
https://github.com/ncblakely/GiantsTools
synced 2024-11-22 22:25:37 +01:00
Compare commits
4 Commits
ac7a8eb4ba
...
7874502ca2
Author | SHA1 | Date | |
---|---|---|---|
|
7874502ca2 | ||
|
312774c745 | ||
|
8454b0df87 | ||
|
382d67f7b1 |
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "External/recastnavigation"]
|
||||
path = External/recastnavigation
|
||||
url = https://github.com/recastnavigation/recastnavigation.git
|
1
External/recastnavigation
vendored
Submodule
1
External/recastnavigation
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c32297c2f9532a55a11c00f22ec763d771d3dae5
|
@ -25,6 +25,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{0801
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imp_gbs", "Plugins\imp_gbs\imp_gbs.vcxproj", "{448F061E-AE05-4E06-84A1-C95660FD048C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Giants.Services.Tests", "Giants.Services.Tests\Giants.Services.Tests.csproj", "{2AFB71CA-8313-472E-B242-0517343764B4}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ServerConsole", "ServerConsoleExample\ServerConsole.vcxproj", "{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NavMeshGenerator", "NavMeshGenerator\NavMeshGenerator.vcxproj", "{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -277,6 +283,74 @@ Global
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.ReleaseBeta|x64.Build.0 = Release|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.ReleaseBeta|x86.ActiveCfg = Release|Win32
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.ReleaseBeta|x86.Build.0 = Release|Win32
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|x64.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|x64.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|x86.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|x86.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|Any CPU.Build.0 = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|x64.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|x64.Build.0 = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|x86.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|x86.Build.0 = Release|Any CPU
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|x64.Build.0 = Debug|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|x86.Build.0 = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|Any CPU.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|Any CPU.Build.0 = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|x64.ActiveCfg = Debug|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|x64.Build.0 = Debug|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|x86.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|x86.Build.0 = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|x64.ActiveCfg = Release|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|x64.Build.0 = Release|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|x86.ActiveCfg = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|x86.Build.0 = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|Any CPU.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|Any CPU.Build.0 = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|x64.ActiveCfg = Release|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|x64.Build.0 = Release|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|x86.ActiveCfg = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|x86.Build.0 = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|Any CPU.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|x64.ActiveCfg = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|x64.Build.0 = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|x86.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|x86.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x64.Build.0 = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x86.Build.0 = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|Any CPU.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|x64.ActiveCfg = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|x64.Build.0 = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|x86.ActiveCfg = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
315
NavMeshGenerator/Framework/ChunkyTriMesh.cpp
Normal file
315
NavMeshGenerator/Framework/ChunkyTriMesh.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
//
|
||||
// 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 "ChunkyTriMesh.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
struct BoundsItem
|
||||
{
|
||||
float bmin[2];
|
||||
float bmax[2];
|
||||
int i;
|
||||
};
|
||||
|
||||
static int compareItemX(const void* va, const void* vb)
|
||||
{
|
||||
const BoundsItem* a = (const BoundsItem*)va;
|
||||
const BoundsItem* b = (const BoundsItem*)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 BoundsItem* a = (const BoundsItem*)va;
|
||||
const BoundsItem* b = (const BoundsItem*)vb;
|
||||
if (a->bmin[1] < b->bmin[1])
|
||||
return -1;
|
||||
if (a->bmin[1] > b->bmin[1])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void calcExtends(const BoundsItem* items, const int /*nitems*/,
|
||||
const int imin, const int imax,
|
||||
float* bmin, float* bmax)
|
||||
{
|
||||
bmin[0] = items[imin].bmin[0];
|
||||
bmin[1] = items[imin].bmin[1];
|
||||
|
||||
bmax[0] = items[imin].bmax[0];
|
||||
bmax[1] = items[imin].bmax[1];
|
||||
|
||||
for (int i = imin+1; i < imax; ++i)
|
||||
{
|
||||
const BoundsItem& 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.bmax[0] > bmax[0]) bmax[0] = it.bmax[0];
|
||||
if (it.bmax[1] > bmax[1]) bmax[1] = it.bmax[1];
|
||||
}
|
||||
}
|
||||
|
||||
inline int longestAxis(float x, float y)
|
||||
{
|
||||
return y > x ? 1 : 0;
|
||||
}
|
||||
|
||||
static void subdivide(BoundsItem* items, int nitems, int imin, int imax, int trisPerChunk,
|
||||
int& curNode, rcChunkyTriMeshNode* nodes, const int maxNodes,
|
||||
int& curTri, int* outTris, const int* inTris)
|
||||
{
|
||||
int inum = imax - imin;
|
||||
int icur = curNode;
|
||||
|
||||
if (curNode >= maxNodes)
|
||||
return;
|
||||
|
||||
rcChunkyTriMeshNode& node = nodes[curNode++];
|
||||
|
||||
if (inum <= trisPerChunk)
|
||||
{
|
||||
// Leaf
|
||||
calcExtends(items, nitems, imin, imax, node.bmin, node.bmax);
|
||||
|
||||
// Copy triangles.
|
||||
node.i = curTri;
|
||||
node.n = inum;
|
||||
|
||||
for (int i = imin; i < imax; ++i)
|
||||
{
|
||||
const int* src = &inTris[items[i].i*3];
|
||||
int* dst = &outTris[curTri*3];
|
||||
curTri++;
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
}
|
||||
}
|
||||
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]);
|
||||
|
||||
if (axis == 0)
|
||||
{
|
||||
// Sort along x-axis
|
||||
qsort(items+imin, static_cast<size_t>(inum), sizeof(BoundsItem), compareItemX);
|
||||
}
|
||||
else if (axis == 1)
|
||||
{
|
||||
// Sort along y-axis
|
||||
qsort(items+imin, static_cast<size_t>(inum), sizeof(BoundsItem), compareItemY);
|
||||
}
|
||||
|
||||
int isplit = imin+inum/2;
|
||||
|
||||
// Left
|
||||
subdivide(items, nitems, imin, isplit, trisPerChunk, curNode, nodes, maxNodes, curTri, outTris, inTris);
|
||||
// Right
|
||||
subdivide(items, nitems, isplit, imax, trisPerChunk, curNode, nodes, maxNodes, curTri, outTris, inTris);
|
||||
|
||||
int iescape = curNode - icur;
|
||||
// Negative index means escape.
|
||||
node.i = -iescape;
|
||||
}
|
||||
}
|
||||
|
||||
bool rcCreateChunkyTriMesh(const float* verts, const int* tris, int ntris,
|
||||
int trisPerChunk, rcChunkyTriMesh* cm)
|
||||
{
|
||||
int nchunks = (ntris + trisPerChunk-1) / trisPerChunk;
|
||||
|
||||
cm->nodes = new rcChunkyTriMeshNode[nchunks*4];
|
||||
if (!cm->nodes)
|
||||
return false;
|
||||
|
||||
cm->tris = new int[ntris*3];
|
||||
if (!cm->tris)
|
||||
return false;
|
||||
|
||||
cm->ntris = ntris;
|
||||
|
||||
// Build tree
|
||||
BoundsItem* items = new BoundsItem[ntris];
|
||||
if (!items)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < ntris; i++)
|
||||
{
|
||||
const int* t = &tris[i*3];
|
||||
BoundsItem& it = items[i];
|
||||
it.i = i;
|
||||
// Calc triangle XZ bounds.
|
||||
it.bmin[0] = it.bmax[0] = verts[t[0]*3+0];
|
||||
it.bmin[1] = it.bmax[1] = verts[t[0]*3+2];
|
||||
for (int j = 1; j < 3; ++j)
|
||||
{
|
||||
const float* v = &verts[t[j]*3];
|
||||
if (v[0] < it.bmin[0]) it.bmin[0] = v[0];
|
||||
if (v[2] < it.bmin[1]) it.bmin[1] = v[2];
|
||||
|
||||
if (v[0] > it.bmax[0]) it.bmax[0] = v[0];
|
||||
if (v[2] > it.bmax[1]) it.bmax[1] = v[2];
|
||||
}
|
||||
}
|
||||
|
||||
int curTri = 0;
|
||||
int curNode = 0;
|
||||
subdivide(items, ntris, 0, ntris, trisPerChunk, curNode, cm->nodes, nchunks*4, curTri, cm->tris, tris);
|
||||
|
||||
delete [] items;
|
||||
|
||||
cm->nnodes = curNode;
|
||||
|
||||
// Calc max tris per node.
|
||||
cm->maxTrisPerChunk = 0;
|
||||
for (int i = 0; i < cm->nnodes; ++i)
|
||||
{
|
||||
rcChunkyTriMeshNode& node = cm->nodes[i];
|
||||
const bool isLeaf = node.i >= 0;
|
||||
if (!isLeaf) continue;
|
||||
if (node.n > cm->maxTrisPerChunk)
|
||||
cm->maxTrisPerChunk = node.n;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
inline bool checkOverlapRect(const float amin[2], const float amax[2],
|
||||
const float bmin[2], const float bmax[2])
|
||||
{
|
||||
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;
|
||||
return overlap;
|
||||
}
|
||||
|
||||
int rcGetChunksOverlappingRect(const rcChunkyTriMesh* cm,
|
||||
float bmin[2], float bmax[2],
|
||||
int* ids, const int maxIds)
|
||||
{
|
||||
// Traverse tree
|
||||
int i = 0;
|
||||
int n = 0;
|
||||
while (i < cm->nnodes)
|
||||
{
|
||||
const rcChunkyTriMeshNode* node = &cm->nodes[i];
|
||||
const bool overlap = checkOverlapRect(bmin, bmax, node->bmin, node->bmax);
|
||||
const bool isLeafNode = node->i >= 0;
|
||||
|
||||
if (isLeafNode && overlap)
|
||||
{
|
||||
if (n < maxIds)
|
||||
{
|
||||
ids[n] = i;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if (overlap || isLeafNode)
|
||||
i++;
|
||||
else
|
||||
{
|
||||
const int escapeIndex = -node->i;
|
||||
i += escapeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool checkOverlapSegment(const float p[2], const float q[2],
|
||||
const float bmin[2], const float bmax[2])
|
||||
{
|
||||
static const float EPSILON = 1e-6f;
|
||||
|
||||
float tmin = 0;
|
||||
float tmax = 1;
|
||||
float d[2];
|
||||
d[0] = q[0] - p[0];
|
||||
d[1] = q[1] - p[1];
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (fabsf(d[i]) < EPSILON)
|
||||
{
|
||||
// Ray is parallel to slab. No hit if origin not within slab
|
||||
if (p[i] < bmin[i] || p[i] > bmax[i])
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compute intersection t value of ray with near and far plane of slab
|
||||
float ood = 1.0f / d[i];
|
||||
float t1 = (bmin[i] - p[i]) * ood;
|
||||
float t2 = (bmax[i] - p[i]) * ood;
|
||||
if (t1 > t2) { float tmp = t1; t1 = t2; t2 = tmp; }
|
||||
if (t1 > tmin) tmin = t1;
|
||||
if (t2 < tmax) tmax = t2;
|
||||
if (tmin > tmax) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int rcGetChunksOverlappingSegment(const rcChunkyTriMesh* cm,
|
||||
float p[2], float q[2],
|
||||
int* ids, const int maxIds)
|
||||
{
|
||||
// Traverse tree
|
||||
int i = 0;
|
||||
int n = 0;
|
||||
while (i < cm->nnodes)
|
||||
{
|
||||
const rcChunkyTriMeshNode* node = &cm->nodes[i];
|
||||
const bool overlap = checkOverlapSegment(p, q, node->bmin, node->bmax);
|
||||
const bool isLeafNode = node->i >= 0;
|
||||
|
||||
if (isLeafNode && overlap)
|
||||
{
|
||||
if (n < maxIds)
|
||||
{
|
||||
ids[n] = i;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if (overlap || isLeafNode)
|
||||
i++;
|
||||
else
|
||||
{
|
||||
const int escapeIndex = -node->i;
|
||||
i += escapeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
59
NavMeshGenerator/Framework/ChunkyTriMesh.h
Normal file
59
NavMeshGenerator/Framework/ChunkyTriMesh.h
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// 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 CHUNKYTRIMESH_H
|
||||
#define CHUNKYTRIMESH_H
|
||||
|
||||
struct rcChunkyTriMeshNode
|
||||
{
|
||||
float bmin[2];
|
||||
float bmax[2];
|
||||
int i;
|
||||
int n;
|
||||
};
|
||||
|
||||
struct rcChunkyTriMesh
|
||||
{
|
||||
inline rcChunkyTriMesh() : nodes(0), nnodes(0), tris(0), ntris(0), maxTrisPerChunk(0) {};
|
||||
inline ~rcChunkyTriMesh() { delete [] nodes; delete [] tris; }
|
||||
|
||||
rcChunkyTriMeshNode* nodes;
|
||||
int nnodes;
|
||||
int* tris;
|
||||
int ntris;
|
||||
int maxTrisPerChunk;
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
rcChunkyTriMesh(const rcChunkyTriMesh&);
|
||||
rcChunkyTriMesh& operator=(const rcChunkyTriMesh&);
|
||||
};
|
||||
|
||||
/// Creates partitioned triangle mesh (AABB tree),
|
||||
/// where each node contains at max trisPerChunk triangles.
|
||||
bool rcCreateChunkyTriMesh(const float* verts, const int* tris, int ntris,
|
||||
int trisPerChunk, rcChunkyTriMesh* cm);
|
||||
|
||||
/// Returns the chunk indices which overlap the input rectable.
|
||||
int rcGetChunksOverlappingRect(const rcChunkyTriMesh* cm, float bmin[2], float bmax[2], int* ids, const int maxIds);
|
||||
|
||||
/// Returns the chunk indices which overlap the input segment.
|
||||
int rcGetChunksOverlappingSegment(const rcChunkyTriMesh* cm, float p[2], float q[2], int* ids, const int maxIds);
|
||||
|
||||
|
||||
#endif // CHUNKYTRIMESH_H
|
614
NavMeshGenerator/Framework/InputGeom.cpp
Normal file
614
NavMeshGenerator/Framework/InputGeom.cpp
Normal file
@ -0,0 +1,614 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include "Recast.h"
|
||||
#include "InputGeom.h"
|
||||
#include "ChunkyTriMesh.h"
|
||||
#include "MeshLoaderObj.h"
|
||||
#include "DebugDraw.h"
|
||||
#include "RecastDebugDraw.h"
|
||||
#include "DetourNavMesh.h"
|
||||
#include "Sample.h"
|
||||
|
||||
static bool intersectSegmentTriangle(const float* sp, const float* sq,
|
||||
const float* a, const float* b, const float* c,
|
||||
float &t)
|
||||
{
|
||||
float v, w;
|
||||
float ab[3], ac[3], qp[3], ap[3], norm[3], e[3];
|
||||
rcVsub(ab, b, a);
|
||||
rcVsub(ac, c, a);
|
||||
rcVsub(qp, sp, sq);
|
||||
|
||||
// Compute triangle normal. Can be precalculated or cached if
|
||||
// intersecting multiple segments against the same triangle
|
||||
rcVcross(norm, ab, ac);
|
||||
|
||||
// Compute denominator d. If d <= 0, segment is parallel to or points
|
||||
// away from triangle, so exit early
|
||||
float d = rcVdot(qp, norm);
|
||||
if (d <= 0.0f) return false;
|
||||
|
||||
// Compute intersection t value of pq with plane of triangle. A ray
|
||||
// intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay
|
||||
// dividing by d until intersection has been found to pierce triangle
|
||||
rcVsub(ap, sp, a);
|
||||
t = rcVdot(ap, norm);
|
||||
if (t < 0.0f) return false;
|
||||
if (t > d) return false; // For segment; exclude this code line for a ray test
|
||||
|
||||
// Compute barycentric coordinate components and test if within bounds
|
||||
rcVcross(e, qp, ap);
|
||||
v = rcVdot(ac, e);
|
||||
if (v < 0.0f || v > d) return false;
|
||||
w = -rcVdot(ab, e);
|
||||
if (w < 0.0f || v + w > d) return false;
|
||||
|
||||
// Segment/ray intersects triangle. Perform delayed division
|
||||
t /= d;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static char* parseRow(char* buf, char* bufEnd, char* row, int len)
|
||||
{
|
||||
bool start = true;
|
||||
bool done = false;
|
||||
int n = 0;
|
||||
while (!done && buf < bufEnd)
|
||||
{
|
||||
char c = *buf;
|
||||
buf++;
|
||||
// multirow
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
if (start) break;
|
||||
done = true;
|
||||
break;
|
||||
case '\r':
|
||||
break;
|
||||
case '\t':
|
||||
case ' ':
|
||||
if (start) break;
|
||||
// else falls through
|
||||
default:
|
||||
start = false;
|
||||
row[n++] = c;
|
||||
if (n >= len-1)
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
row[n] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
InputGeom::InputGeom() :
|
||||
m_chunkyMesh(0),
|
||||
m_mesh(0),
|
||||
m_hasBuildSettings(false),
|
||||
m_offMeshConCount(0),
|
||||
m_volumeCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
InputGeom::~InputGeom()
|
||||
{
|
||||
delete m_chunkyMesh;
|
||||
delete m_mesh;
|
||||
}
|
||||
|
||||
bool InputGeom::loadMesh(rcContext* ctx, const std::string& filepath)
|
||||
{
|
||||
if (m_mesh)
|
||||
{
|
||||
delete m_chunkyMesh;
|
||||
m_chunkyMesh = 0;
|
||||
delete m_mesh;
|
||||
m_mesh = 0;
|
||||
}
|
||||
m_offMeshConCount = 0;
|
||||
m_volumeCount = 0;
|
||||
|
||||
m_mesh = new rcMeshLoaderObj;
|
||||
if (!m_mesh)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "loadMesh: Out of memory 'm_mesh'.");
|
||||
return false;
|
||||
}
|
||||
if (!m_mesh->load(filepath))
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
rcCalcBounds(m_mesh->getVerts(), m_mesh->getVertCount(), m_meshBMin, m_meshBMax);
|
||||
|
||||
m_chunkyMesh = new rcChunkyTriMesh;
|
||||
if (!m_chunkyMesh)
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Out of memory 'm_chunkyMesh'.");
|
||||
return false;
|
||||
}
|
||||
if (!rcCreateChunkyTriMesh(m_mesh->getVerts(), m_mesh->getTris(), m_mesh->getTriCount(), 256, m_chunkyMesh))
|
||||
{
|
||||
ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Failed to build chunky mesh.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputGeom::loadGeomSet(rcContext* ctx, const std::string& filepath)
|
||||
{
|
||||
char* buf = 0;
|
||||
FILE* fp = fopen(filepath.c_str(), "rb");
|
||||
if (!fp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (fseek(fp, 0, SEEK_END) != 0)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
long bufSize = ftell(fp);
|
||||
if (bufSize < 0)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
if (fseek(fp, 0, SEEK_SET) != 0)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
buf = new char[bufSize];
|
||||
if (!buf)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
size_t readLen = fread(buf, bufSize, 1, fp);
|
||||
fclose(fp);
|
||||
if (readLen != 1)
|
||||
{
|
||||
delete[] buf;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_offMeshConCount = 0;
|
||||
m_volumeCount = 0;
|
||||
delete m_mesh;
|
||||
m_mesh = 0;
|
||||
|
||||
char* src = buf;
|
||||
char* srcEnd = buf + bufSize;
|
||||
char row[512];
|
||||
while (src < srcEnd)
|
||||
{
|
||||
// Parse one row
|
||||
row[0] = '\0';
|
||||
src = parseRow(src, srcEnd, row, sizeof(row)/sizeof(char));
|
||||
if (row[0] == 'f')
|
||||
{
|
||||
// File name.
|
||||
const char* name = row+1;
|
||||
// Skip white spaces
|
||||
while (*name && isspace(*name))
|
||||
name++;
|
||||
if (*name)
|
||||
{
|
||||
if (!loadMesh(ctx, name))
|
||||
{
|
||||
delete [] buf;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (row[0] == 'c')
|
||||
{
|
||||
// Off-mesh connection
|
||||
if (m_offMeshConCount < MAX_OFFMESH_CONNECTIONS)
|
||||
{
|
||||
float* v = &m_offMeshConVerts[m_offMeshConCount*3*2];
|
||||
int bidir, area = 0, flags = 0;
|
||||
float rad;
|
||||
sscanf(row+1, "%f %f %f %f %f %f %f %d %d %d",
|
||||
&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &rad, &bidir, &area, &flags);
|
||||
m_offMeshConRads[m_offMeshConCount] = rad;
|
||||
m_offMeshConDirs[m_offMeshConCount] = (unsigned char)bidir;
|
||||
m_offMeshConAreas[m_offMeshConCount] = (unsigned char)area;
|
||||
m_offMeshConFlags[m_offMeshConCount] = (unsigned short)flags;
|
||||
m_offMeshConCount++;
|
||||
}
|
||||
}
|
||||
else if (row[0] == 'v')
|
||||
{
|
||||
// Convex volumes
|
||||
if (m_volumeCount < MAX_VOLUMES)
|
||||
{
|
||||
ConvexVolume* vol = &m_volumes[m_volumeCount++];
|
||||
sscanf(row+1, "%d %d %f %f", &vol->nverts, &vol->area, &vol->hmin, &vol->hmax);
|
||||
for (int i = 0; i < vol->nverts; ++i)
|
||||
{
|
||||
row[0] = '\0';
|
||||
src = parseRow(src, srcEnd, row, sizeof(row)/sizeof(char));
|
||||
sscanf(row, "%f %f %f", &vol->verts[i*3+0], &vol->verts[i*3+1], &vol->verts[i*3+2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (row[0] == 's')
|
||||
{
|
||||
// Settings
|
||||
m_hasBuildSettings = true;
|
||||
sscanf(row + 1, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d %f %f %f %f %f %f %f",
|
||||
&m_buildSettings.cellSize,
|
||||
&m_buildSettings.cellHeight,
|
||||
&m_buildSettings.agentHeight,
|
||||
&m_buildSettings.agentRadius,
|
||||
&m_buildSettings.agentMaxClimb,
|
||||
&m_buildSettings.agentMaxSlope,
|
||||
&m_buildSettings.regionMinSize,
|
||||
&m_buildSettings.regionMergeSize,
|
||||
&m_buildSettings.edgeMaxLen,
|
||||
&m_buildSettings.edgeMaxError,
|
||||
&m_buildSettings.vertsPerPoly,
|
||||
&m_buildSettings.detailSampleDist,
|
||||
&m_buildSettings.detailSampleMaxError,
|
||||
&m_buildSettings.partitionType,
|
||||
&m_buildSettings.navMeshBMin[0],
|
||||
&m_buildSettings.navMeshBMin[1],
|
||||
&m_buildSettings.navMeshBMin[2],
|
||||
&m_buildSettings.navMeshBMax[0],
|
||||
&m_buildSettings.navMeshBMax[1],
|
||||
&m_buildSettings.navMeshBMax[2],
|
||||
&m_buildSettings.tileSize);
|
||||
}
|
||||
}
|
||||
|
||||
delete [] buf;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputGeom::load(rcContext* ctx, const std::string& filepath)
|
||||
{
|
||||
size_t extensionPos = filepath.find_last_of('.');
|
||||
if (extensionPos == std::string::npos)
|
||||
return false;
|
||||
|
||||
std::string extension = filepath.substr(extensionPos);
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), tolower);
|
||||
|
||||
if (extension == ".gset")
|
||||
return loadGeomSet(ctx, filepath);
|
||||
if (extension == ".obj")
|
||||
return loadMesh(ctx, filepath);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InputGeom::saveGeomSet(const BuildSettings* settings)
|
||||
{
|
||||
if (!m_mesh) return false;
|
||||
|
||||
// Change extension
|
||||
std::string filepath = m_mesh->getFileName();
|
||||
size_t extPos = filepath.find_last_of('.');
|
||||
if (extPos != std::string::npos)
|
||||
filepath = filepath.substr(0, extPos);
|
||||
|
||||
filepath += ".gset";
|
||||
|
||||
FILE* fp = fopen(filepath.c_str(), "w");
|
||||
if (!fp) return false;
|
||||
|
||||
// Store mesh filename.
|
||||
fprintf(fp, "f %s\n", m_mesh->getFileName().c_str());
|
||||
|
||||
// Store settings if any
|
||||
if (settings)
|
||||
{
|
||||
fprintf(fp,
|
||||
"s %f %f %f %f %f %f %f %f %f %f %f %f %f %d %f %f %f %f %f %f %f\n",
|
||||
settings->cellSize,
|
||||
settings->cellHeight,
|
||||
settings->agentHeight,
|
||||
settings->agentRadius,
|
||||
settings->agentMaxClimb,
|
||||
settings->agentMaxSlope,
|
||||
settings->regionMinSize,
|
||||
settings->regionMergeSize,
|
||||
settings->edgeMaxLen,
|
||||
settings->edgeMaxError,
|
||||
settings->vertsPerPoly,
|
||||
settings->detailSampleDist,
|
||||
settings->detailSampleMaxError,
|
||||
settings->partitionType,
|
||||
settings->navMeshBMin[0],
|
||||
settings->navMeshBMin[1],
|
||||
settings->navMeshBMin[2],
|
||||
settings->navMeshBMax[0],
|
||||
settings->navMeshBMax[1],
|
||||
settings->navMeshBMax[2],
|
||||
settings->tileSize);
|
||||
}
|
||||
|
||||
// Store off-mesh links.
|
||||
for (int i = 0; i < m_offMeshConCount; ++i)
|
||||
{
|
||||
const float* v = &m_offMeshConVerts[i*3*2];
|
||||
const float rad = m_offMeshConRads[i];
|
||||
const int bidir = m_offMeshConDirs[i];
|
||||
const int area = m_offMeshConAreas[i];
|
||||
const int flags = m_offMeshConFlags[i];
|
||||
fprintf(fp, "c %f %f %f %f %f %f %f %d %d %d\n",
|
||||
v[0], v[1], v[2], v[3], v[4], v[5], rad, bidir, area, flags);
|
||||
}
|
||||
|
||||
// Convex volumes
|
||||
for (int i = 0; i < m_volumeCount; ++i)
|
||||
{
|
||||
ConvexVolume* vol = &m_volumes[i];
|
||||
fprintf(fp, "v %d %d %f %f\n", vol->nverts, vol->area, vol->hmin, vol->hmax);
|
||||
for (int j = 0; j < vol->nverts; ++j)
|
||||
fprintf(fp, "%f %f %f\n", vol->verts[j*3+0], vol->verts[j*3+1], vol->verts[j*3+2]);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isectSegAABB(const float* sp, const float* sq,
|
||||
const float* amin, const float* amax,
|
||||
float& tmin, float& tmax)
|
||||
{
|
||||
static const float EPS = 1e-6f;
|
||||
|
||||
float d[3];
|
||||
d[0] = sq[0] - sp[0];
|
||||
d[1] = sq[1] - sp[1];
|
||||
d[2] = sq[2] - sp[2];
|
||||
tmin = 0.0;
|
||||
tmax = 1.0f;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (fabsf(d[i]) < EPS)
|
||||
{
|
||||
if (sp[i] < amin[i] || sp[i] > amax[i])
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float ood = 1.0f / d[i];
|
||||
float t1 = (amin[i] - sp[i]) * ood;
|
||||
float t2 = (amax[i] - sp[i]) * ood;
|
||||
if (t1 > t2) { float tmp = t1; t1 = t2; t2 = tmp; }
|
||||
if (t1 > tmin) tmin = t1;
|
||||
if (t2 < tmax) tmax = t2;
|
||||
if (tmin > tmax) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool InputGeom::raycastMesh(float* src, float* dst, float& tmin)
|
||||
{
|
||||
// Prune hit ray.
|
||||
float btmin, btmax;
|
||||
if (!isectSegAABB(src, dst, m_meshBMin, m_meshBMax, btmin, btmax))
|
||||
return false;
|
||||
float p[2], q[2];
|
||||
p[0] = src[0] + (dst[0]-src[0])*btmin;
|
||||
p[1] = src[2] + (dst[2]-src[2])*btmin;
|
||||
q[0] = src[0] + (dst[0]-src[0])*btmax;
|
||||
q[1] = src[2] + (dst[2]-src[2])*btmax;
|
||||
|
||||
int cid[512];
|
||||
const int ncid = rcGetChunksOverlappingSegment(m_chunkyMesh, p, q, cid, 512);
|
||||
if (!ncid)
|
||||
return false;
|
||||
|
||||
tmin = 1.0f;
|
||||
bool hit = false;
|
||||
const float* verts = m_mesh->getVerts();
|
||||
|
||||
for (int i = 0; i < ncid; ++i)
|
||||
{
|
||||
const rcChunkyTriMeshNode& node = m_chunkyMesh->nodes[cid[i]];
|
||||
const int* tris = &m_chunkyMesh->tris[node.i*3];
|
||||
const int ntris = node.n;
|
||||
|
||||
for (int j = 0; j < ntris*3; j += 3)
|
||||
{
|
||||
float t = 1;
|
||||
if (intersectSegmentTriangle(src, dst,
|
||||
&verts[tris[j]*3],
|
||||
&verts[tris[j+1]*3],
|
||||
&verts[tris[j+2]*3], t))
|
||||
{
|
||||
if (t < tmin)
|
||||
tmin = t;
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
void InputGeom::addOffMeshConnection(const float* spos, const float* epos, const float rad,
|
||||
unsigned char bidir, unsigned char area, unsigned short flags)
|
||||
{
|
||||
if (m_offMeshConCount >= MAX_OFFMESH_CONNECTIONS) return;
|
||||
float* v = &m_offMeshConVerts[m_offMeshConCount*3*2];
|
||||
m_offMeshConRads[m_offMeshConCount] = rad;
|
||||
m_offMeshConDirs[m_offMeshConCount] = bidir;
|
||||
m_offMeshConAreas[m_offMeshConCount] = area;
|
||||
m_offMeshConFlags[m_offMeshConCount] = flags;
|
||||
m_offMeshConId[m_offMeshConCount] = 1000 + m_offMeshConCount;
|
||||
rcVcopy(&v[0], spos);
|
||||
rcVcopy(&v[3], epos);
|
||||
m_offMeshConCount++;
|
||||
}
|
||||
|
||||
void InputGeom::deleteOffMeshConnection(int i)
|
||||
{
|
||||
m_offMeshConCount--;
|
||||
float* src = &m_offMeshConVerts[m_offMeshConCount*3*2];
|
||||
float* dst = &m_offMeshConVerts[i*3*2];
|
||||
rcVcopy(&dst[0], &src[0]);
|
||||
rcVcopy(&dst[3], &src[3]);
|
||||
m_offMeshConRads[i] = m_offMeshConRads[m_offMeshConCount];
|
||||
m_offMeshConDirs[i] = m_offMeshConDirs[m_offMeshConCount];
|
||||
m_offMeshConAreas[i] = m_offMeshConAreas[m_offMeshConCount];
|
||||
m_offMeshConFlags[i] = m_offMeshConFlags[m_offMeshConCount];
|
||||
}
|
||||
|
||||
void InputGeom::drawOffMeshConnections(duDebugDraw* dd, bool hilight)
|
||||
{
|
||||
unsigned int conColor = duRGBA(192,0,128,192);
|
||||
unsigned int baseColor = duRGBA(0,0,0,64);
|
||||
dd->depthMask(false);
|
||||
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
for (int i = 0; i < m_offMeshConCount; ++i)
|
||||
{
|
||||
float* v = &m_offMeshConVerts[i*3*2];
|
||||
|
||||
dd->vertex(v[0],v[1],v[2], baseColor);
|
||||
dd->vertex(v[0],v[1]+0.2f,v[2], baseColor);
|
||||
|
||||
dd->vertex(v[3],v[4],v[5], baseColor);
|
||||
dd->vertex(v[3],v[4]+0.2f,v[5], baseColor);
|
||||
|
||||
duAppendCircle(dd, v[0],v[1]+0.1f,v[2], m_offMeshConRads[i], baseColor);
|
||||
duAppendCircle(dd, v[3],v[4]+0.1f,v[5], m_offMeshConRads[i], baseColor);
|
||||
|
||||
if (hilight)
|
||||
{
|
||||
duAppendArc(dd, v[0],v[1],v[2], v[3],v[4],v[5], 0.25f,
|
||||
(m_offMeshConDirs[i]&1) ? 0.6f : 0.0f, 0.6f, conColor);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
dd->depthMask(true);
|
||||
}
|
||||
|
||||
void InputGeom::addConvexVolume(const float* verts, const int nverts,
|
||||
const float minh, const float maxh, unsigned char area)
|
||||
{
|
||||
if (m_volumeCount >= MAX_VOLUMES) return;
|
||||
ConvexVolume* vol = &m_volumes[m_volumeCount++];
|
||||
memset(vol, 0, sizeof(ConvexVolume));
|
||||
memcpy(vol->verts, verts, sizeof(float)*3*nverts);
|
||||
vol->hmin = minh;
|
||||
vol->hmax = maxh;
|
||||
vol->nverts = nverts;
|
||||
vol->area = area;
|
||||
}
|
||||
|
||||
void InputGeom::deleteConvexVolume(int i)
|
||||
{
|
||||
m_volumeCount--;
|
||||
m_volumes[i] = m_volumes[m_volumeCount];
|
||||
}
|
||||
|
||||
void InputGeom::drawConvexVolumes(struct duDebugDraw* dd, bool /*hilight*/)
|
||||
{
|
||||
dd->depthMask(false);
|
||||
|
||||
dd->begin(DU_DRAW_TRIS);
|
||||
|
||||
for (int i = 0; i < m_volumeCount; ++i)
|
||||
{
|
||||
const ConvexVolume* vol = &m_volumes[i];
|
||||
unsigned int col = duTransCol(dd->areaToCol(vol->area), 32);
|
||||
for (int j = 0, k = vol->nverts-1; j < vol->nverts; k = j++)
|
||||
{
|
||||
const float* va = &vol->verts[k*3];
|
||||
const float* vb = &vol->verts[j*3];
|
||||
|
||||
dd->vertex(vol->verts[0],vol->hmax,vol->verts[2], col);
|
||||
dd->vertex(vb[0],vol->hmax,vb[2], col);
|
||||
dd->vertex(va[0],vol->hmax,va[2], col);
|
||||
|
||||
dd->vertex(va[0],vol->hmin,va[2], duDarkenCol(col));
|
||||
dd->vertex(va[0],vol->hmax,va[2], col);
|
||||
dd->vertex(vb[0],vol->hmax,vb[2], col);
|
||||
|
||||
dd->vertex(va[0],vol->hmin,va[2], duDarkenCol(col));
|
||||
dd->vertex(vb[0],vol->hmax,vb[2], col);
|
||||
dd->vertex(vb[0],vol->hmin,vb[2], duDarkenCol(col));
|
||||
}
|
||||
}
|
||||
|
||||
dd->end();
|
||||
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
for (int i = 0; i < m_volumeCount; ++i)
|
||||
{
|
||||
const ConvexVolume* vol = &m_volumes[i];
|
||||
unsigned int col = duTransCol(dd->areaToCol(vol->area), 220);
|
||||
for (int j = 0, k = vol->nverts-1; j < vol->nverts; k = j++)
|
||||
{
|
||||
const float* va = &vol->verts[k*3];
|
||||
const float* vb = &vol->verts[j*3];
|
||||
dd->vertex(va[0],vol->hmin,va[2], duDarkenCol(col));
|
||||
dd->vertex(vb[0],vol->hmin,vb[2], duDarkenCol(col));
|
||||
dd->vertex(va[0],vol->hmax,va[2], col);
|
||||
dd->vertex(vb[0],vol->hmax,vb[2], col);
|
||||
dd->vertex(va[0],vol->hmin,va[2], duDarkenCol(col));
|
||||
dd->vertex(va[0],vol->hmax,va[2], col);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
dd->begin(DU_DRAW_POINTS, 3.0f);
|
||||
for (int i = 0; i < m_volumeCount; ++i)
|
||||
{
|
||||
const ConvexVolume* vol = &m_volumes[i];
|
||||
unsigned int col = duDarkenCol(duTransCol(dd->areaToCol(vol->area), 220));
|
||||
for (int j = 0; j < vol->nverts; ++j)
|
||||
{
|
||||
dd->vertex(vol->verts[j*3+0],vol->verts[j*3+1]+0.1f,vol->verts[j*3+2], col);
|
||||
dd->vertex(vol->verts[j*3+0],vol->hmin,vol->verts[j*3+2], col);
|
||||
dd->vertex(vol->verts[j*3+0],vol->hmax,vol->verts[j*3+2], col);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
|
||||
dd->depthMask(true);
|
||||
}
|
150
NavMeshGenerator/Framework/InputGeom.h
Normal file
150
NavMeshGenerator/Framework/InputGeom.h
Normal file
@ -0,0 +1,150 @@
|
||||
//
|
||||
// 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 INPUTGEOM_H
|
||||
#define INPUTGEOM_H
|
||||
|
||||
#include "ChunkyTriMesh.h"
|
||||
#include "MeshLoaderObj.h"
|
||||
|
||||
static const int MAX_CONVEXVOL_PTS = 12;
|
||||
struct ConvexVolume
|
||||
{
|
||||
float verts[MAX_CONVEXVOL_PTS*3];
|
||||
float hmin, hmax;
|
||||
int nverts;
|
||||
int area;
|
||||
};
|
||||
|
||||
struct BuildSettings
|
||||
{
|
||||
// Cell size in world units
|
||||
float cellSize;
|
||||
// Cell height in world units
|
||||
float cellHeight;
|
||||
// Agent height in world units
|
||||
float agentHeight;
|
||||
// Agent radius in world units
|
||||
float agentRadius;
|
||||
// Agent max climb in world units
|
||||
float agentMaxClimb;
|
||||
// Agent max slope in degrees
|
||||
float agentMaxSlope;
|
||||
// Region minimum size in voxels.
|
||||
// regionMinSize = sqrt(regionMinArea)
|
||||
float regionMinSize;
|
||||
// Region merge size in voxels.
|
||||
// regionMergeSize = sqrt(regionMergeArea)
|
||||
float regionMergeSize;
|
||||
// Edge max length in world units
|
||||
float edgeMaxLen;
|
||||
// Edge max error in voxels
|
||||
float edgeMaxError;
|
||||
float vertsPerPoly;
|
||||
// Detail sample distance in voxels
|
||||
float detailSampleDist;
|
||||
// Detail sample max error in voxel heights.
|
||||
float detailSampleMaxError;
|
||||
// Partition type, see SamplePartitionType
|
||||
int partitionType;
|
||||
// Bounds of the area to mesh
|
||||
float navMeshBMin[3];
|
||||
float navMeshBMax[3];
|
||||
// Size of the tiles in voxels
|
||||
float tileSize;
|
||||
};
|
||||
|
||||
class InputGeom
|
||||
{
|
||||
rcChunkyTriMesh* m_chunkyMesh;
|
||||
rcMeshLoaderObj* m_mesh;
|
||||
float m_meshBMin[3], m_meshBMax[3];
|
||||
BuildSettings m_buildSettings;
|
||||
bool m_hasBuildSettings;
|
||||
|
||||
/// @name Off-Mesh connections.
|
||||
///@{
|
||||
static const int MAX_OFFMESH_CONNECTIONS = 256;
|
||||
float m_offMeshConVerts[MAX_OFFMESH_CONNECTIONS*3*2];
|
||||
float m_offMeshConRads[MAX_OFFMESH_CONNECTIONS];
|
||||
unsigned char m_offMeshConDirs[MAX_OFFMESH_CONNECTIONS];
|
||||
unsigned char m_offMeshConAreas[MAX_OFFMESH_CONNECTIONS];
|
||||
unsigned short m_offMeshConFlags[MAX_OFFMESH_CONNECTIONS];
|
||||
unsigned int m_offMeshConId[MAX_OFFMESH_CONNECTIONS];
|
||||
int m_offMeshConCount;
|
||||
///@}
|
||||
|
||||
/// @name Convex Volumes.
|
||||
///@{
|
||||
static const int MAX_VOLUMES = 256;
|
||||
ConvexVolume m_volumes[MAX_VOLUMES];
|
||||
int m_volumeCount;
|
||||
///@}
|
||||
|
||||
bool loadMesh(class rcContext* ctx, const std::string& filepath);
|
||||
bool loadGeomSet(class rcContext* ctx, const std::string& filepath);
|
||||
public:
|
||||
InputGeom();
|
||||
~InputGeom();
|
||||
|
||||
|
||||
bool load(class rcContext* ctx, const std::string& filepath);
|
||||
bool saveGeomSet(const BuildSettings* settings);
|
||||
|
||||
/// Method to return static mesh data.
|
||||
const rcMeshLoaderObj* getMesh() const { return m_mesh; }
|
||||
const float* getMeshBoundsMin() const { return m_meshBMin; }
|
||||
const float* getMeshBoundsMax() const { return m_meshBMax; }
|
||||
const float* getNavMeshBoundsMin() const { return m_hasBuildSettings ? m_buildSettings.navMeshBMin : m_meshBMin; }
|
||||
const float* getNavMeshBoundsMax() const { return m_hasBuildSettings ? m_buildSettings.navMeshBMax : m_meshBMax; }
|
||||
const rcChunkyTriMesh* getChunkyMesh() const { return m_chunkyMesh; }
|
||||
const BuildSettings* getBuildSettings() const { return m_hasBuildSettings ? &m_buildSettings : 0; }
|
||||
bool raycastMesh(float* src, float* dst, float& tmin);
|
||||
|
||||
/// @name Off-Mesh connections.
|
||||
///@{
|
||||
int getOffMeshConnectionCount() const { return m_offMeshConCount; }
|
||||
const float* getOffMeshConnectionVerts() const { return m_offMeshConVerts; }
|
||||
const float* getOffMeshConnectionRads() const { return m_offMeshConRads; }
|
||||
const unsigned char* getOffMeshConnectionDirs() const { return m_offMeshConDirs; }
|
||||
const unsigned char* getOffMeshConnectionAreas() const { return m_offMeshConAreas; }
|
||||
const unsigned short* getOffMeshConnectionFlags() const { return m_offMeshConFlags; }
|
||||
const unsigned int* getOffMeshConnectionId() const { return m_offMeshConId; }
|
||||
void addOffMeshConnection(const float* spos, const float* epos, const float rad,
|
||||
unsigned char bidir, unsigned char area, unsigned short flags);
|
||||
void deleteOffMeshConnection(int i);
|
||||
void drawOffMeshConnections(struct duDebugDraw* dd, bool hilight = false);
|
||||
///@}
|
||||
|
||||
/// @name Box Volumes.
|
||||
///@{
|
||||
int getConvexVolumeCount() const { return m_volumeCount; }
|
||||
const ConvexVolume* getConvexVolumes() const { return m_volumes; }
|
||||
void addConvexVolume(const float* verts, const int nverts,
|
||||
const float minh, const float maxh, unsigned char area);
|
||||
void deleteConvexVolume(int i);
|
||||
void drawConvexVolumes(struct duDebugDraw* dd, bool hilight = false);
|
||||
///@}
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
InputGeom(const InputGeom&);
|
||||
InputGeom& operator=(const InputGeom&);
|
||||
};
|
||||
|
||||
#endif // INPUTGEOM_H
|
245
NavMeshGenerator/Framework/MeshLoaderObj.cpp
Normal file
245
NavMeshGenerator/Framework/MeshLoaderObj.cpp
Normal file
@ -0,0 +1,245 @@
|
||||
//
|
||||
// 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 "MeshLoaderObj.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstring>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
rcMeshLoaderObj::rcMeshLoaderObj() :
|
||||
m_scale(1.0f),
|
||||
m_verts(0),
|
||||
m_tris(0),
|
||||
m_normals(0),
|
||||
m_vertCount(0),
|
||||
m_triCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
rcMeshLoaderObj::~rcMeshLoaderObj()
|
||||
{
|
||||
delete [] m_verts;
|
||||
delete [] m_normals;
|
||||
delete [] m_tris;
|
||||
}
|
||||
|
||||
void rcMeshLoaderObj::addVertex(float x, float y, float z, int& cap)
|
||||
{
|
||||
if (m_vertCount+1 > cap)
|
||||
{
|
||||
cap = !cap ? 8 : cap*2;
|
||||
float* nv = new float[cap*3];
|
||||
if (m_vertCount)
|
||||
memcpy(nv, m_verts, m_vertCount*3*sizeof(float));
|
||||
delete [] m_verts;
|
||||
m_verts = nv;
|
||||
}
|
||||
float* dst = &m_verts[m_vertCount*3];
|
||||
*dst++ = x*m_scale;
|
||||
*dst++ = y*m_scale;
|
||||
*dst++ = z*m_scale;
|
||||
m_vertCount++;
|
||||
}
|
||||
|
||||
void rcMeshLoaderObj::addTriangle(int a, int b, int c, int& cap)
|
||||
{
|
||||
if (m_triCount+1 > cap)
|
||||
{
|
||||
cap = !cap ? 8 : cap*2;
|
||||
int* nv = new int[cap*3];
|
||||
if (m_triCount)
|
||||
memcpy(nv, m_tris, m_triCount*3*sizeof(int));
|
||||
delete [] m_tris;
|
||||
m_tris = nv;
|
||||
}
|
||||
int* dst = &m_tris[m_triCount*3];
|
||||
*dst++ = a;
|
||||
*dst++ = b;
|
||||
*dst++ = c;
|
||||
m_triCount++;
|
||||
}
|
||||
|
||||
static char* parseRow(char* buf, char* bufEnd, char* row, int len)
|
||||
{
|
||||
bool start = true;
|
||||
bool done = false;
|
||||
int n = 0;
|
||||
while (!done && buf < bufEnd)
|
||||
{
|
||||
char c = *buf;
|
||||
buf++;
|
||||
// multirow
|
||||
switch (c)
|
||||
{
|
||||
case '\\':
|
||||
break;
|
||||
case '\n':
|
||||
if (start) break;
|
||||
done = true;
|
||||
break;
|
||||
case '\r':
|
||||
break;
|
||||
case '\t':
|
||||
case ' ':
|
||||
if (start) break;
|
||||
// else falls through
|
||||
default:
|
||||
start = false;
|
||||
row[n++] = c;
|
||||
if (n >= len-1)
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
row[n] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int parseFace(char* row, int* data, int n, int vcnt)
|
||||
{
|
||||
int j = 0;
|
||||
while (*row != '\0')
|
||||
{
|
||||
// Skip initial white space
|
||||
while (*row != '\0' && (*row == ' ' || *row == '\t'))
|
||||
row++;
|
||||
char* s = row;
|
||||
// Find vertex delimiter and terminated the string there for conversion.
|
||||
while (*row != '\0' && *row != ' ' && *row != '\t')
|
||||
{
|
||||
if (*row == '/') *row = '\0';
|
||||
row++;
|
||||
}
|
||||
if (*s == '\0')
|
||||
continue;
|
||||
int vi = atoi(s);
|
||||
data[j++] = vi < 0 ? vi+vcnt : vi-1;
|
||||
if (j >= n) return j;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
bool rcMeshLoaderObj::load(const std::string& filename)
|
||||
{
|
||||
char* buf = 0;
|
||||
FILE* fp = fopen(filename.c_str(), "rb");
|
||||
if (!fp)
|
||||
return false;
|
||||
if (fseek(fp, 0, SEEK_END) != 0)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
long bufSize = ftell(fp);
|
||||
if (bufSize < 0)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
if (fseek(fp, 0, SEEK_SET) != 0)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
buf = new char[bufSize];
|
||||
if (!buf)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
size_t readLen = fread(buf, bufSize, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
if (readLen != 1)
|
||||
{
|
||||
delete[] buf;
|
||||
return false;
|
||||
}
|
||||
|
||||
char* src = buf;
|
||||
char* srcEnd = buf + bufSize;
|
||||
char row[512];
|
||||
int face[32];
|
||||
float x,y,z;
|
||||
int nv;
|
||||
int vcap = 0;
|
||||
int tcap = 0;
|
||||
|
||||
while (src < srcEnd)
|
||||
{
|
||||
// Parse one row
|
||||
row[0] = '\0';
|
||||
src = parseRow(src, srcEnd, row, sizeof(row)/sizeof(char));
|
||||
// Skip comments
|
||||
if (row[0] == '#') continue;
|
||||
if (row[0] == 'v' && row[1] != 'n' && row[1] != 't')
|
||||
{
|
||||
// Vertex pos
|
||||
sscanf(row+1, "%f %f %f", &x, &y, &z);
|
||||
addVertex(x, y, z, vcap);
|
||||
}
|
||||
if (row[0] == 'f')
|
||||
{
|
||||
// Faces
|
||||
nv = parseFace(row+1, face, 32, m_vertCount);
|
||||
for (int i = 2; i < nv; ++i)
|
||||
{
|
||||
const int a = face[0];
|
||||
const int b = face[i-1];
|
||||
const int c = face[i];
|
||||
if (a < 0 || a >= m_vertCount || b < 0 || b >= m_vertCount || c < 0 || c >= m_vertCount)
|
||||
continue;
|
||||
addTriangle(a, b, c, tcap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] buf;
|
||||
|
||||
// Calculate normals.
|
||||
m_normals = new float[m_triCount*3];
|
||||
for (int i = 0; i < m_triCount*3; i += 3)
|
||||
{
|
||||
const float* v0 = &m_verts[m_tris[i]*3];
|
||||
const float* v1 = &m_verts[m_tris[i+1]*3];
|
||||
const float* v2 = &m_verts[m_tris[i+2]*3];
|
||||
float e0[3], e1[3];
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
e0[j] = v1[j] - v0[j];
|
||||
e1[j] = v2[j] - v0[j];
|
||||
}
|
||||
float* n = &m_normals[i];
|
||||
n[0] = e0[1]*e1[2] - e0[2]*e1[1];
|
||||
n[1] = e0[2]*e1[0] - e0[0]*e1[2];
|
||||
n[2] = e0[0]*e1[1] - e0[1]*e1[0];
|
||||
float d = sqrtf(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
|
||||
if (d > 0)
|
||||
{
|
||||
d = 1.0f/d;
|
||||
n[0] *= d;
|
||||
n[1] *= d;
|
||||
n[2] *= d;
|
||||
}
|
||||
}
|
||||
|
||||
m_filename = filename;
|
||||
return true;
|
||||
}
|
56
NavMeshGenerator/Framework/MeshLoaderObj.h
Normal file
56
NavMeshGenerator/Framework/MeshLoaderObj.h
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 MESHLOADER_OBJ
|
||||
#define MESHLOADER_OBJ
|
||||
|
||||
#include <string>
|
||||
|
||||
class rcMeshLoaderObj
|
||||
{
|
||||
public:
|
||||
rcMeshLoaderObj();
|
||||
~rcMeshLoaderObj();
|
||||
|
||||
bool load(const std::string& fileName);
|
||||
|
||||
const float* getVerts() const { return m_verts; }
|
||||
const float* getNormals() const { return m_normals; }
|
||||
const int* getTris() const { return m_tris; }
|
||||
int getVertCount() const { return m_vertCount; }
|
||||
int getTriCount() const { return m_triCount; }
|
||||
const std::string& getFileName() const { return m_filename; }
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
rcMeshLoaderObj(const rcMeshLoaderObj&);
|
||||
rcMeshLoaderObj& operator=(const rcMeshLoaderObj&);
|
||||
|
||||
void addVertex(float x, float y, float z, int& cap);
|
||||
void addTriangle(int a, int b, int c, int& cap);
|
||||
|
||||
std::string m_filename;
|
||||
float m_scale;
|
||||
float* m_verts;
|
||||
int* m_tris;
|
||||
float* m_normals;
|
||||
int m_vertCount;
|
||||
int m_triCount;
|
||||
};
|
||||
|
||||
#endif // MESHLOADER_OBJ
|
59
NavMeshGenerator/Framework/PerfTimer.cpp
Normal file
59
NavMeshGenerator/Framework/PerfTimer.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// 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 "PerfTimer.h"
|
||||
|
||||
#if defined(WIN32)
|
||||
|
||||
// Win32
|
||||
#include <windows.h>
|
||||
|
||||
TimeVal getPerfTime()
|
||||
{
|
||||
__int64 count;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&count);
|
||||
return count;
|
||||
}
|
||||
|
||||
int getPerfTimeUsec(const TimeVal duration)
|
||||
{
|
||||
static __int64 freq = 0;
|
||||
if (freq == 0)
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
|
||||
return (int)(duration*1000000 / freq);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Linux, BSD, OSX
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
TimeVal getPerfTime()
|
||||
{
|
||||
timeval now;
|
||||
gettimeofday(&now, 0);
|
||||
return (TimeVal)now.tv_sec*1000000L + (TimeVal)now.tv_usec;
|
||||
}
|
||||
|
||||
int getPerfTimeUsec(const TimeVal duration)
|
||||
{
|
||||
return (int)duration;
|
||||
}
|
||||
|
||||
#endif
|
32
NavMeshGenerator/Framework/PerfTimer.h
Normal file
32
NavMeshGenerator/Framework/PerfTimer.h
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// 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 PERFTIMER_H
|
||||
#define PERFTIMER_H
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <stdint.h>
|
||||
typedef int64_t TimeVal;
|
||||
#else
|
||||
typedef __int64 TimeVal;
|
||||
#endif
|
||||
|
||||
TimeVal getPerfTime();
|
||||
int getPerfTimeUsec(const TimeVal duration);
|
||||
|
||||
#endif // PERFTIMER_H
|
190
NavMeshGenerator/Framework/Sample.h
Normal file
190
NavMeshGenerator/Framework/Sample.h
Normal file
@ -0,0 +1,190 @@
|
||||
//
|
||||
// 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 RECASTSAMPLE_H
|
||||
#define RECASTSAMPLE_H
|
||||
|
||||
#include "Recast.h"
|
||||
#include "SampleInterfaces.h"
|
||||
|
||||
|
||||
/// Tool types.
|
||||
enum SampleToolType
|
||||
{
|
||||
TOOL_NONE = 0,
|
||||
TOOL_TILE_EDIT,
|
||||
TOOL_TILE_HIGHLIGHT,
|
||||
TOOL_TEMP_OBSTACLE,
|
||||
TOOL_NAVMESH_TESTER,
|
||||
TOOL_NAVMESH_PRUNE,
|
||||
TOOL_OFFMESH_CONNECTION,
|
||||
TOOL_CONVEX_VOLUME,
|
||||
TOOL_CROWD,
|
||||
MAX_TOOLS
|
||||
};
|
||||
|
||||
/// These are just sample areas to use consistent values across the samples.
|
||||
/// The use should specify these base on his needs.
|
||||
enum SamplePolyAreas
|
||||
{
|
||||
SAMPLE_POLYAREA_GROUND,
|
||||
SAMPLE_POLYAREA_WATER,
|
||||
SAMPLE_POLYAREA_ROAD,
|
||||
SAMPLE_POLYAREA_DOOR,
|
||||
SAMPLE_POLYAREA_GRASS,
|
||||
SAMPLE_POLYAREA_JUMP,
|
||||
};
|
||||
enum SamplePolyFlags
|
||||
{
|
||||
SAMPLE_POLYFLAGS_WALK = 0x01, // Ability to walk (ground, grass, road)
|
||||
SAMPLE_POLYFLAGS_SWIM = 0x02, // Ability to swim (water).
|
||||
SAMPLE_POLYFLAGS_DOOR = 0x04, // Ability to move through doors.
|
||||
SAMPLE_POLYFLAGS_JUMP = 0x08, // Ability to jump.
|
||||
SAMPLE_POLYFLAGS_DISABLED = 0x10, // Disabled polygon
|
||||
SAMPLE_POLYFLAGS_ALL = 0xffff // All abilities.
|
||||
};
|
||||
|
||||
class SampleDebugDraw : public DebugDrawGL
|
||||
{
|
||||
public:
|
||||
virtual unsigned int areaToCol(unsigned int area);
|
||||
};
|
||||
|
||||
enum SamplePartitionType
|
||||
{
|
||||
SAMPLE_PARTITION_WATERSHED,
|
||||
SAMPLE_PARTITION_MONOTONE,
|
||||
SAMPLE_PARTITION_LAYERS,
|
||||
};
|
||||
|
||||
struct SampleTool
|
||||
{
|
||||
virtual ~SampleTool() {}
|
||||
virtual int type() = 0;
|
||||
virtual void init(class Sample* sample) = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual void handleMenu() = 0;
|
||||
virtual void handleClick(const float* s, const float* p, bool shift) = 0;
|
||||
virtual void handleRender() = 0;
|
||||
virtual void handleRenderOverlay(double* proj, double* model, int* view) = 0;
|
||||
virtual void handleToggle() = 0;
|
||||
virtual void handleStep() = 0;
|
||||
virtual void handleUpdate(const float dt) = 0;
|
||||
};
|
||||
|
||||
struct SampleToolState {
|
||||
virtual ~SampleToolState() {}
|
||||
virtual void init(class Sample* sample) = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual void handleRender() = 0;
|
||||
virtual void handleRenderOverlay(double* proj, double* model, int* view) = 0;
|
||||
virtual void handleUpdate(const float dt) = 0;
|
||||
};
|
||||
|
||||
class Sample
|
||||
{
|
||||
protected:
|
||||
class InputGeom* m_geom;
|
||||
class dtNavMesh* m_navMesh;
|
||||
class dtNavMeshQuery* m_navQuery;
|
||||
class dtCrowd* m_crowd;
|
||||
|
||||
unsigned char m_navMeshDrawFlags;
|
||||
|
||||
float m_cellSize;
|
||||
float m_cellHeight;
|
||||
float m_agentHeight;
|
||||
float m_agentRadius;
|
||||
float m_agentMaxClimb;
|
||||
float m_agentMaxSlope;
|
||||
float m_regionMinSize;
|
||||
float m_regionMergeSize;
|
||||
float m_edgeMaxLen;
|
||||
float m_edgeMaxError;
|
||||
float m_vertsPerPoly;
|
||||
float m_detailSampleDist;
|
||||
float m_detailSampleMaxError;
|
||||
int m_partitionType;
|
||||
|
||||
bool m_filterLowHangingObstacles;
|
||||
bool m_filterLedgeSpans;
|
||||
bool m_filterWalkableLowHeightSpans;
|
||||
|
||||
SampleTool* m_tool;
|
||||
SampleToolState* m_toolStates[MAX_TOOLS];
|
||||
|
||||
BuildContext* m_ctx;
|
||||
|
||||
SampleDebugDraw m_dd;
|
||||
|
||||
dtNavMesh* loadAll(const char* path);
|
||||
void saveAll(const char* path, const dtNavMesh* mesh);
|
||||
|
||||
public:
|
||||
Sample();
|
||||
virtual ~Sample();
|
||||
|
||||
void setContext(BuildContext* ctx) { m_ctx = ctx; }
|
||||
|
||||
void setTool(SampleTool* tool);
|
||||
SampleToolState* getToolState(int type) { return m_toolStates[type]; }
|
||||
void setToolState(int type, SampleToolState* s) { m_toolStates[type] = s; }
|
||||
|
||||
SampleDebugDraw& getDebugDraw() { return m_dd; }
|
||||
|
||||
virtual void handleSettings();
|
||||
virtual void handleTools();
|
||||
virtual void handleDebugMode();
|
||||
virtual void handleClick(const float* s, const float* p, bool shift);
|
||||
virtual void handleToggle();
|
||||
virtual void handleStep();
|
||||
virtual void handleRender();
|
||||
virtual void handleRenderOverlay(double* proj, double* model, int* view);
|
||||
virtual void handleMeshChanged(class InputGeom* geom);
|
||||
virtual bool handleBuild();
|
||||
virtual void handleUpdate(const float dt);
|
||||
virtual void collectSettings(struct BuildSettings& settings);
|
||||
|
||||
virtual class InputGeom* getInputGeom() { return m_geom; }
|
||||
virtual class dtNavMesh* getNavMesh() { return m_navMesh; }
|
||||
virtual class dtNavMeshQuery* getNavMeshQuery() { return m_navQuery; }
|
||||
virtual class dtCrowd* getCrowd() { return m_crowd; }
|
||||
virtual float getAgentRadius() { return m_agentRadius; }
|
||||
virtual float getAgentHeight() { return m_agentHeight; }
|
||||
virtual float getAgentClimb() { return m_agentMaxClimb; }
|
||||
|
||||
unsigned char getNavMeshDrawFlags() const { return m_navMeshDrawFlags; }
|
||||
void setNavMeshDrawFlags(unsigned char flags) { m_navMeshDrawFlags = flags; }
|
||||
|
||||
void updateToolStates(const float dt);
|
||||
void initToolStates(Sample* sample);
|
||||
void resetToolStates();
|
||||
void renderToolStates();
|
||||
void renderOverlayToolStates(double* proj, double* model, int* view);
|
||||
|
||||
void resetCommonSettings();
|
||||
void handleCommonSettings();
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
Sample(const Sample&);
|
||||
Sample& operator=(const Sample&);
|
||||
};
|
||||
|
||||
|
||||
#endif // RECASTSAMPLE_H
|
99
NavMeshGenerator/Framework/SampleInterfaces.h
Normal file
99
NavMeshGenerator/Framework/SampleInterfaces.h
Normal file
@ -0,0 +1,99 @@
|
||||
//
|
||||
// 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 SAMPLEINTERFACES_H
|
||||
#define SAMPLEINTERFACES_H
|
||||
|
||||
#include "DebugDraw.h"
|
||||
#include "Recast.h"
|
||||
#include "RecastDump.h"
|
||||
#include "PerfTimer.h"
|
||||
|
||||
// These are example implementations of various interfaces used in Recast and Detour.
|
||||
|
||||
/// Recast build context.
|
||||
class BuildContext : public rcContext
|
||||
{
|
||||
TimeVal m_startTime[RC_MAX_TIMERS];
|
||||
TimeVal m_accTime[RC_MAX_TIMERS];
|
||||
|
||||
static const int MAX_MESSAGES = 1000;
|
||||
const char* m_messages[MAX_MESSAGES];
|
||||
int m_messageCount;
|
||||
static const int TEXT_POOL_SIZE = 8000;
|
||||
char m_textPool[TEXT_POOL_SIZE];
|
||||
int m_textPoolSize;
|
||||
|
||||
public:
|
||||
BuildContext();
|
||||
|
||||
/// Dumps the log to stdout.
|
||||
void dumpLog(const char* format, ...);
|
||||
/// Returns number of log messages.
|
||||
int getLogCount() const;
|
||||
/// Returns log message text.
|
||||
const char* getLogText(const int i) const;
|
||||
|
||||
protected:
|
||||
/// Virtual functions for custom implementations.
|
||||
///@{
|
||||
virtual void doResetLog();
|
||||
virtual void doLog(const rcLogCategory category, const char* msg, const int len);
|
||||
virtual void doResetTimers();
|
||||
virtual void doStartTimer(const rcTimerLabel label);
|
||||
virtual void doStopTimer(const rcTimerLabel label);
|
||||
virtual int doGetAccumulatedTime(const rcTimerLabel label) const;
|
||||
///@}
|
||||
};
|
||||
|
||||
/// OpenGL debug draw implementation.
|
||||
class DebugDrawGL : public duDebugDraw
|
||||
{
|
||||
public:
|
||||
virtual void depthMask(bool state);
|
||||
virtual void texture(bool state);
|
||||
virtual void begin(duDebugDrawPrimitives prim, float size = 1.0f);
|
||||
virtual void vertex(const float* pos, unsigned int color);
|
||||
virtual void vertex(const float x, const float y, const float z, unsigned int color);
|
||||
virtual void vertex(const float* pos, unsigned int color, const float* uv);
|
||||
virtual void vertex(const float x, const float y, const float z, unsigned int color, const float u, const float v);
|
||||
virtual void end();
|
||||
};
|
||||
|
||||
/// stdio file implementation.
|
||||
class FileIO : public duFileIO
|
||||
{
|
||||
FILE* m_fp;
|
||||
int m_mode;
|
||||
public:
|
||||
FileIO();
|
||||
virtual ~FileIO();
|
||||
bool openForWrite(const char* path);
|
||||
bool openForRead(const char* path);
|
||||
virtual bool isWriting() const;
|
||||
virtual bool isReading() const;
|
||||
virtual bool write(const void* ptr, const size_t size);
|
||||
virtual bool read(void* ptr, const size_t size);
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
FileIO(const FileIO&);
|
||||
FileIO& operator=(const FileIO&);
|
||||
};
|
||||
|
||||
#endif // SAMPLEINTERFACES_H
|
||||
|
49
NavMeshGenerator/Main.cpp
Normal file
49
NavMeshGenerator/Main.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include "Framework/InputGeom.h"
|
||||
|
||||
#include "NavMeshGenerator.h"
|
||||
#include "RecastContext.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::filesystem::path inputPath;
|
||||
std::filesystem::path outputPath;
|
||||
bool enableLogging = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (!_stricmp(argv[i], "--input"))
|
||||
{
|
||||
inputPath = argv[++i];
|
||||
}
|
||||
else if (!_stricmp(argv[i], "--output"))
|
||||
{
|
||||
outputPath = argv[++i];
|
||||
}
|
||||
else if (!_stricmp(argv[i], "--enableLogging"))
|
||||
{
|
||||
enableLogging = true;
|
||||
}
|
||||
}
|
||||
|
||||
InputGeom* geom = new InputGeom();
|
||||
geom->load(nullptr, inputPath.string());
|
||||
|
||||
if (outputPath.empty())
|
||||
{
|
||||
printf("Warning: no output path set, no file will be generated.\n");
|
||||
}
|
||||
|
||||
const auto context = std::make_shared<RecastContext>(enableLogging);
|
||||
NavMeshGenerator generator(geom, context);
|
||||
bool success = generator.BuildNavMesh();
|
||||
|
||||
float totalTime = context->getAccumulatedTime(RC_TIMER_TOTAL) / 1000.0f;
|
||||
|
||||
printf("Success: %d\n", success);
|
||||
printf("Total time in milliseconds: %.2f\n", totalTime);
|
||||
|
||||
if (!outputPath.empty())
|
||||
{
|
||||
generator.Serialize(outputPath);
|
||||
}
|
||||
}
|
527
NavMeshGenerator/NavMeshGenerator.cpp
Normal file
527
NavMeshGenerator/NavMeshGenerator.cpp
Normal file
@ -0,0 +1,527 @@
|
||||
#include "NavMeshGenerator.h"
|
||||
|
||||
#include "DetourNavMesh.h"
|
||||
#include "DetourNavMeshBuilder.h"
|
||||
#include "Recast.h"
|
||||
#include "RecastContext.h"
|
||||
|
||||
NavMeshGenerator::NavMeshGenerator(InputGeom* geom, std::shared_ptr<RecastContext> context)
|
||||
: m_geom(geom),
|
||||
m_navMeshQuery(dtAllocNavMeshQuery()),
|
||||
m_navMesh(dtAllocNavMesh()),
|
||||
m_ctx(context)
|
||||
{
|
||||
}
|
||||
|
||||
NavMeshGenerator::~NavMeshGenerator()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void NavMeshGenerator::Cleanup()
|
||||
{
|
||||
delete[] m_triareas;
|
||||
m_triareas = 0;
|
||||
rcFreeHeightField(m_solid);
|
||||
m_solid = 0;
|
||||
rcFreeCompactHeightfield(m_chf);
|
||||
m_chf = 0;
|
||||
rcFreeContourSet(m_cset);
|
||||
m_cset = 0;
|
||||
rcFreePolyMesh(m_pmesh);
|
||||
m_pmesh = 0;
|
||||
rcFreePolyMeshDetail(m_dmesh);
|
||||
m_dmesh = 0;
|
||||
}
|
||||
|
||||
bool NavMeshGenerator::BuildNavMesh()
|
||||
{
|
||||
dtNavMeshParams params{};
|
||||
rcVcopy(params.orig, m_geom->getNavMeshBoundsMin());
|
||||
params.tileWidth = m_tileSize * m_cellSize;
|
||||
params.tileHeight = m_tileSize * m_cellSize;
|
||||
params.maxTiles = m_maxTiles;
|
||||
params.maxPolys = m_maxPolysPerTile;
|
||||
|
||||
dtStatus status = m_navMesh->init(¶ms);
|
||||
if (dtStatusFailed(status))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
status = m_navMeshQuery->init(m_navMesh.get(), 2048);
|
||||
if (dtStatusFailed(status))
|
||||
{
|
||||
//m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init Detour navmesh query");
|
||||
return false;
|
||||
}
|
||||
|
||||
BuildAllTiles();
|
||||
return true;
|
||||
}
|
||||
|
||||
void NavMeshGenerator::BuildAllTiles()
|
||||
{
|
||||
const float* bmin = m_geom->getNavMeshBoundsMin();
|
||||
const float* bmax = m_geom->getNavMeshBoundsMax();
|
||||
|
||||
int gw = 0, gh = 0;
|
||||
rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);
|
||||
const int ts = (int)m_tileSize;
|
||||
const int tw = (gw + ts - 1) / ts;
|
||||
const int th = (gh + ts - 1) / ts;
|
||||
const float tcs = m_tileSize * m_cellSize;
|
||||
|
||||
m_ctx->startTimer(RC_TIMER_TEMP);
|
||||
|
||||
for (int y = 0; y < th; ++y)
|
||||
{
|
||||
for (int x = 0; x < tw; ++x)
|
||||
{
|
||||
m_lastBuiltTileBmin[0] = bmin[0] + x * tcs;
|
||||
m_lastBuiltTileBmin[1] = bmin[1];
|
||||
m_lastBuiltTileBmin[2] = bmin[2] + y * tcs;
|
||||
|
||||
m_lastBuiltTileBmax[0] = bmin[0] + (x + 1) * tcs;
|
||||
m_lastBuiltTileBmax[1] = bmax[1];
|
||||
m_lastBuiltTileBmax[2] = bmin[2] + (y + 1) * tcs;
|
||||
|
||||
int dataSize = 0;
|
||||
unsigned char* data = BuildTileMesh(x, y, m_lastBuiltTileBmin, m_lastBuiltTileBmax, dataSize);
|
||||
if (data)
|
||||
{
|
||||
// Remove any previous data (navmesh owns and deletes the data).
|
||||
m_navMesh->removeTile(m_navMesh->getTileRefAt(x, y, 0), 0, 0);
|
||||
// Let the navmesh own the data.
|
||||
dtStatus status = m_navMesh->addTile(data, dataSize, DT_TILE_FREE_DATA, 0, 0);
|
||||
if (dtStatusFailed(status))
|
||||
dtFree(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start the build process.
|
||||
m_ctx->stopTimer(RC_TIMER_TEMP);
|
||||
|
||||
//m_totalBuildTimeMs = m_ctx->getAccumulatedTime(RC_TIMER_TEMP) / 1000.0f;
|
||||
}
|
||||
|
||||
unsigned char* NavMeshGenerator::BuildTileMesh(const int tx, const int ty, const float* bmin, const float* bmax, int& dataSize)
|
||||
{
|
||||
if (!m_geom || !m_geom->getMesh() || !m_geom->getChunkyMesh())
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Input mesh is not specified.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_tileMemUsage = 0;
|
||||
m_tileBuildTime = 0;
|
||||
|
||||
Cleanup();
|
||||
|
||||
const float* verts = m_geom->getMesh()->getVerts();
|
||||
const int nverts = m_geom->getMesh()->getVertCount();
|
||||
const int ntris = m_geom->getMesh()->getTriCount();
|
||||
const rcChunkyTriMesh* chunkyMesh = m_geom->getChunkyMesh();
|
||||
|
||||
// Init build configuration from GUI
|
||||
memset(&m_cfg, 0, sizeof(m_cfg));
|
||||
m_cfg.cs = m_cellSize;
|
||||
m_cfg.ch = m_cellHeight;
|
||||
m_cfg.walkableSlopeAngle = m_agentMaxSlope;
|
||||
m_cfg.walkableHeight = (int)ceilf(m_agentHeight / m_cfg.ch);
|
||||
m_cfg.walkableClimb = (int)floorf(m_agentMaxClimb / m_cfg.ch);
|
||||
m_cfg.walkableRadius = (int)ceilf(m_agentRadius / m_cfg.cs);
|
||||
m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize);
|
||||
m_cfg.maxSimplificationError = m_edgeMaxError;
|
||||
m_cfg.minRegionArea = (int)rcSqr(m_regionMinSize); // Note: area = size*size
|
||||
m_cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize); // Note: area = size*size
|
||||
m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly;
|
||||
m_cfg.tileSize = (int)m_tileSize;
|
||||
m_cfg.borderSize = m_cfg.walkableRadius + 3; // Reserve enough padding.
|
||||
m_cfg.width = m_cfg.tileSize + m_cfg.borderSize * 2;
|
||||
m_cfg.height = m_cfg.tileSize + m_cfg.borderSize * 2;
|
||||
m_cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist;
|
||||
m_cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError;
|
||||
|
||||
// Expand the heighfield bounding box by border size to find the extents of geometry we need to build this tile.
|
||||
//
|
||||
// This is done in order to make sure that the navmesh tiles connect correctly at the borders,
|
||||
// and the obstacles close to the border work correctly with the dilation process.
|
||||
// No polygons (or contours) will be created on the border area.
|
||||
//
|
||||
// IMPORTANT!
|
||||
//
|
||||
// :''''''''':
|
||||
// : +-----+ :
|
||||
// : | | :
|
||||
// : | |<--- tile to build
|
||||
// : | | :
|
||||
// : +-----+ :<-- geometry needed
|
||||
// :.........:
|
||||
//
|
||||
// You should use this bounding box to query your input geometry.
|
||||
//
|
||||
// For example if you build a navmesh for terrain, and want the navmesh tiles to match the terrain tile size
|
||||
// you will need to pass in data from neighbour terrain tiles too! In a simple case, just pass in all the 8 neighbours,
|
||||
// or use the bounding box below to only pass in a sliver of each of the 8 neighbours.
|
||||
rcVcopy(m_cfg.bmin, bmin);
|
||||
rcVcopy(m_cfg.bmax, bmax);
|
||||
m_cfg.bmin[0] -= m_cfg.borderSize * m_cfg.cs;
|
||||
m_cfg.bmin[2] -= m_cfg.borderSize * m_cfg.cs;
|
||||
m_cfg.bmax[0] += m_cfg.borderSize * m_cfg.cs;
|
||||
m_cfg.bmax[2] += m_cfg.borderSize * m_cfg.cs;
|
||||
|
||||
// Reset build times gathering.
|
||||
m_ctx->resetTimers();
|
||||
|
||||
// Start the build process.
|
||||
m_ctx->startTimer(RC_TIMER_TOTAL);
|
||||
|
||||
m_ctx->log(RC_LOG_PROGRESS, "Building navigation:");
|
||||
m_ctx->log(RC_LOG_PROGRESS, " - %d x %d cells", m_cfg.width, m_cfg.height);
|
||||
m_ctx->log(RC_LOG_PROGRESS, " - %.1fK verts, %.1fK tris", nverts / 1000.0f, ntris / 1000.0f);
|
||||
|
||||
// Allocate voxel heightfield where we rasterize our input data to.
|
||||
m_solid = rcAllocHeightfield();
|
||||
if (!m_solid)
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'.");
|
||||
return 0;
|
||||
}
|
||||
if (!rcCreateHeightfield(m_ctx.get(), *m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch))
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create solid heightfield.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate array that can hold triangle flags.
|
||||
// If you have multiple meshes you need to process, allocate
|
||||
// and array which can hold the max number of triangles you need to process.
|
||||
m_triareas = new unsigned char[chunkyMesh->maxTrisPerChunk];
|
||||
if (!m_triareas)
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'm_triareas' (%d).", chunkyMesh->maxTrisPerChunk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float tbmin[2], tbmax[2];
|
||||
tbmin[0] = m_cfg.bmin[0];
|
||||
tbmin[1] = m_cfg.bmin[2];
|
||||
tbmax[0] = m_cfg.bmax[0];
|
||||
tbmax[1] = m_cfg.bmax[2];
|
||||
int cid[512];// TODO: Make grow when returning too many items.
|
||||
const int ncid = rcGetChunksOverlappingRect(chunkyMesh, tbmin, tbmax, cid, 512);
|
||||
if (!ncid)
|
||||
return 0;
|
||||
|
||||
m_tileTriCount = 0;
|
||||
|
||||
for (int i = 0; i < ncid; ++i)
|
||||
{
|
||||
const rcChunkyTriMeshNode& node = chunkyMesh->nodes[cid[i]];
|
||||
const int* ctris = &chunkyMesh->tris[node.i * 3];
|
||||
const int nctris = node.n;
|
||||
|
||||
m_tileTriCount += nctris;
|
||||
|
||||
memset(m_triareas, 0, nctris * sizeof(unsigned char));
|
||||
rcMarkWalkableTriangles(m_ctx.get(), m_cfg.walkableSlopeAngle,
|
||||
verts, nverts, ctris, nctris, m_triareas);
|
||||
|
||||
if (!rcRasterizeTriangles(m_ctx.get(), verts, nverts, ctris, m_triareas, nctris, *m_solid, m_cfg.walkableClimb))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_keepInterResults)
|
||||
{
|
||||
delete[] m_triareas;
|
||||
m_triareas = 0;
|
||||
}
|
||||
|
||||
// Once all geometry is rasterized, we do initial pass of filtering to
|
||||
// remove unwanted overhangs caused by the conservative rasterization
|
||||
// as well as filter spans where the character cannot possibly stand.
|
||||
if (m_filterLowHangingObstacles)
|
||||
rcFilterLowHangingWalkableObstacles(m_ctx.get(), m_cfg.walkableClimb, *m_solid);
|
||||
if (m_filterLedgeSpans)
|
||||
rcFilterLedgeSpans(m_ctx.get(), m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid);
|
||||
if (m_filterWalkableLowHeightSpans)
|
||||
rcFilterWalkableLowHeightSpans(m_ctx.get(), m_cfg.walkableHeight, *m_solid);
|
||||
|
||||
// Compact the heightfield so that it is faster to handle from now on.
|
||||
// This will result more cache coherent data as well as the neighbours
|
||||
// between walkable cells will be calculated.
|
||||
m_chf = rcAllocCompactHeightfield();
|
||||
if (!m_chf)
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'.");
|
||||
return 0;
|
||||
}
|
||||
if (!rcBuildCompactHeightfield(m_ctx.get(), m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid, *m_chf))
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build compact data.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_keepInterResults)
|
||||
{
|
||||
rcFreeHeightField(m_solid);
|
||||
m_solid = 0;
|
||||
}
|
||||
|
||||
// Erode the walkable area by agent radius.
|
||||
if (!rcErodeWalkableArea(m_ctx.get(), m_cfg.walkableRadius, *m_chf))
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not erode.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// (Optional) Mark areas.
|
||||
const ConvexVolume* vols = m_geom->getConvexVolumes();
|
||||
for (int i = 0; i < m_geom->getConvexVolumeCount(); ++i)
|
||||
rcMarkConvexPolyArea(m_ctx.get(), vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned char)vols[i].area, *m_chf);
|
||||
|
||||
|
||||
// Partition the heightfield so that we can use simple algorithm later to triangulate the walkable areas.
|
||||
// There are 3 martitioning methods, each with some pros and cons:
|
||||
// 1) Watershed partitioning
|
||||
// - the classic Recast partitioning
|
||||
// - creates the nicest tessellation
|
||||
// - usually slowest
|
||||
// - partitions the heightfield into nice regions without holes or overlaps
|
||||
// - the are some corner cases where this method creates produces holes and overlaps
|
||||
// - holes may appear when a small obstacles is close to large open area (triangulation can handle this)
|
||||
// - overlaps may occur if you have narrow spiral corridors (i.e stairs), this make triangulation to fail
|
||||
// * generally the best choice if you precompute the nacmesh, use this if you have large open areas
|
||||
// 2) Monotone partioning
|
||||
// - fastest
|
||||
// - partitions the heightfield into regions without holes and overlaps (guaranteed)
|
||||
// - creates long thin polygons, which sometimes causes paths with detours
|
||||
// * use this if you want fast navmesh generation
|
||||
// 3) Layer partitoining
|
||||
// - quite fast
|
||||
// - partitions the heighfield into non-overlapping regions
|
||||
// - relies on the triangulation code to cope with holes (thus slower than monotone partitioning)
|
||||
// - produces better triangles than monotone partitioning
|
||||
// - does not have the corner cases of watershed partitioning
|
||||
// - can be slow and create a bit ugly tessellation (still better than monotone)
|
||||
// if you have large open areas with small obstacles (not a problem if you use tiles)
|
||||
// * good choice to use for tiled navmesh with medium and small sized tiles
|
||||
|
||||
if (m_partitionType == SAMPLE_PARTITION_WATERSHED)
|
||||
{
|
||||
// Prepare for region partitioning, by calculating distance field along the walkable surface.
|
||||
if (!rcBuildDistanceField(m_ctx.get(), *m_chf))
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Partition the walkable surface into simple regions without holes.
|
||||
if (!rcBuildRegions(m_ctx.get(), *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build watershed regions.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (m_partitionType == SAMPLE_PARTITION_MONOTONE)
|
||||
{
|
||||
// Partition the walkable surface into simple regions without holes.
|
||||
// Monotone partitioning does not need distancefield.
|
||||
if (!rcBuildRegionsMonotone(m_ctx.get(), *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build monotone regions.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else // SAMPLE_PARTITION_LAYERS
|
||||
{
|
||||
// Partition the walkable surface into simple regions without holes.
|
||||
if (!rcBuildLayerRegions(m_ctx.get(), *m_chf, m_cfg.borderSize, m_cfg.minRegionArea))
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build layer regions.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Create contours.
|
||||
m_cset = rcAllocContourSet();
|
||||
if (!m_cset)
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'.");
|
||||
return 0;
|
||||
}
|
||||
if (!rcBuildContours(m_ctx.get(), *m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset))
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create contours.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_cset->nconts == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Build polygon navmesh from the contours.
|
||||
m_pmesh = rcAllocPolyMesh();
|
||||
if (!m_pmesh)
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmesh'.");
|
||||
return 0;
|
||||
}
|
||||
if (!rcBuildPolyMesh(m_ctx.get(), *m_cset, m_cfg.maxVertsPerPoly, *m_pmesh))
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not triangulate contours.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Build detail mesh.
|
||||
m_dmesh = rcAllocPolyMeshDetail();
|
||||
if (!m_dmesh)
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'dmesh'.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!rcBuildPolyMeshDetail(m_ctx.get(), *m_pmesh, *m_chf,
|
||||
m_cfg.detailSampleDist, m_cfg.detailSampleMaxError,
|
||||
*m_dmesh))
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could build polymesh detail.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_keepInterResults)
|
||||
{
|
||||
rcFreeCompactHeightfield(m_chf);
|
||||
m_chf = 0;
|
||||
rcFreeContourSet(m_cset);
|
||||
m_cset = 0;
|
||||
}
|
||||
|
||||
unsigned char* navData = 0;
|
||||
int navDataSize = 0;
|
||||
if (m_cfg.maxVertsPerPoly <= DT_VERTS_PER_POLYGON)
|
||||
{
|
||||
if (m_pmesh->nverts >= 0xffff)
|
||||
{
|
||||
// The vertex indices are ushorts, and cannot point to more than 0xffff vertices.
|
||||
m_ctx->log(RC_LOG_ERROR, "Too many vertices per tile %d (max: %d).", m_pmesh->nverts, 0xffff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Update poly flags from areas.
|
||||
for (int i = 0; i < m_pmesh->npolys; ++i)
|
||||
{
|
||||
if (m_pmesh->areas[i] == RC_WALKABLE_AREA)
|
||||
m_pmesh->areas[i] = SAMPLE_POLYAREA_GROUND;
|
||||
|
||||
if (m_pmesh->areas[i] == SAMPLE_POLYAREA_GROUND ||
|
||||
m_pmesh->areas[i] == SAMPLE_POLYAREA_GRASS ||
|
||||
m_pmesh->areas[i] == SAMPLE_POLYAREA_ROAD)
|
||||
{
|
||||
m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK;
|
||||
}
|
||||
else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_WATER)
|
||||
{
|
||||
m_pmesh->flags[i] = SAMPLE_POLYFLAGS_SWIM;
|
||||
}
|
||||
else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_DOOR)
|
||||
{
|
||||
m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR;
|
||||
}
|
||||
}
|
||||
|
||||
dtNavMeshCreateParams params{};
|
||||
params.verts = m_pmesh->verts;
|
||||
params.vertCount = m_pmesh->nverts;
|
||||
params.polys = m_pmesh->polys;
|
||||
params.polyAreas = m_pmesh->areas;
|
||||
params.polyFlags = m_pmesh->flags;
|
||||
params.polyCount = m_pmesh->npolys;
|
||||
params.nvp = m_pmesh->nvp;
|
||||
params.detailMeshes = m_dmesh->meshes;
|
||||
params.detailVerts = m_dmesh->verts;
|
||||
params.detailVertsCount = m_dmesh->nverts;
|
||||
params.detailTris = m_dmesh->tris;
|
||||
params.detailTriCount = m_dmesh->ntris;
|
||||
params.offMeshConVerts = m_geom->getOffMeshConnectionVerts();
|
||||
params.offMeshConRad = m_geom->getOffMeshConnectionRads();
|
||||
params.offMeshConDir = m_geom->getOffMeshConnectionDirs();
|
||||
params.offMeshConAreas = m_geom->getOffMeshConnectionAreas();
|
||||
params.offMeshConFlags = m_geom->getOffMeshConnectionFlags();
|
||||
params.offMeshConUserID = m_geom->getOffMeshConnectionId();
|
||||
params.offMeshConCount = m_geom->getOffMeshConnectionCount();
|
||||
params.walkableHeight = m_agentHeight;
|
||||
params.walkableRadius = m_agentRadius;
|
||||
params.walkableClimb = m_agentMaxClimb;
|
||||
params.tileX = tx;
|
||||
params.tileY = ty;
|
||||
params.tileLayer = 0;
|
||||
rcVcopy(params.bmin, m_pmesh->bmin);
|
||||
rcVcopy(params.bmax, m_pmesh->bmax);
|
||||
params.cs = m_cfg.cs;
|
||||
params.ch = m_cfg.ch;
|
||||
params.buildBvTree = true;
|
||||
|
||||
if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize))
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "Could not build Detour navmesh.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
m_tileMemUsage = navDataSize / 1024.0f;
|
||||
|
||||
m_ctx->stopTimer(RC_TIMER_TOTAL);
|
||||
|
||||
// Show performance stats.
|
||||
duLogBuildTimes(*m_ctx, m_ctx->getAccumulatedTime(RC_TIMER_TOTAL));
|
||||
m_ctx->log(RC_LOG_PROGRESS, ">> Polymesh: %d vertices %d polygons", m_pmesh->nverts, m_pmesh->npolys);
|
||||
|
||||
m_tileBuildTime = m_ctx->getAccumulatedTime(RC_TIMER_TOTAL) / 1000.0f;
|
||||
|
||||
dataSize = navDataSize;
|
||||
return navData;
|
||||
}
|
||||
|
||||
void NavMeshGenerator::Serialize(const std::filesystem::path& path) const
|
||||
{
|
||||
if (!m_navMesh) return;
|
||||
|
||||
FILE* fp = fopen(path.string().c_str(), "wb");
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
// Store header.
|
||||
NavMeshSetHeader header;
|
||||
header.magic = NAVMESHSET_MAGIC;
|
||||
header.version = NAVMESHSET_VERSION;
|
||||
header.numTiles = 0;
|
||||
for (int i = 0; i < m_navMesh->getMaxTiles(); ++i)
|
||||
{
|
||||
const dtNavMesh* navMesh = m_navMesh.get();
|
||||
const dtMeshTile* tile = navMesh->getTile(i);
|
||||
if (!tile || !tile->header || !tile->dataSize) continue;
|
||||
header.numTiles++;
|
||||
}
|
||||
memcpy(&header.params, m_navMesh->getParams(), sizeof(dtNavMeshParams));
|
||||
fwrite(&header, sizeof(NavMeshSetHeader), 1, fp);
|
||||
|
||||
// Store tiles.
|
||||
for (int i = 0; i < m_navMesh->getMaxTiles(); ++i)
|
||||
{
|
||||
const dtNavMesh* navMesh = m_navMesh.get();
|
||||
const dtMeshTile* tile = navMesh->getTile(i);
|
||||
if (!tile || !tile->header || !tile->dataSize) continue;
|
||||
|
||||
NavMeshTileHeader tileHeader;
|
||||
tileHeader.tileRef = m_navMesh->getTileRef(tile);
|
||||
tileHeader.dataSize = tile->dataSize;
|
||||
fwrite(&tileHeader, sizeof(tileHeader), 1, fp);
|
||||
|
||||
fwrite(tile->data, tile->dataSize, 1, fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
77
NavMeshGenerator/NavMeshGenerator.h
Normal file
77
NavMeshGenerator/NavMeshGenerator.h
Normal file
@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
// Recast
|
||||
#include "Recast.h"
|
||||
#include "DetourNavMesh.h"
|
||||
#include "DetourNavMeshQuery.h"
|
||||
|
||||
// Framework
|
||||
#include "Framework/InputGeom.h"
|
||||
#include "Framework/Sample.h"
|
||||
|
||||
#include "NavMeshUtil.h"
|
||||
#include "RecastContext.h"
|
||||
|
||||
class NavMeshGenerator
|
||||
{
|
||||
public:
|
||||
NavMeshGenerator(InputGeom* geom, std::shared_ptr<RecastContext> context);
|
||||
virtual ~NavMeshGenerator();
|
||||
|
||||
bool BuildNavMesh();
|
||||
void Serialize(const std::filesystem::path& path) const;
|
||||
private:
|
||||
void BuildAllTiles();
|
||||
void Cleanup();
|
||||
|
||||
unsigned char* BuildTileMesh(const int tx, const int ty, const float* bmin, const float* bmax, int& dataSize);
|
||||
|
||||
std::unique_ptr<InputGeom> m_geom;
|
||||
std::unique_ptr<dtNavMesh, NavMeshDeleter> m_navMesh;
|
||||
std::unique_ptr<dtNavMeshQuery, NavMeshQueryDeleter> m_navMeshQuery;
|
||||
std::shared_ptr<rcContext> m_ctx;
|
||||
|
||||
|
||||
unsigned char* m_triareas{};
|
||||
rcHeightfield* m_solid{};
|
||||
rcCompactHeightfield* m_chf{};
|
||||
rcContourSet* m_cset{};
|
||||
rcPolyMesh* m_pmesh{};
|
||||
rcPolyMeshDetail* m_dmesh{};
|
||||
rcConfig m_cfg{};
|
||||
|
||||
// Core configuration
|
||||
float m_cellSize = 0.3f;
|
||||
float m_cellHeight = 0.2f;
|
||||
float m_agentHeight = 2.0f;
|
||||
float m_agentRadius = 0.6f;
|
||||
float m_agentMaxClimb = 0.9f;
|
||||
float m_agentMaxSlope = 50.0f; //45.0f;
|
||||
float m_regionMinSize = 8;
|
||||
float m_regionMergeSize = 20;
|
||||
float m_edgeMaxLen = 12.0f;
|
||||
float m_edgeMaxError = 1.3f;
|
||||
float m_vertsPerPoly = 6.0f;
|
||||
float m_detailSampleDist = 6.0f;
|
||||
float m_detailSampleMaxError = 1.0f;
|
||||
int m_partitionType = SAMPLE_PARTITION_WATERSHED;
|
||||
bool m_keepInterResults = false;
|
||||
|
||||
// Core filtering configuration
|
||||
bool m_filterLowHangingObstacles = true;
|
||||
bool m_filterLedgeSpans = true;
|
||||
bool m_filterWalkableLowHeightSpans = true;
|
||||
|
||||
// Tile configuration
|
||||
int m_maxTiles = 0;
|
||||
int m_maxPolysPerTile = 0;
|
||||
float m_tileSize = 32;
|
||||
|
||||
unsigned int m_tileCol{};
|
||||
float m_lastBuiltTileBmin[3]{};
|
||||
float m_lastBuiltTileBmax[3]{};
|
||||
float m_tileMemUsage{};
|
||||
float m_tileBuildTime{};
|
||||
int m_tileTriCount{};
|
||||
|
||||
};
|
31
NavMeshGenerator/NavMeshGenerator.sln
Normal file
31
NavMeshGenerator/NavMeshGenerator.sln
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30804.86
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NavMeshGenerator", "NavMeshGenerator.vcxproj", "{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x64.Build.0 = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {4274A358-82D6-4297-99D3-9647B7FC1368}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
221
NavMeshGenerator/NavMeshGenerator.vcxproj
Normal file
221
NavMeshGenerator/NavMeshGenerator.vcxproj
Normal file
@ -0,0 +1,221 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{ca9c0938-3ada-4c73-a89a-e9447abce101}</ProjectGuid>
|
||||
<RootNamespace>NavMeshGenerator</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\External\recastnavigation\DebugUtils\Include;..\External\recastnavigation\Detour\Include;..\External\recastnavigation\DetourTileCache\Include;;..\External\recastnavigation\Recast\Include</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\External\recastnavigation\DebugUtils\Include;..\External\recastnavigation\Detour\Include;..\External\recastnavigation\DetourTileCache\Include;;..\External\recastnavigation\Recast\Include</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\External\recastnavigation\DebugUtils\Source\DebugDraw.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\DebugUtils\Source\DetourDebugDraw.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\DebugUtils\Source\RecastDebugDraw.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\DebugUtils\Source\RecastDump.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\DetourTileCache\Source\DetourTileCache.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\DetourTileCache\Source\DetourTileCacheBuilder.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourAlloc.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourAssert.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourCommon.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourNavMesh.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourNavMeshBuilder.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourNavMeshQuery.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourNode.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\Recast.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastAlloc.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastArea.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastAssert.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastContour.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastFilter.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastLayers.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastMesh.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastMeshDetail.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastRasterization.cpp" />
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastRegion.cpp" />
|
||||
<ClCompile Include="Framework\ChunkyTriMesh.cpp" />
|
||||
<ClCompile Include="Framework\InputGeom.cpp" />
|
||||
<ClCompile Include="Framework\MeshLoaderObj.cpp" />
|
||||
<ClCompile Include="Framework\PerfTimer.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="NavMeshGenerator.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RecastContext.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\External\recastnavigation\DebugUtils\Include\DebugDraw.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\DebugUtils\Include\DetourDebugDraw.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\DebugUtils\Include\RecastDebugDraw.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\DebugUtils\Include\RecastDump.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\DetourTileCache\Include\DetourTileCache.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\DetourTileCache\Include\DetourTileCacheBuilder.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourAlloc.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourAssert.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourCommon.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourMath.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourNavMesh.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourNavMeshBuilder.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourNavMeshQuery.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourNode.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourStatus.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Recast\Include\Recast.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Recast\Include\RecastAlloc.h" />
|
||||
<ClInclude Include="..\External\recastnavigation\Recast\Include\RecastAssert.h" />
|
||||
<ClInclude Include="Framework\ChunkyTriMesh.h" />
|
||||
<ClInclude Include="Framework\InputGeom.h" />
|
||||
<ClInclude Include="Framework\MeshLoaderObj.h" />
|
||||
<ClInclude Include="Framework\PerfTimer.h" />
|
||||
<ClInclude Include="Framework\Sample.h" />
|
||||
<ClInclude Include="Framework\SampleInterfaces.h" />
|
||||
<ClInclude Include="NavMeshGenerator.h" />
|
||||
<ClInclude Include="NavMeshUtil.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="RecastContext.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
243
NavMeshGenerator/NavMeshGenerator.vcxproj.filters
Normal file
243
NavMeshGenerator/NavMeshGenerator.vcxproj.filters
Normal file
@ -0,0 +1,243 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Recast">
|
||||
<UniqueIdentifier>{82f0fd75-bb9d-4e6c-849a-71f66d5a8f0a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\DebugUtils">
|
||||
<UniqueIdentifier>{31af1122-2287-4254-860d-7d9819551310}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\DebugUtils\Include">
|
||||
<UniqueIdentifier>{7589cc4f-b87f-4191-81fc-17622331c7ca}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\DebugUtils\Source">
|
||||
<UniqueIdentifier>{203ec006-7bdb-47fa-858a-6f12327c5d44}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\Detour">
|
||||
<UniqueIdentifier>{b05a0256-22d5-478e-85d7-c56cef704e1e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\Detour\Source">
|
||||
<UniqueIdentifier>{d30da57a-2663-4461-a272-be169bd1a3a5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\Detour\Include">
|
||||
<UniqueIdentifier>{1cb89f5c-da8d-49cf-9bfa-0cb8b38fabac}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\DetourTileCache">
|
||||
<UniqueIdentifier>{b4850d74-861d-4dc8-aa4e-59b6f18a7754}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\DetourTileCache\Include">
|
||||
<UniqueIdentifier>{f0447598-7859-485b-97e8-61035bd87634}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\DetourTileCache\Source">
|
||||
<UniqueIdentifier>{1bc45b59-e845-4a30-b042-2c6ff3fdc3fe}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\Recast">
|
||||
<UniqueIdentifier>{b17dc902-8d50-4da4-9013-e1bd39206ca5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\Recast\Source">
|
||||
<UniqueIdentifier>{091ace17-5d99-46d0-9d81-57fd2b4eb225}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recast\Recast\Include">
|
||||
<UniqueIdentifier>{54fffb89-f106-45f9-9a78-119f59e17fed}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Framework">
|
||||
<UniqueIdentifier>{c5ca75e6-1ec9-4c06-a733-4323f130f5c4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\External\recastnavigation\DebugUtils\Source\DebugDraw.cpp">
|
||||
<Filter>Recast\DebugUtils\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\DebugUtils\Source\DetourDebugDraw.cpp">
|
||||
<Filter>Recast\DebugUtils\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\DebugUtils\Source\RecastDebugDraw.cpp">
|
||||
<Filter>Recast\DebugUtils\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\DebugUtils\Source\RecastDump.cpp">
|
||||
<Filter>Recast\DebugUtils\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourAlloc.cpp">
|
||||
<Filter>Recast\Detour\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourAssert.cpp">
|
||||
<Filter>Recast\Detour\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourCommon.cpp">
|
||||
<Filter>Recast\Detour\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourNavMesh.cpp">
|
||||
<Filter>Recast\Detour\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourNavMeshBuilder.cpp">
|
||||
<Filter>Recast\Detour\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourNavMeshQuery.cpp">
|
||||
<Filter>Recast\Detour\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Detour\Source\DetourNode.cpp">
|
||||
<Filter>Recast\Detour\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\DetourTileCache\Source\DetourTileCache.cpp">
|
||||
<Filter>Recast\DetourTileCache\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\DetourTileCache\Source\DetourTileCacheBuilder.cpp">
|
||||
<Filter>Recast\DetourTileCache\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\Recast.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastAlloc.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastArea.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastAssert.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastContour.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastFilter.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastLayers.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastMesh.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastMeshDetail.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastRasterization.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastRegion.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NavMeshGenerator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RecastContext.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Framework\ChunkyTriMesh.cpp">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Framework\InputGeom.cpp">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Framework\MeshLoaderObj.cpp">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Framework\PerfTimer.cpp">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\External\recastnavigation\DebugUtils\Include\DebugDraw.h">
|
||||
<Filter>Recast\DebugUtils\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\DebugUtils\Include\DetourDebugDraw.h">
|
||||
<Filter>Recast\DebugUtils\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\DebugUtils\Include\RecastDebugDraw.h">
|
||||
<Filter>Recast\DebugUtils\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\DebugUtils\Include\RecastDump.h">
|
||||
<Filter>Recast\DebugUtils\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourAlloc.h">
|
||||
<Filter>Recast\Detour\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourAssert.h">
|
||||
<Filter>Recast\Detour\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourCommon.h">
|
||||
<Filter>Recast\Detour\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourMath.h">
|
||||
<Filter>Recast\Detour\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourNavMesh.h">
|
||||
<Filter>Recast\Detour\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourNavMeshBuilder.h">
|
||||
<Filter>Recast\Detour\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourNavMeshQuery.h">
|
||||
<Filter>Recast\Detour\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourNode.h">
|
||||
<Filter>Recast\Detour\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Detour\Include\DetourStatus.h">
|
||||
<Filter>Recast\Detour\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\DetourTileCache\Include\DetourTileCache.h">
|
||||
<Filter>Recast\DetourTileCache\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\DetourTileCache\Include\DetourTileCacheBuilder.h">
|
||||
<Filter>Recast\DetourTileCache\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Recast\Include\Recast.h">
|
||||
<Filter>Recast\Recast\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Recast\Include\RecastAlloc.h">
|
||||
<Filter>Recast\Recast\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\External\recastnavigation\Recast\Include\RecastAssert.h">
|
||||
<Filter>Recast\Recast\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NavMeshGenerator.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NavMeshUtil.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RecastContext.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\ChunkyTriMesh.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\InputGeom.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\MeshLoaderObj.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\PerfTimer.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\Sample.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\SampleInterfaces.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
41
NavMeshGenerator/NavMeshUtil.h
Normal file
41
NavMeshGenerator/NavMeshUtil.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// Smart pointer deleters
|
||||
|
||||
struct NavMeshDeleter
|
||||
{
|
||||
void operator()(dtNavMesh* navMesh)
|
||||
{
|
||||
if (navMesh)
|
||||
dtFreeNavMesh(navMesh);
|
||||
}
|
||||
};
|
||||
|
||||
struct NavMeshQueryDeleter
|
||||
{
|
||||
void operator()(dtNavMeshQuery* navMeshQuery)
|
||||
{
|
||||
if (navMeshQuery)
|
||||
dtFreeNavMeshQuery(navMeshQuery);
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// Serialization logic
|
||||
struct NavMeshSetHeader
|
||||
{
|
||||
int magic;
|
||||
int version;
|
||||
int numTiles;
|
||||
dtNavMeshParams params;
|
||||
};
|
||||
|
||||
struct NavMeshTileHeader
|
||||
{
|
||||
dtTileRef tileRef;
|
||||
int dataSize;
|
||||
};
|
||||
|
||||
static const int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; //'MSET';
|
||||
static const int NAVMESHSET_VERSION = 1;
|
44
NavMeshGenerator/RecastContext.cpp
Normal file
44
NavMeshGenerator/RecastContext.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "RecastContext.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
RecastContext::RecastContext(bool enableLogging)
|
||||
: m_enableLogging(enableLogging)
|
||||
{
|
||||
}
|
||||
|
||||
void RecastContext::doResetLog()
|
||||
{
|
||||
}
|
||||
|
||||
void RecastContext::doLog(const rcLogCategory category, const char* msg, const int len)
|
||||
{
|
||||
if (m_enableLogging)
|
||||
printf("RECAST: %s\n", msg);
|
||||
}
|
||||
|
||||
void RecastContext::doResetTimers()
|
||||
{
|
||||
for (int i = 0; i < RC_MAX_TIMERS; ++i)
|
||||
m_accTime[i] = -1;
|
||||
}
|
||||
|
||||
void RecastContext::doStartTimer(const rcTimerLabel label)
|
||||
{
|
||||
m_startTime[label] = getPerfTime();
|
||||
}
|
||||
|
||||
void RecastContext::doStopTimer(const rcTimerLabel label)
|
||||
{
|
||||
const TimeVal endTime = getPerfTime();
|
||||
const TimeVal deltaTime = endTime - m_startTime[label];
|
||||
if (m_accTime[label] == -1)
|
||||
m_accTime[label] = deltaTime;
|
||||
else
|
||||
m_accTime[label] += deltaTime;
|
||||
}
|
||||
|
||||
int RecastContext::doGetAccumulatedTime(const rcTimerLabel label) const
|
||||
{
|
||||
return getPerfTimeUsec(m_accTime[label]);
|
||||
}
|
23
NavMeshGenerator/RecastContext.h
Normal file
23
NavMeshGenerator/RecastContext.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "Recast.h"
|
||||
#include "Framework/PerfTimer.h"
|
||||
|
||||
class RecastContext : public rcContext
|
||||
{
|
||||
public:
|
||||
RecastContext(bool enableLogging);
|
||||
|
||||
protected:
|
||||
virtual void doResetLog();
|
||||
virtual void doLog(const rcLogCategory category, const char* msg, const int len);
|
||||
virtual void doResetTimers();
|
||||
virtual void doStartTimer(const rcTimerLabel label);
|
||||
virtual void doStopTimer(const rcTimerLabel label);
|
||||
virtual int doGetAccumulatedTime(const rcTimerLabel label) const;
|
||||
|
||||
private:
|
||||
bool m_enableLogging{};
|
||||
TimeVal m_startTime[RC_MAX_TIMERS]{};
|
||||
TimeVal m_accTime[RC_MAX_TIMERS]{};
|
||||
};
|
0
NavMeshGenerator/pch.cpp
Normal file
0
NavMeshGenerator/pch.cpp
Normal file
3
NavMeshGenerator/pch.h
Normal file
3
NavMeshGenerator/pch.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
@ -19,6 +19,7 @@
|
||||
<RootNamespace>GiantsExp</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectName>imp_gbs</ProjectName>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
@ -74,7 +75,7 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
@ -110,7 +111,7 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
@ -142,7 +143,7 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
|
165
Sdk/Include/DataTypes.h
Normal file
165
Sdk/Include/DataTypes.h
Normal file
@ -0,0 +1,165 @@
|
||||
#pragma once
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Basic game data types and macros
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned char UBYTE;
|
||||
typedef signed char SBYTE;
|
||||
typedef unsigned short UWORD;
|
||||
typedef int BOOL;
|
||||
typedef unsigned long ULONG;
|
||||
typedef unsigned long DWORD;
|
||||
typedef std::int64_t int64;
|
||||
typedef std::uint64_t uint64;
|
||||
#ifdef UNICODE
|
||||
typedef std::wstring tstring;
|
||||
typedef std::wstring_view tstring_view;
|
||||
#else
|
||||
typedef std::string tstring;
|
||||
typedef std::string_view tstring_view;
|
||||
#endif
|
||||
|
||||
#define countof(array) (sizeof((array)) / sizeof((array)[0]))
|
||||
|
||||
#define FlagSet(b, f) ((b) |= (f))
|
||||
#define FlagClear(b, f) ((b) &= ~(f))
|
||||
#define FlagIsClear(b, f) (!FlagIsSet(b, f))
|
||||
#define FlagFlip(b, f) ((b) ^= (f))
|
||||
#define FlagIsSet(b, f) (((b) & (f)) != 0)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Vectors
|
||||
|
||||
struct P3D
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
inline const P3D& operator -= (const P3D& rhs)
|
||||
{
|
||||
x -= rhs.x;
|
||||
y -= rhs.y;
|
||||
z -= rhs.z;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const P3D& operator += (const P3D& rhs)
|
||||
{
|
||||
x += rhs.x;
|
||||
y += rhs.y;
|
||||
z += rhs.z;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline P3D operator - (const P3D& rhs)
|
||||
{
|
||||
P3D result;
|
||||
|
||||
result.x = x - rhs.x;
|
||||
result.y = y - rhs.y;
|
||||
result.z = z - rhs.z;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline P3D Cross(const P3D& v2)
|
||||
{
|
||||
P3D result;
|
||||
|
||||
result.x = y * v2.z - z * v2.y;
|
||||
result.y = z * v2.x - x * v2.z;
|
||||
result.z = x * v2.y - y * v2.x;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline float Dot(const P3D& v2)
|
||||
{
|
||||
return x * v2.x + y * v2.y + z * v2.z;
|
||||
}
|
||||
|
||||
inline float Length()
|
||||
{
|
||||
return (float)(sqrt(x * x + y * y + z * z));
|
||||
}
|
||||
|
||||
inline P3D Scale(float scale)
|
||||
{
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
z *= scale;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline P3D Normalize()
|
||||
{
|
||||
const float length = Length();
|
||||
P3D normalized = *this;
|
||||
|
||||
float factor = 0.0f;
|
||||
if (length)
|
||||
{
|
||||
factor = 1 / length;
|
||||
}
|
||||
else
|
||||
{
|
||||
factor = 1.0f;
|
||||
}
|
||||
|
||||
normalized.x *= factor;
|
||||
normalized.y *= factor;
|
||||
normalized.z *= factor;
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
bool IsNaN() const
|
||||
{
|
||||
return (_isnan(x) || _isnan(y) || _isnan(z));
|
||||
}
|
||||
|
||||
bool Finite() const
|
||||
{
|
||||
return (_finite(x) && _finite(y) && _finite(z));
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack (push, 1)
|
||||
// Optimized 3D vector for network packets.
|
||||
struct NetP3D
|
||||
{
|
||||
short x, y, z;
|
||||
};
|
||||
#pragma pack (pop)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct RGBFloat
|
||||
{
|
||||
float r{};
|
||||
float g{};
|
||||
float b{};
|
||||
};
|
||||
|
||||
struct VertRGB
|
||||
{
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
};
|
||||
|
||||
struct UV
|
||||
{
|
||||
float u, v;
|
||||
};
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <DataTypes.h>
|
||||
|
||||
#include "NetCommon.h"
|
||||
|
||||
/// <summary>
|
||||
@ -29,21 +31,22 @@ struct PlayerConnectedEvent : GameServerEvent
|
||||
{
|
||||
PlayerConnectedEvent() noexcept : GameServerEvent(GameServerEventType::PlayerConnected) { }
|
||||
|
||||
std::unique_ptr<PlayerInfo> info;
|
||||
std::shared_ptr<PlayerInfo> info;
|
||||
};
|
||||
|
||||
struct PlayerDisconnectedEvent : GameServerEvent
|
||||
{
|
||||
PlayerDisconnectedEvent() noexcept : GameServerEvent(GameServerEventType::PlayerDisconnected) { }
|
||||
|
||||
std::unique_ptr<PlayerInfo> info;
|
||||
std::shared_ptr<PlayerInfo> info;
|
||||
};
|
||||
|
||||
struct ChatMessageEvent : GameServerEvent
|
||||
{
|
||||
ChatMessageEvent() noexcept : GameServerEvent(GameServerEventType::ChatMessage) { }
|
||||
|
||||
std::string_view message;
|
||||
tstring_view message{};
|
||||
PlayerIndex senderIndex{};
|
||||
};
|
||||
|
||||
struct WorldLoadedEvent : GameServerEvent
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <DataTypes.h>
|
||||
#include <IComponent.h>
|
||||
#include <IEventSource.h>
|
||||
|
||||
@ -19,19 +21,60 @@ struct IGameServer : IComponent, IEventSource<GameServerEventType, GameServerEve
|
||||
{
|
||||
virtual ~IGameServer() = default;
|
||||
|
||||
virtual void STDMETHODCALLTYPE SendChatMessage(const std::string_view& message, ChatColor color, int flags, PlayerIndex indexTo) = 0;
|
||||
/// <summary>
|
||||
/// Sends a chat message to all players or to a specified player.
|
||||
/// </summary>
|
||||
/// <param name="message">The chat message.</param>
|
||||
/// <param name="color">Text color.</param>
|
||||
/// <param name="flags">Flags for the message.</param>
|
||||
/// <param name="indexTo">The index to send the message to. If 0, it will be sent to all players.</param>
|
||||
virtual void STDMETHODCALLTYPE SendChatMessage(const tstring_view& message, ChatColor color, int flags, PlayerIndex indexTo) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Bans the player at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The player index.</param>
|
||||
/// <returns></returns>
|
||||
virtual void STDMETHODCALLTYPE BanPlayer(int index) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Kicks the player at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The player index.</param>
|
||||
/// <param name="reason">The reason for kicking the player.</param>
|
||||
/// <returns></returns>
|
||||
virtual void STDMETHODCALLTYPE KickPlayer(int index, KickReason reason) = 0;
|
||||
|
||||
virtual PlayerInfo STDMETHODCALLTYPE GetPlayer(int index) = 0;
|
||||
/// <summary>
|
||||
/// Gets player data for the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The zero-based player index.</param>
|
||||
/// <throws>std::out_of_range</throws>
|
||||
virtual const std::shared_ptr<PlayerInfo> STDMETHODCALLTYPE GetPlayer(int index) const = 0;
|
||||
|
||||
virtual std::vector<PlayerInfo> STDMETHODCALLTYPE GetPlayers() = 0;
|
||||
/// <summary>
|
||||
/// Gets data for all players in the current game.
|
||||
/// </summary>
|
||||
virtual std::vector<std::shared_ptr<PlayerInfo>> STDMETHODCALLTYPE GetPlayers() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Toggles or increments the specified game option.
|
||||
/// Note: the behavior of this method is the same as changing an option from the F1 in-game menu.
|
||||
/// </summary>
|
||||
/// <param name="option"></param>
|
||||
/// <returns></returns>
|
||||
virtual void STDMETHODCALLTYPE ChangeGameOption(GameOption option) = 0;
|
||||
|
||||
virtual NetGameDetails STDMETHODCALLTYPE GetGameDetails() = 0;
|
||||
/// <summary>
|
||||
/// Gets details for the current game.
|
||||
/// </summary>
|
||||
virtual const std::shared_ptr<NetGameDetails> STDMETHODCALLTYPE GetGameDetails() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Modifies the settings for the current game.
|
||||
/// </summary>
|
||||
/// <param name="gameDetails">The game details.</param>
|
||||
virtual void STDMETHODCALLTYPE ChangeGameDetails(const NetGameDetails& gameDetails) = 0;
|
||||
};
|
||||
|
||||
struct DECLSPEC_UUID("{B2D67EE7-8063-488F-B3B9-E7DA675CB752}") IGameServer;
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <DataTypes.h>
|
||||
#include <IComponent.h>
|
||||
#include <string>
|
||||
|
||||
@ -14,7 +15,7 @@ inline const GUID IID_ITextLookupService = { 0x770debd3, 0x165d, 0x4340, 0x82, 0
|
||||
/// </summary>
|
||||
struct ITextLookupService : public IComponent
|
||||
{
|
||||
virtual std::string STDMETHODCALLTYPE GetLocalized(std::string_view lookup) = 0;
|
||||
virtual std::string STDMETHODCALLTYPE GetLocalized(tstring_view lookup) = 0;
|
||||
|
||||
virtual std::string STDMETHODCALLTYPE GetNetPlayerStateName(enum class NetPlayerState state) = 0;
|
||||
|
||||
|
1
ServerConsoleExample/.gitignore
vendored
Normal file
1
ServerConsoleExample/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
vcpkg_installed/
|
@ -93,6 +93,9 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnableManifest>true</VcpkgEnableManifest>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
@ -100,7 +103,7 @@
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_WINDOWS;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_DEBUG;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..\..\Sdk\Include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\Sdk\Include</AdditionalIncludeDirectories>
|
||||
<EnablePREfast>true</EnablePREfast>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
@ -154,7 +157,7 @@
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_WINDOWS;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;NDEBUG;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..\..\Sdk\Include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\Sdk\Include</AdditionalIncludeDirectories>
|
||||
<EnablePREfast>true</EnablePREfast>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
|
@ -132,7 +132,7 @@ void ServerDialog::RefreshPlayers()
|
||||
const auto& pGameServer = m_pContainer->Get<IGameServer>();
|
||||
for (const auto& player : pGameServer->GetPlayers())
|
||||
{
|
||||
if (player.host)
|
||||
if (player->host)
|
||||
{
|
||||
continue; // Skip host player
|
||||
}
|
||||
@ -140,14 +140,14 @@ void ServerDialog::RefreshPlayers()
|
||||
LVITEM item{};
|
||||
item.cColumns = NumColumns;
|
||||
item.mask = LVIF_COLUMNS | LVIF_PARAM;
|
||||
item.lParam = player.index;
|
||||
item.lParam = player->index;
|
||||
|
||||
const int index = PlayersListCtrl.InsertItem(&item);
|
||||
PlayersListCtrl.SetItemText(index, 0, player.name.c_str());
|
||||
PlayersListCtrl.SetItemText(index, 1, pTextLookupService->GetNetPlayerStateName(player.state).c_str());
|
||||
PlayersListCtrl.SetItemText(index, 2, fmt::format(_T("{0}"), player.ping).c_str());
|
||||
PlayersListCtrl.SetItemText(index, 3, fmt::format(_T("{0}"), player.score).c_str());
|
||||
PlayersListCtrl.SetItemText(index, 4, pTextLookupService->GetPlayerTeamName(player.team).c_str());
|
||||
PlayersListCtrl.SetItemText(index, 0, player->name.c_str());
|
||||
PlayersListCtrl.SetItemText(index, 1, pTextLookupService->GetNetPlayerStateName(player->state).c_str());
|
||||
PlayersListCtrl.SetItemText(index, 2, fmt::format(_T("{0}"), player->ping).c_str());
|
||||
PlayersListCtrl.SetItemText(index, 3, fmt::format(_T("{0}"), player->score).c_str());
|
||||
PlayersListCtrl.SetItemText(index, 4, pTextLookupService->GetPlayerTeamName(player->team).c_str());
|
||||
}
|
||||
|
||||
PlayersListCtrl.SetSelectionMark(savedSelection);
|
||||
@ -181,7 +181,7 @@ void ServerDialog::HandleWorldLoaded(const GameServerEvent& event)
|
||||
|
||||
const auto& pGameServer = m_pContainer->Get<IGameServer>();
|
||||
|
||||
NetGameDetails details = pGameServer->GetGameDetails();
|
||||
auto details = pGameServer->GetGameDetails();
|
||||
|
||||
// TODO: Connect to world state controls
|
||||
}
|
||||
|
7
ServerConsoleExample/vcpkg.json
Normal file
7
ServerConsoleExample/vcpkg.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "server-console",
|
||||
"version-string": "1.0.0",
|
||||
"dependencies": [
|
||||
"fmt"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user