- added finalizeSlicedFindPathPartial()

- added handleStep()/handleToggle() to samples
- changed how crowds are rendered
- added path topology optimization step
This commit is contained in:
Mikko Mononen 2010-11-07 10:56:48 +00:00
parent e5d603ac92
commit ccf401d3da
26 changed files with 2619 additions and 1964 deletions

View File

@ -140,6 +140,9 @@ void duDebugDrawCross(struct duDebugDraw* dd, const float x, const float y, cons
void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz, void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, const unsigned int* fcol); float maxx, float maxy, float maxz, const unsigned int* fcol);
void duDebugDrawCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, unsigned int col);
void duDebugDrawGridXZ(struct duDebugDraw* dd, const float ox, const float oy, const float oz, void duDebugDrawGridXZ(struct duDebugDraw* dd, const float ox, const float oy, const float oz,
const int w, const int h, const float size, const int w, const int h, const float size,
const unsigned int col, const float lineWidth); const unsigned int col, const float lineWidth);
@ -172,6 +175,9 @@ void duAppendCross(struct duDebugDraw* dd, const float x, const float y, const f
void duAppendBox(struct duDebugDraw* dd, float minx, float miny, float minz, void duAppendBox(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, const unsigned int* fcol); float maxx, float maxy, float maxz, const unsigned int* fcol);
void duAppendCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, unsigned int col);
class duDisplayList : public duDebugDraw class duDisplayList : public duDebugDraw
{ {

View File

@ -135,6 +135,16 @@ void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz,
dd->end(); dd->end();
} }
void duDebugDrawCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, unsigned int col)
{
if (!dd) return;
dd->begin(DU_DRAW_TRIS);
duAppendCylinder(dd, minx,miny,minz, maxx,maxy,maxz, col);
dd->end();
}
void duDebugDrawGridXZ(struct duDebugDraw* dd, const float ox, const float oy, const float oz, void duDebugDrawGridXZ(struct duDebugDraw* dd, const float ox, const float oy, const float oz,
const int w, const int h, const float size, const int w, const int h, const float size,
const unsigned int col, const float lineWidth) const unsigned int col, const float lineWidth)
@ -289,6 +299,58 @@ void duAppendBox(struct duDebugDraw* dd, float minx, float miny, float minz,
} }
} }
void duAppendCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, unsigned int col)
{
if (!dd) return;
static const int NUM_SEG = 16;
static float dir[NUM_SEG*2];
static bool init = false;
if (!init)
{
init = true;
for (int i = 0; i < NUM_SEG; ++i)
{
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
dir[i*2] = cosf(a);
dir[i*2+1] = sinf(a);
}
}
unsigned int col2 = duMultCol(col, 160);
const float cx = (maxx + minx)/2;
const float cz = (maxz + minz)/2;
const float rx = (maxx - minx)/2;
const float rz = (maxz - minz)/2;
for (int i = 2; i < NUM_SEG; ++i)
{
const int a = 0, b = i-1, c = i;
dd->vertex(cx+dir[a*2+0]*rx, miny, cz+dir[a*2+1]*rz, col2);
dd->vertex(cx+dir[b*2+0]*rx, miny, cz+dir[b*2+1]*rz, col2);
dd->vertex(cx+dir[c*2+0]*rx, miny, cz+dir[c*2+1]*rz, col2);
}
for (int i = 2; i < NUM_SEG; ++i)
{
const int a = 0, b = i, c = i-1;
dd->vertex(cx+dir[a*2+0]*rx, maxy, cz+dir[a*2+1]*rz, col);
dd->vertex(cx+dir[b*2+0]*rx, maxy, cz+dir[b*2+1]*rz, col);
dd->vertex(cx+dir[c*2+0]*rx, maxy, cz+dir[c*2+1]*rz, col);
}
for (int i = 0, j = NUM_SEG-1; i < NUM_SEG; j = i++)
{
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col2);
dd->vertex(cx+dir[j*2+0]*rx, miny, cz+dir[j*2+1]*rz, col2);
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col2);
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
dd->vertex(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz, col);
}
}
inline void evalArc(const float x0, const float y0, const float z0, inline void evalArc(const float x0, const float y0, const float z0,
const float dx, const float dy, const float dz, const float dx, const float dy, const float dz,

View File

@ -72,9 +72,9 @@ static void drawPolyBoundaries(duDebugDraw* dd, const dtMeshTile* tile,
} }
} }
if (con) if (con)
c = duRGBA(255,255,255,64); c = duRGBA(255,255,255,24);
else else
c = duRGBA(0,0,0,128); c = duRGBA(0,0,0,48);
} }
else else
c = duRGBA(0,48,64,32); c = duRGBA(0,48,64,32);

View File

@ -173,12 +173,22 @@ public:
// Returns: Path query state. // Returns: Path query state.
dtStatus updateSlicedFindPath(const int maxIter); dtStatus updateSlicedFindPath(const int maxIter);
// Finalizes sliced path find query. // Finalizes sliced path find query and returns found path.
// path - (out) array holding the search result. // path - (out) array holding the search result.
// pathCount - (out) Number of polygons in search result array. // pathCount - (out) Number of polygons in search result array.
// maxPath - (in) The max number of polygons the path array can hold. // maxPath - (in) The max number of polygons the path array can hold.
dtStatus finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath); dtStatus finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath);
// Finalizes partial sliced path find query and returns path to the furthest
// polygon on the existing path that was visited during the search.
// existing - (out) Array of polygons in the existing path.
// existingSize - (out) Number of polygons in existing path array.
// path - (out) array holding the search result.
// pathCount - (out) Number of polygons in search result array.
// maxPath - (in) The max number of polygons the path array can hold.
dtStatus finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
dtPolyRef* path, int* pathCount, const int maxPath);
// Finds a straight path from start to end locations within the corridor // Finds a straight path from start to end locations within the corridor
// described by the path polygons. // described by the path polygons.
// Start and end locations will be clamped on the corridor. // Start and end locations will be clamped on the corridor.

View File

@ -47,7 +47,7 @@ public:
inline void operator=(const dtNodePool&) {} inline void operator=(const dtNodePool&) {}
void clear(); void clear();
dtNode* getNode(dtPolyRef id); dtNode* getNode(dtPolyRef id);
const dtNode* findNode(dtPolyRef id) const; dtNode* findNode(dtPolyRef id);
inline unsigned int getNodeIdx(const dtNode* node) const inline unsigned int getNodeIdx(const dtNode* node) const
{ {

View File

@ -1015,6 +1015,75 @@ dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount,
return DT_SUCCESS; return DT_SUCCESS;
} }
dtStatus dtNavMeshQuery::finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
dtPolyRef* path, int* pathCount, const int maxPath)
{
*pathCount = 0;
if (existingSize == 0)
{
return DT_FAILURE;
}
if (m_query.status != DT_SUCCESS && m_query.status != DT_IN_PROGRESS)
{
// Reset query.
memset(&m_query, 0, sizeof(dtQueryData));
return DT_FAILURE;
}
int n = 0;
if (m_query.startRef == m_query.endRef)
{
// Special case: the search starts and ends at same poly.
path[n++] = m_query.startRef;
}
else
{
// Find furthest existing node that was visited.
dtNode* prev = 0;
dtNode* node = 0;
for (int i = existingSize-1; i >= 0; --i)
{
node = m_nodePool->findNode(existing[i]);
if (node)
break;
}
if (!node)
{
return DT_FAILURE;
}
// Reverse the path.
do
{
dtNode* next = m_nodePool->getNodeAtIdx(node->pidx);
node->pidx = m_nodePool->getNodeIdx(prev);
prev = node;
node = next;
}
while (node);
// Store path
node = prev;
do
{
path[n++] = node->id;
node = m_nodePool->getNodeAtIdx(node->pidx);
}
while (node && n < maxPath);
}
// Reset query.
memset(&m_query, 0, sizeof(dtQueryData));
*pathCount = n;
return DT_SUCCESS;
}
dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* endPos, dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* endPos,
const dtPolyRef* path, const int pathSize, const dtPolyRef* path, const int pathSize,

View File

@ -70,7 +70,7 @@ void dtNodePool::clear()
m_nodeCount = 0; m_nodeCount = 0;
} }
const dtNode* dtNodePool::findNode(dtPolyRef id) const dtNode* dtNodePool::findNode(dtPolyRef id)
{ {
unsigned int bucket = dtHashRef(id) & (m_hashSize-1); unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
unsigned short i = m_first[bucket]; unsigned short i = m_first[bucket];

File diff suppressed because it is too large Load Diff

View File

@ -284,14 +284,14 @@
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key> <key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
<array> <array>
<array> <array>
<integer>59</integer> <integer>52</integer>
<integer>51</integer> <integer>51</integer>
<integer>1</integer> <integer>1</integer>
<integer>0</integer> <integer>0</integer>
</array> </array>
</array> </array>
<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key> <key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
<string>{{0, 590}, {264, 660}}</string> <string>{{0, 577}, {264, 622}}</string>
</dict> </dict>
<key>PBXTopSmartGroupGIDs</key> <key>PBXTopSmartGroupGIDs</key>
<array/> <array/>
@ -301,14 +301,14 @@
<key>GeometryConfiguration</key> <key>GeometryConfiguration</key>
<dict> <dict>
<key>Frame</key> <key>Frame</key>
<string>{{0, 0}, {281, 678}}</string> <string>{{0, 0}, {281, 640}}</string>
<key>GroupTreeTableConfiguration</key> <key>GroupTreeTableConfiguration</key>
<array> <array>
<string>MainColumn</string> <string>MainColumn</string>
<real>264</real> <real>264</real>
</array> </array>
<key>RubberWindowFrame</key> <key>RubberWindowFrame</key>
<string>0 59 1278 719 0 0 1280 778 </string> <string>47 97 1200 681 0 0 1280 778 </string>
</dict> </dict>
<key>Module</key> <key>Module</key>
<string>PBXSmartGroupTreeModule</string> <string>PBXSmartGroupTreeModule</string>
@ -326,7 +326,7 @@
<key>PBXProjectModuleGUID</key> <key>PBXProjectModuleGUID</key>
<string>6B8632A30F78115100E2684A</string> <string>6B8632A30F78115100E2684A</string>
<key>PBXProjectModuleLabel</key> <key>PBXProjectModuleLabel</key>
<string>NavMeshTesterTool.cpp</string> <string>CrowdTool.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key> <key>PBXSplitModuleInNavigatorKey</key>
<dict> <dict>
<key>Split0</key> <key>Split0</key>
@ -334,29 +334,46 @@
<key>PBXProjectModuleGUID</key> <key>PBXProjectModuleGUID</key>
<string>6B8632A40F78115100E2684A</string> <string>6B8632A40F78115100E2684A</string>
<key>PBXProjectModuleLabel</key> <key>PBXProjectModuleLabel</key>
<string>NavMeshTesterTool.cpp</string> <string>CrowdTool.cpp</string>
<key>_historyCapacity</key> <key>_historyCapacity</key>
<integer>0</integer> <integer>0</integer>
<key>bookmark</key> <key>bookmark</key>
<string>6B8D56DA127AEC580077C699</string> <string>6B74B7631286BB6900262888</string>
<key>history</key> <key>history</key>
<array> <array>
<string>6B8D565F127ADB0D0077C699</string> <string>6B8D565F127ADB0D0077C699</string>
<string>6B8D566D127ADB7D0077C699</string>
<string>6B8D566F127ADB7D0077C699</string> <string>6B8D566F127ADB7D0077C699</string>
<string>6B8D56C7127AEC100077C699</string> <string>6B8D56C7127AEC100077C699</string>
<string>6B8D56C8127AEC100077C699</string>
<string>6B8D56C9127AEC100077C699</string>
<string>6B8D56CA127AEC100077C699</string>
<string>6B8D56CB127AEC100077C699</string>
<string>6B8D56CC127AEC100077C699</string>
<string>6B8D56CD127AEC100077C699</string>
<string>6B8D56CE127AEC100077C699</string>
<string>6B8D56CF127AEC100077C699</string>
<string>6B8D56D0127AEC100077C699</string>
<string>6B8D56D2127AEC100077C699</string> <string>6B8D56D2127AEC100077C699</string>
<string>6B8D56D8127AEC580077C699</string> <string>6B4DE62F12807542001CFDF4</string>
<string>6B8D56D9127AEC580077C699</string> <string>6B4DE647128079E0001CFDF4</string>
<string>6B4DE649128079E0001CFDF4</string>
<string>6B4DE64A128079E0001CFDF4</string>
<string>6B74B5F3128312AC00262888</string>
<string>6B74B5F4128312AC00262888</string>
<string>6B74B60F128312E900262888</string>
<string>6B74B623128314A500262888</string>
<string>6B74B624128314A500262888</string>
<string>6B74B626128314A500262888</string>
<string>6B74B627128314A500262888</string>
<string>6B74B628128314A500262888</string>
<string>6B74B629128314A500262888</string>
<string>6B74B62A128314A500262888</string>
<string>6B74B62B128314A500262888</string>
<string>6B74B62C128314A500262888</string>
<string>6B74B66412869CE100262888</string>
<string>6B74B66712869CE100262888</string>
<string>6B74B66F12869E3000262888</string>
<string>6B74B6BF1286AA0C00262888</string>
<string>6B74B6D81286ABC000262888</string>
<string>6B74B6FC1286AE0B00262888</string>
<string>6B74B7061286AEBD00262888</string>
<string>6B74B7071286AEBD00262888</string>
<string>6B74B7401286B7C400262888</string>
<string>6B74B75F1286BB6900262888</string>
<string>6B74B7601286BB6900262888</string>
<string>6B74B7611286BB6900262888</string>
<string>6B74B7621286BB6900262888</string>
</array> </array>
</dict> </dict>
<key>SplitCount</key> <key>SplitCount</key>
@ -370,18 +387,18 @@
<key>GeometryConfiguration</key> <key>GeometryConfiguration</key>
<dict> <dict>
<key>Frame</key> <key>Frame</key>
<string>{{0, 0}, {992, 434}}</string> <string>{{0, 0}, {914, 472}}</string>
<key>RubberWindowFrame</key> <key>RubberWindowFrame</key>
<string>0 59 1278 719 0 0 1280 778 </string> <string>47 97 1200 681 0 0 1280 778 </string>
</dict> </dict>
<key>Module</key> <key>Module</key>
<string>PBXNavigatorGroup</string> <string>PBXNavigatorGroup</string>
<key>Proportion</key> <key>Proportion</key>
<string>434pt</string> <string>472pt</string>
</dict> </dict>
<dict> <dict>
<key>Proportion</key> <key>Proportion</key>
<string>239pt</string> <string>164pt</string>
<key>Tabs</key> <key>Tabs</key>
<array> <array>
<dict> <dict>
@ -395,7 +412,7 @@
<key>GeometryConfiguration</key> <key>GeometryConfiguration</key>
<dict> <dict>
<key>Frame</key> <key>Frame</key>
<string>{{10, 27}, {992, -27}}</string> <string>{{10, 27}, {992, 49}}</string>
</dict> </dict>
<key>Module</key> <key>Module</key>
<string>XCDetailModule</string> <string>XCDetailModule</string>
@ -411,7 +428,7 @@
<key>GeometryConfiguration</key> <key>GeometryConfiguration</key>
<dict> <dict>
<key>Frame</key> <key>Frame</key>
<string>{{10, 27}, {992, 212}}</string> <string>{{10, 27}, {992, 169}}</string>
</dict> </dict>
<key>Module</key> <key>Module</key>
<string>PBXProjectFindModule</string> <string>PBXProjectFindModule</string>
@ -449,9 +466,9 @@
<key>GeometryConfiguration</key> <key>GeometryConfiguration</key>
<dict> <dict>
<key>Frame</key> <key>Frame</key>
<string>{{10, 27}, {992, 212}}</string> <string>{{10, 27}, {914, 137}}</string>
<key>RubberWindowFrame</key> <key>RubberWindowFrame</key>
<string>0 59 1278 719 0 0 1280 778 </string> <string>47 97 1200 681 0 0 1280 778 </string>
</dict> </dict>
<key>Module</key> <key>Module</key>
<string>PBXBuildResultsModule</string> <string>PBXBuildResultsModule</string>
@ -460,7 +477,7 @@
</dict> </dict>
</array> </array>
<key>Proportion</key> <key>Proportion</key>
<string>992pt</string> <string>914pt</string>
</dict> </dict>
</array> </array>
<key>Name</key> <key>Name</key>
@ -479,11 +496,11 @@
</array> </array>
<key>TableOfContents</key> <key>TableOfContents</key>
<array> <array>
<string>6B8D5625127AD44A0077C699</string> <string>6B74B5DD1283104100262888</string>
<string>1CA23ED40692098700951B8B</string> <string>1CA23ED40692098700951B8B</string>
<string>6B8D5626127AD44A0077C699</string> <string>6B74B5DE1283104100262888</string>
<string>6B8632A30F78115100E2684A</string> <string>6B8632A30F78115100E2684A</string>
<string>6B8D5627127AD44A0077C699</string> <string>6B74B5DF1283104100262888</string>
<string>1CA23EDF0692099D00951B8B</string> <string>1CA23EDF0692099D00951B8B</string>
<string>1CA23EE00692099D00951B8B</string> <string>1CA23EE00692099D00951B8B</string>
<string>1CA23EE10692099D00951B8B</string> <string>1CA23EE10692099D00951B8B</string>
@ -631,14 +648,14 @@
</array> </array>
<key>TableOfContents</key> <key>TableOfContents</key>
<array> <array>
<string>6B8D563A127AD6CA0077C699</string> <string>6B74B5FD128312AC00262888</string>
<string>1CCC7628064C1048000F2A68</string> <string>1CCC7628064C1048000F2A68</string>
<string>1CCC7629064C1048000F2A68</string> <string>1CCC7629064C1048000F2A68</string>
<string>6B8D563B127AD6CA0077C699</string> <string>6B74B5FE128312AC00262888</string>
<string>6B8D563C127AD6CA0077C699</string> <string>6B74B5FF128312AC00262888</string>
<string>6B8D563D127AD6CA0077C699</string> <string>6B74B600128312AC00262888</string>
<string>6B8D563E127AD6CA0077C699</string> <string>6B74B601128312AC00262888</string>
<string>6B8D563F127AD6CA0077C699</string> <string>6B74B602128312AC00262888</string>
</array> </array>
<key>ToolbarConfigUserDefaultsMinorVersion</key> <key>ToolbarConfigUserDefaultsMinorVersion</key>
<string>2</string> <string>2</string>
@ -670,13 +687,12 @@
<integer>5</integer> <integer>5</integer>
<key>WindowOrderList</key> <key>WindowOrderList</key>
<array> <array>
<string>6B8D56D5127AEC100077C699</string> <string>6B74B604128312AC00262888</string>
<string>6B8D56D6127AEC100077C699</string> <string>6B74B605128312AC00262888</string>
<string>6B8D56D7127AEC100077C699</string>
<string>/Users/memon/Code/recastnavigation/RecastDemo/Build/Xcode/Recast.xcodeproj</string> <string>/Users/memon/Code/recastnavigation/RecastDemo/Build/Xcode/Recast.xcodeproj</string>
</array> </array>
<key>WindowString</key> <key>WindowString</key>
<string>0 59 1278 719 0 0 1280 778 </string> <string>47 97 1200 681 0 0 1280 778 </string>
<key>WindowToolsV3</key> <key>WindowToolsV3</key>
<array> <array>
<dict> <dict>

View File

@ -45,6 +45,7 @@ public:
virtual void reset(); virtual void reset();
virtual void handleMenu(); virtual void handleMenu();
virtual void handleClick(const float* s, const float* p, bool shift); virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleToggle();
virtual void handleStep(); virtual void handleStep();
virtual void handleUpdate(const float dt); virtual void handleUpdate(const float dt);
virtual void handleRender(); virtual void handleRender();

View File

@ -138,9 +138,11 @@ public:
dtPolyRef* cornerPolys, const int maxCorners, dtPolyRef* cornerPolys, const int maxCorners,
dtNavMeshQuery* navquery, const dtQueryFilter* filter); dtNavMeshQuery* navquery, const dtQueryFilter* filter);
void optimizePath(const float* next, const float pathOptimizationRange, void optimizePathVisibility(const float* next, const float pathOptimizationRange,
dtNavMeshQuery* navquery, const dtQueryFilter* filter); dtNavMeshQuery* navquery, const dtQueryFilter* filter);
bool optimizePathTopology(dtNavMeshQuery* navquery, const dtQueryFilter* filter);
void movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter); void movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
void moveTargetPosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter); void moveTargetPosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
@ -216,6 +218,8 @@ struct Agent
float collisionQueryRange; float collisionQueryRange;
float pathOptimizationRange; float pathOptimizationRange;
float topologyOptTime;
Neighbour neis[AGENT_MAX_NEIGHBOURS]; Neighbour neis[AGENT_MAX_NEIGHBOURS];
int nneis; int nneis;
@ -243,6 +247,8 @@ enum UpdateFlags
CROWDMAN_ANTICIPATE_TURNS = 1, CROWDMAN_ANTICIPATE_TURNS = 1,
CROWDMAN_USE_VO = 2, CROWDMAN_USE_VO = 2,
CROWDMAN_DRUNK = 4, CROWDMAN_DRUNK = 4,
CROWDMAN_OPTIMIZE_VIS = 8,
CROWDMAN_OPTIMIZE_TOPO = 16,
}; };
@ -295,6 +301,9 @@ class CrowdManager
int getNeighbours(const float* pos, const float height, const float range, int getNeighbours(const float* pos, const float height, const float range,
const Agent* skip, Neighbour* result, const int maxResult); const Agent* skip, Neighbour* result, const int maxResult);
void updateTopologyOptimization(const float dt, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
void updateMoveRequest(const float dt, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
public: public:
CrowdManager(); CrowdManager();
~CrowdManager(); ~CrowdManager();
@ -309,7 +318,6 @@ public:
bool adjustMoveTarget(const int idx, dtPolyRef ref, const float* pos); bool adjustMoveTarget(const int idx, dtPolyRef ref, const float* pos);
int getActiveAgents(Agent** agents, const int maxAgents); int getActiveAgents(Agent** agents, const int maxAgents);
void updateMoveRequest(const float dt, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
void update(const float dt, unsigned int flags, dtNavMeshQuery* navquery); void update(const float dt, unsigned int flags, dtNavMeshQuery* navquery);
const dtQueryFilter* getFilter() const { return &m_filter; } const dtQueryFilter* getFilter() const { return &m_filter; }

View File

@ -44,9 +44,13 @@ class CrowdTool : public SampleTool
bool m_showVO; bool m_showVO;
bool m_showOpt; bool m_showOpt;
bool m_showGrid; bool m_showGrid;
bool m_showNodes;
bool m_showPerfGraph;
bool m_expandOptions; bool m_expandOptions;
bool m_anticipateTurns; bool m_anticipateTurns;
bool m_optimizeVis;
bool m_optimizeTopo;
bool m_useVO; bool m_useVO;
bool m_drunkMove; bool m_drunkMove;
@ -74,6 +78,7 @@ public:
virtual void reset(); virtual void reset();
virtual void handleMenu(); virtual void handleMenu();
virtual void handleClick(const float* s, const float* p, bool shift); virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleToggle();
virtual void handleStep(); virtual void handleStep();
virtual void handleUpdate(const float dt); virtual void handleUpdate(const float dt);
virtual void handleRender(); virtual void handleRender();

View File

@ -93,6 +93,7 @@ public:
virtual void reset(); virtual void reset();
virtual void handleMenu(); virtual void handleMenu();
virtual void handleClick(const float* s, const float* p, bool shift); virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleToggle();
virtual void handleStep(); virtual void handleStep();
virtual void handleUpdate(const float dt); virtual void handleUpdate(const float dt);
virtual void handleRender(); virtual void handleRender();

View File

@ -40,6 +40,7 @@ public:
virtual void reset(); virtual void reset();
virtual void handleMenu(); virtual void handleMenu();
virtual void handleClick(const float* s, const float* p, bool shift); virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleToggle();
virtual void handleStep(); virtual void handleStep();
virtual void handleUpdate(const float dt); virtual void handleUpdate(const float dt);
virtual void handleRender(); virtual void handleRender();

View File

@ -65,6 +65,7 @@ struct SampleTool
virtual void handleClick(const float* s, const float* p, bool shift) = 0; virtual void handleClick(const float* s, const float* p, bool shift) = 0;
virtual void handleRender() = 0; virtual void handleRender() = 0;
virtual void handleRenderOverlay(double* proj, double* model, int* view) = 0; virtual void handleRenderOverlay(double* proj, double* model, int* view) = 0;
virtual void handleToggle() = 0;
virtual void handleStep() = 0; virtual void handleStep() = 0;
virtual void handleUpdate(const float dt) = 0; virtual void handleUpdate(const float dt) = 0;
}; };
@ -108,6 +109,7 @@ public:
virtual void handleTools(); virtual void handleTools();
virtual void handleDebugMode(); virtual void handleDebugMode();
virtual void handleClick(const float* s, const float* p, bool shift); virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleToggle();
virtual void handleStep(); virtual void handleStep();
virtual void handleRender(); virtual void handleRender();
virtual void handleRenderOverlay(double* proj, double* model, int* view); virtual void handleRenderOverlay(double* proj, double* model, int* view);

View File

@ -44,7 +44,7 @@ public:
virtual void handleTools(); virtual void handleTools();
virtual void handleDebugMode(); virtual void handleDebugMode();
virtual void handleClick(const float* s, const float* p, bool shift); virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleStep(); virtual void handleToggle();
virtual void handleRender(); virtual void handleRender();
virtual void handleRenderOverlay(double* proj, double* model, int* view); virtual void handleRenderOverlay(double* proj, double* model, int* view);
virtual void handleMeshChanged(class InputGeom* geom); virtual void handleMeshChanged(class InputGeom* geom);

View File

@ -230,6 +230,10 @@ void ConvexVolumeTool::handleClick(const float* /*s*/, const float* p, bool shif
} }
void ConvexVolumeTool::handleToggle()
{
}
void ConvexVolumeTool::handleStep() void ConvexVolumeTool::handleStep()
{ {
} }

View File

@ -506,7 +506,7 @@ int PathCorridor::findCorners(float* cornerVerts, unsigned char* cornerFlags,
return ncorners; return ncorners;
} }
void PathCorridor::optimizePath(const float* next, const float pathOptimizationRange, void PathCorridor::optimizePathVisibility(const float* next, const float pathOptimizationRange,
dtNavMeshQuery* navquery, const dtQueryFilter* filter) dtNavMeshQuery* navquery, const dtQueryFilter* filter)
{ {
dtAssert(m_path); dtAssert(m_path);
@ -539,6 +539,31 @@ void PathCorridor::optimizePath(const float* next, const float pathOptimizationR
} }
} }
bool PathCorridor::optimizePathTopology(dtNavMeshQuery* navquery, const dtQueryFilter* filter)
{
dtAssert(m_path);
if (m_npath < 3)
return false;
static const int MAX_ITER = 32;
static const int MAX_RES = 32;
dtPolyRef res[MAX_RES];
int nres = 0;
navquery->initSlicedFindPath(m_path[0], m_path[m_npath-1], m_pos, m_target, filter);
navquery->updateSlicedFindPath(MAX_ITER);
dtStatus status = navquery->finalizeSlicedFindPathPartial(m_path, m_npath, res, &nres, MAX_RES);
if (status == DT_SUCCESS && nres > 0)
{
m_npath = mergeCorridor(m_path, m_npath, m_maxPath, res, nres);
return true;
}
return false;
}
void PathCorridor::movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter) void PathCorridor::movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
{ {
dtAssert(m_path); dtAssert(m_path);
@ -876,6 +901,7 @@ int CrowdManager::addAgent(const float* pos, const float radius, const float hei
ag->height = height; ag->height = height;
ag->collisionQueryRange = radius * 8; ag->collisionQueryRange = radius * 8;
ag->pathOptimizationRange = radius * 30; ag->pathOptimizationRange = radius * 30;
ag->topologyOptTime = 0;
ag->nneis = 0; ag->nneis = 0;
dtVset(ag->dvel, 0,0,0); dtVset(ag->dvel, 0,0,0);
@ -901,7 +927,9 @@ int CrowdManager::addAgent(const float* pos, const float radius, const float hei
void CrowdManager::removeAgent(const int idx) void CrowdManager::removeAgent(const int idx)
{ {
if (idx >= 0 && idx < MAX_AGENTS) if (idx >= 0 && idx < MAX_AGENTS)
memset(&m_agents[idx], 0, sizeof(Agent)); {
m_agents[idx].active = 0;
}
} }
bool CrowdManager::requestMoveTarget(const int idx, dtPolyRef ref, const float* pos) bool CrowdManager::requestMoveTarget(const int idx, dtPolyRef ref, const float* pos)
@ -1231,6 +1259,76 @@ void CrowdManager::updateMoveRequest(const float dt, dtNavMeshQuery* navquery, c
} }
static int addToOptQueue(Agent* newag, Agent** agents, const int nagents, const int maxAgents)
{
// Insert neighbour based on greatest time.
int slot = 0;
if (!nagents)
{
slot = nagents;
}
else if (newag->topologyOptTime <= agents[nagents-1]->topologyOptTime)
{
if (nagents >= maxAgents)
return nagents;
slot = nagents;
}
else
{
int i;
for (i = 0; i < nagents; ++i)
if (newag->topologyOptTime >= agents[i]->topologyOptTime)
break;
const int tgt = i+1;
const int n = dtMin(nagents-i, maxAgents-tgt);
dtAssert(tgt+n <= maxAgents);
if (n > 0)
memmove(&agents[tgt], &agents[i], sizeof(Agent*)*n);
slot = i;
}
agents[slot] = newag;
return dtMin(nagents+1, maxAgents);
}
void CrowdManager::updateTopologyOptimization(const float dt, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
{
Agent* agents[MAX_AGENTS];
int nagents = getActiveAgents(agents, MAX_AGENTS);
if (!nagents)
return;
const float OPT_TIME_THR = 0.5f; // seconds
const int OPT_MAX_AGENTS = 1;
Agent* queue[OPT_MAX_AGENTS];
int nqueue = 0;
for (int i = 0; i < nagents; ++i)
{
Agent* ag = agents[i];
ag->topologyOptTime += dt;
if (ag->topologyOptTime >= OPT_TIME_THR)
{
nqueue = addToOptQueue(ag, queue, nqueue, OPT_MAX_AGENTS);
}
}
for (int i = 0; i < nqueue; ++i)
{
Agent* ag = queue[i];
ag->corridor.optimizePathTopology(navquery, filter);
ag->topologyOptTime = 0;
}
}
void CrowdManager::update(const float dt, unsigned int flags, dtNavMeshQuery* navquery) void CrowdManager::update(const float dt, unsigned int flags, dtNavMeshQuery* navquery)
{ {
m_sampleCount = 0; m_sampleCount = 0;
@ -1251,6 +1349,10 @@ void CrowdManager::update(const float dt, unsigned int flags, dtNavMeshQuery* na
// Update async move request and path finder. // Update async move request and path finder.
updateMoveRequest(dt, navquery, &m_filter); updateMoveRequest(dt, navquery, &m_filter);
// Optimize path topology.
if (flags & CROWDMAN_OPTIMIZE_TOPO)
updateTopologyOptimization(dt, navquery, &m_filter);
// Register agents to proximity grid. // Register agents to proximity grid.
m_grid.clear(); m_grid.clear();
for (int i = 0; i < nagents; ++i) for (int i = 0; i < nagents; ++i)
@ -1283,12 +1385,12 @@ void CrowdManager::update(const float dt, unsigned int flags, dtNavMeshQuery* na
// Check to see if the corner after the next corner is directly visible, // Check to see if the corner after the next corner is directly visible,
// and short cut to there. // and short cut to there.
if (ag->ncorners > 0) if ((flags & CROWDMAN_OPTIMIZE_VIS) && ag->ncorners > 0)
{ {
const float* target = &ag->cornerVerts[dtMin(1,ag->ncorners-1)*3]; const float* target = &ag->cornerVerts[dtMin(1,ag->ncorners-1)*3];
dtVcopy(ag->opts, ag->corridor.getPos()); dtVcopy(ag->opts, ag->corridor.getPos());
dtVcopy(ag->opte, target); dtVcopy(ag->opte, target);
ag->corridor.optimizePath(target, ag->pathOptimizationRange, navquery, &m_filter); ag->corridor.optimizePathVisibility(target, ag->pathOptimizationRange, navquery, &m_filter);
} }
else else
{ {

View File

@ -95,7 +95,7 @@ CrowdTool::CrowdTool() :
m_oldFlags(0), m_oldFlags(0),
m_targetRef(0), m_targetRef(0),
m_expandDebugDraw(false), m_expandDebugDraw(false),
m_showLabels(true), m_showLabels(false),
m_showCorners(false), m_showCorners(false),
m_showTargets(false), m_showTargets(false),
m_showCollisionSegments(false), m_showCollisionSegments(false),
@ -103,8 +103,12 @@ CrowdTool::CrowdTool() :
m_showVO(false), m_showVO(false),
m_showOpt(false), m_showOpt(false),
m_showGrid(false), m_showGrid(false),
m_showNodes(false),
m_showPerfGraph(false),
m_expandOptions(true), m_expandOptions(true),
m_anticipateTurns(true), m_anticipateTurns(true),
m_optimizeVis(true),
m_optimizeTopo(true),
m_useVO(true), m_useVO(true),
m_drunkMove(false), m_drunkMove(false),
m_run(true), m_run(true),
@ -168,6 +172,10 @@ void CrowdTool::handleMenu()
if (m_expandOptions) if (m_expandOptions)
{ {
imguiIndent(); imguiIndent();
if (imguiCheck("Optimize Visibility", m_optimizeVis))
m_optimizeVis = !m_optimizeVis;
if (imguiCheck("Optimize Topology", m_optimizeTopo))
m_optimizeTopo = !m_optimizeTopo;
if (imguiCheck("Anticipate Turns", m_anticipateTurns)) if (imguiCheck("Anticipate Turns", m_anticipateTurns))
m_anticipateTurns = !m_anticipateTurns; m_anticipateTurns = !m_anticipateTurns;
if (imguiCheck("Use VO", m_useVO)) if (imguiCheck("Use VO", m_useVO))
@ -199,6 +207,10 @@ void CrowdTool::handleMenu()
m_showOpt = !m_showOpt; m_showOpt = !m_showOpt;
if (imguiCheck("Show Prox Grid", m_showGrid)) if (imguiCheck("Show Prox Grid", m_showGrid))
m_showGrid = !m_showGrid; m_showGrid = !m_showGrid;
if (imguiCheck("Show Nodes", m_showNodes))
m_showNodes = !m_showNodes;
if (imguiCheck("Show Perf Graph", m_showPerfGraph))
m_showPerfGraph = !m_showPerfGraph;
imguiUnindent(); imguiUnindent();
} }
} }
@ -280,6 +292,10 @@ void CrowdTool::handleClick(const float* s, const float* p, bool shift)
} }
void CrowdTool::handleStep() void CrowdTool::handleStep()
{
}
void CrowdTool::handleToggle()
{ {
m_run = !m_run; m_run = !m_run;
} }
@ -298,6 +314,10 @@ void CrowdTool::handleUpdate(const float dt)
flags |= CROWDMAN_USE_VO; flags |= CROWDMAN_USE_VO;
if (m_drunkMove) if (m_drunkMove)
flags |= CROWDMAN_DRUNK; flags |= CROWDMAN_DRUNK;
if (m_optimizeVis)
flags |= CROWDMAN_OPTIMIZE_VIS;
if (m_optimizeTopo)
flags |= CROWDMAN_OPTIMIZE_TOPO;
m_crowd.update(dt, flags, m_sample->getNavMeshQuery()); m_crowd.update(dt, flags, m_sample->getNavMeshQuery());
@ -316,31 +336,74 @@ void CrowdTool::handleRender()
if (!nmesh) if (!nmesh)
return; return;
if (m_targetRef) dtNavMeshQuery* navquery = m_sample->getNavMeshQuery();
duDebugDrawCross(&dd, m_targetPos[0],m_targetPos[1]+0.1f,m_targetPos[2], s, duRGBA(0,0,0,128), 2.0f);
if (m_showNodes)
{
if (navquery)
duDebugDrawNavMeshNodes(&dd, *navquery);
}
dd.depthMask(false);
// Draw paths
if (m_showPath)
{
for (int i = 0; i < m_crowd.getAgentCount(); ++i) for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{ {
const Agent* ag = m_crowd.getAgent(i); const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue; if (!ag->active) continue;
const float height = ag->height;
const float radius = ag->radius;
const float* pos = ag->npos;
const float* target = ag->corridor.getTarget();
const float* vel = ag->vel;
const float* dvel = ag->dvel;
dd.depthMask(false);
if (m_showPath)
{
const dtPolyRef* path = ag->corridor.getPath(); const dtPolyRef* path = ag->corridor.getPath();
const int npath = ag->corridor.getPathCount(); const int npath = ag->corridor.getPathCount();
for (int i = 0; i < npath; ++i) for (int i = 0; i < npath; ++i)
duDebugDrawNavMeshPoly(&dd, *nmesh, path[i], duRGBA(0,0,0,64)); duDebugDrawNavMeshPoly(&dd, *nmesh, path[i], duRGBA(0,0,0,32));
} }
}
if (m_targetRef)
duDebugDrawCross(&dd, m_targetPos[0],m_targetPos[1]+0.1f,m_targetPos[2], s, duRGBA(255,255,255,192), 2.0f);
// Occupancy grid.
if (m_showGrid)
{
float gridy = -FLT_MAX;
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float* pos = ag->corridor.getPos();
gridy = dtMax(gridy, pos[1]);
}
gridy += 1.0f;
dd.begin(DU_DRAW_QUADS);
const ProximityGrid* grid = m_crowd.getGrid();
const int* bounds = grid->getBounds();
const float cs = grid->getCellSize();
for (int y = bounds[1]; y <= bounds[3]; ++y)
{
for (int x = bounds[0]; x <= bounds[2]; ++x)
{
const int count = grid->getItemCountAt(x,y);
if (!count) continue;
unsigned int col = duRGBA(128,0,0,dtMin(count*40,255));
dd.vertex(x*cs, gridy, y*cs, col);
dd.vertex(x*cs, gridy, y*cs+cs, col);
dd.vertex(x*cs+cs, gridy, y*cs+cs, col);
dd.vertex(x*cs+cs, gridy, y*cs, col);
}
}
dd.end();
}
// Trail
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float* pos = ag->npos;
dd.begin(DU_DRAW_LINES,3.0f); dd.begin(DU_DRAW_LINES,3.0f);
float prev[3], preva = 1; float prev[3], preva = 1;
@ -357,12 +420,17 @@ void CrowdTool::handleRender()
} }
dd.end(); dd.end();
if (m_showTargets)
{
duDebugDrawArc(&dd, pos[0], pos[1], pos[2], target[0], target[1], target[2],
0.25f, 0, 0.4f, duRGBA(0,0,0,128), 1.0f);
} }
// Corners & co
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float radius = ag->radius;
const float* pos = ag->npos;
if (m_showCorners) if (m_showCorners)
{ {
if (ag->ncorners) if (ag->ncorners)
@ -372,14 +440,14 @@ void CrowdTool::handleRender()
{ {
const float* va = j == 0 ? pos : &ag->cornerVerts[(j-1)*3]; const float* va = j == 0 ? pos : &ag->cornerVerts[(j-1)*3];
const float* vb = &ag->cornerVerts[j*3]; const float* vb = &ag->cornerVerts[j*3];
dd.vertex(va[0],va[1]+radius,va[2], duRGBA(128,0,0,64)); dd.vertex(va[0],va[1]+radius,va[2], duRGBA(128,0,0,192));
dd.vertex(vb[0],vb[1]+radius,vb[2], duRGBA(128,0,0,64)); dd.vertex(vb[0],vb[1]+radius,vb[2], duRGBA(128,0,0,192));
} }
dd.end(); dd.end();
if (m_anticipateTurns) if (m_anticipateTurns)
{ {
/* float dvel[3], pos[3]; /* float dvel[3], pos[3];
calcSmoothSteerDirection(ag->pos, ag->cornerVerts, ag->ncorners, dvel); calcSmoothSteerDirection(ag->pos, ag->cornerVerts, ag->ncorners, dvel);
pos[0] = ag->pos[0] + dvel[0]; pos[0] = ag->pos[0] + dvel[0];
pos[1] = ag->pos[1] + dvel[1]; pos[1] = ag->pos[1] + dvel[1];
@ -429,6 +497,48 @@ void CrowdTool::handleRender()
dd.vertex(ag->opte[0],ag->opte[1]+0.3f,ag->opte[2], duRGBA(0,128,0,192)); dd.vertex(ag->opte[0],ag->opte[1]+0.3f,ag->opte[2], duRGBA(0,128,0,192));
dd.end(); dd.end();
} }
}
// Agent cylinders.
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float radius = ag->radius;
const float* pos = ag->npos;
duDebugDrawCircle(&dd, pos[0], pos[1], pos[2], radius, duRGBA(0,0,0,32), 2.0f);
}
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float height = ag->height;
const float radius = ag->radius;
const float* pos = ag->npos;
duDebugDrawCylinder(&dd, pos[0]-radius, pos[1]+radius*0.1f, pos[2]-radius,
pos[0]+radius, pos[1]+height, pos[2]+radius,
duRGBA(220,220,220,128));
}
// Velocity stuff.
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float radius = ag->radius;
const float height = ag->height;
const float* pos = ag->npos;
const float* vel = ag->vel;
const float* dvel = ag->dvel;
duDebugDrawCircle(&dd, pos[0], pos[1]+height, pos[2], radius, duRGBA(220,220,220,192), 2.0f);
if (m_showVO) if (m_showVO)
{ {
@ -458,138 +568,31 @@ void CrowdTool::handleRender()
} }
duDebugDrawArrow(&dd, pos[0],pos[1]+height,pos[2], duDebugDrawArrow(&dd, pos[0],pos[1]+height,pos[2],
pos[0]+vel[0],pos[1]+height+vel[1],pos[2]+vel[2], pos[0]+dvel[0],pos[1]+height+dvel[1],pos[2]+dvel[2],
0.0f, 0.4f, duRGBA(0,0,0,192), 2.0f);
duDebugDrawArrow(&dd, pos[0],pos[1]+height-0.1f,pos[2],
pos[0]+dvel[0],pos[1]+height-0.1f+dvel[1],pos[2]+dvel[2],
0.0f, 0.4f, duRGBA(0,192,255,192), 1.0f); 0.0f, 0.4f, duRGBA(0,192,255,192), 1.0f);
duDebugDrawCylinderWire(&dd, pos[0]-radius, pos[1]+radius*0.1f, pos[2]-radius, duDebugDrawArrow(&dd, pos[0],pos[1]+height,pos[2],
pos[0]+radius, pos[1]+height, pos[2]+radius, pos[0]+vel[0],pos[1]+height+vel[1],pos[2]+vel[2],
duRGBA(0,192,255,255), 3.0f); 0.0f, 0.4f, duRGBA(0,0,0,192), 2.0f);
dd.depthMask(true);
} }
if (m_showGrid) // Targets
{
float gridy = -FLT_MAX;
for (int i = 0; i < m_crowd.getAgentCount(); ++i) for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{ {
const Agent* ag = m_crowd.getAgent(i); const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue; if (!ag->active) continue;
const float* pos = ag->corridor.getPos();
gridy = dtMax(gridy, pos[1]);
}
gridy += 1.0f;
dd.depthMask(false); const float* pos = ag->npos;
dd.begin(DU_DRAW_QUADS); const float* target = ag->corridor.getTarget();
const ProximityGrid* grid = m_crowd.getGrid();
const int* bounds = grid->getBounds();
const float cs = grid->getCellSize();
for (int y = bounds[1]; y <= bounds[3]; ++y)
{
for (int x = bounds[0]; x <= bounds[2]; ++x)
{
const int count = grid->getItemCountAt(x,y);
if (!count) continue;
unsigned int col = duRGBA(128,0,0,dtMin(count*40,255));
dd.vertex(x*cs, gridy, y*cs, col);
dd.vertex(x*cs, gridy, y*cs+cs, col);
dd.vertex(x*cs+cs, gridy, y*cs+cs, col);
dd.vertex(x*cs+cs, gridy, y*cs, col);
}
}
dd.end();
dd.depthMask(true);
}
if (m_showTargets)
/*
for (int i = 0; i < m_form.npolys; ++i)
{ {
duDebugDrawNavMeshPoly(&dd, *nmesh, m_form.polys[i], duRGBA(255,255,255,32)); duDebugDrawArc(&dd, pos[0], pos[1], pos[2], target[0], target[1], target[2],
0.25f, 0, 0.4f, duRGBA(0,0,0,128), 1.0f);
} }
dd.depthMask(false);
dd.begin(DU_DRAW_POINTS, 4.0f);
for (int i = 0; i < m_form.nsegs; ++i)
{
const FormationSeg* seg = &m_form.segs[i];
for (int j = 0; j < seg->nints-1; ++j)
{
if (seg->ints[j].inside == 0) continue;
const float u0 = seg->ints[j].u;
const float u1 = seg->ints[j+1].u;
float ia[3], ib[3];
dtVlerp(ia, seg->p,seg->q, u0);
dtVlerp(ib, seg->p,seg->q, u1);
dd.vertex(ia,duRGBA(128,0,0,192));
dd.vertex(ib,duRGBA(128,0,0,192));
}
}
dd.end();
dd.begin(DU_DRAW_LINES, 2.0f);
for (int i = 0; i < m_form.nsegs; ++i)
{
const FormationSeg* seg = &m_form.segs[i];
dd.vertex(seg->p,duRGBA(255,255,255,128));
dd.vertex(seg->q,duRGBA(255,255,255,128));
for (int j = 0; j < seg->nints-1; ++j)
{
if (seg->ints[j].inside == 0) continue;
const float u0 = seg->ints[j].u;
const float u1 = seg->ints[j+1].u;
float ia[3], ib[3];
dtVlerp(ia, seg->p,seg->q, u0);
dtVlerp(ib, seg->p,seg->q, u1);
dd.vertex(ia,duRGBA(128,0,0,192));
dd.vertex(ib,duRGBA(128,0,0,192));
}
}
dd.end();
{
const float r = m_sample->getAgentRadius();
dd.begin(DU_DRAW_LINES, 2.0f);
for (int i = 0; i < m_form.nsegs; ++i)
{
const FormationSeg* seg = &m_form.segs[i];
dd.vertex(seg->p,duRGBA(255,255,255,128));
dd.vertex(seg->q,duRGBA(255,255,255,128));
for (int j = 0; j < seg->nints-1; ++j)
{
if (seg->ints[j].inside == 0) continue;
const float u0 = seg->ints[j].u;
const float u1 = seg->ints[j+1].u;
float ia[3], ib[3];
dtVlerp(ia, seg->p,seg->q, u0);
dtVlerp(ib, seg->p,seg->q, u1);
const float spacing = r*2.5f;
float delta[3];
dtVsub(delta, ib,ia);
float d = dtVlen(delta);
int np = (int)floorf(d/spacing);
for (int k = 0; k < np; ++k)
{
float pos[3];
dtVmad(pos, ia, delta, (float)(k+0.5f)/(float)np);
dd.vertex(pos[0],pos[1]-1,pos[2],duRGBA(128,0,0,192));
dd.vertex(pos[0],pos[1]+2,pos[2],duRGBA(128,0,0,192));
}
}
}
dd.end();
} }
dd.depthMask(true); dd.depthMask(true);
*/
} }
void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view) void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view)
@ -622,6 +625,8 @@ void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view)
} }
} }
if (m_showPerfGraph)
{
GraphParams gp; GraphParams gp;
gp.setRect(300, 10, 500, 200, 8); gp.setRect(300, 10, 500, 200, 8);
gp.setValueRange(0.0f, 2.0f, 4, "ms"); gp.setValueRange(0.0f, 2.0f, 4, "ms");
@ -633,4 +638,5 @@ void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view)
gp.setRect(300, 10, 500, 50, 8); gp.setRect(300, 10, 500, 50, 8);
gp.setValueRange(0.0f, 2000.0f, 1, "0"); gp.setValueRange(0.0f, 2000.0f, 1, "0");
drawGraph(&gp, &m_crowdSampleCount, 0, "Sample Count", duRGBA(255,255,255,255)); drawGraph(&gp, &m_crowdSampleCount, 0, "Sample Count", duRGBA(255,255,255,255));
}
} }

View File

@ -321,6 +321,10 @@ void NavMeshTesterTool::handleClick(const float* /*s*/, const float* p, bool shi
} }
void NavMeshTesterTool::handleStep() void NavMeshTesterTool::handleStep()
{
}
void NavMeshTesterTool::handleToggle()
{ {
// TODO: merge separate to a path iterator. Use same code in recalc() too. // TODO: merge separate to a path iterator. Use same code in recalc() too.
if (m_toolMode != TOOLMODE_PATHFIND_FOLLOW) if (m_toolMode != TOOLMODE_PATHFIND_FOLLOW)

View File

@ -132,6 +132,10 @@ void OffMeshConnectionTool::handleClick(const float* /*s*/, const float* p, bool
} }
void OffMeshConnectionTool::handleToggle()
{
}
void OffMeshConnectionTool::handleStep() void OffMeshConnectionTool::handleStep()
{ {
} }

View File

@ -176,6 +176,12 @@ void Sample::handleClick(const float* s, const float* p, bool shift)
m_tool->handleClick(s, p, shift); m_tool->handleClick(s, p, shift);
} }
void Sample::handleToggle()
{
if (m_tool)
m_tool->handleToggle();
}
void Sample::handleStep() void Sample::handleStep()
{ {
if (m_tool) if (m_tool)

View File

@ -357,10 +357,10 @@ void Sample_Debug::handleClick(const float* s, const float* p, bool shift)
m_tool->handleClick(s, p, shift); m_tool->handleClick(s, p, shift);
} }
void Sample_Debug::handleStep() void Sample_Debug::handleToggle()
{ {
if (m_tool) if (m_tool)
m_tool->handleStep(); m_tool->handleToggle();
} }
bool Sample_Debug::handleBuild() bool Sample_Debug::handleBuild()

View File

@ -86,6 +86,8 @@ public:
m_sample->setHighlightedTile(m_hitPos); m_sample->setHighlightedTile(m_hitPos);
} }
virtual void handleToggle() {}
virtual void handleStep() {} virtual void handleStep() {}
virtual void handleUpdate(const float /*dt*/) {} virtual void handleUpdate(const float /*dt*/) {}

View File

@ -125,6 +125,8 @@ public:
} }
} }
virtual void handleToggle() {}
virtual void handleStep() {} virtual void handleStep() {}
virtual void handleUpdate(const float /*dt*/) {} virtual void handleUpdate(const float /*dt*/) {}

View File

@ -204,14 +204,19 @@ int main(int /*argc*/, char** /*argv*/)
else if (event.key.keysym.sym == SDLK_SPACE) else if (event.key.keysym.sym == SDLK_SPACE)
{ {
if (sample) if (sample)
sample->handleStep(); sample->handleToggle();
} }
else if (event.key.keysym.sym == SDLK_1) else if (event.key.keysym.sym == SDLK_1)
{
if (sample)
sample->handleStep();
}
else if (event.key.keysym.sym == SDLK_9)
{ {
if (geom) if (geom)
geom->save("geomset.txt"); geom->save("geomset.txt");
} }
else if (event.key.keysym.sym == SDLK_2) else if (event.key.keysym.sym == SDLK_0)
{ {
delete geom; delete geom;
geom = new InputGeom; geom = new InputGeom;