diff --git a/DebugUtils/Include/DetourDebugDraw.h b/DebugUtils/Include/DetourDebugDraw.h index d076db0..34d93e1 100755 --- a/DebugUtils/Include/DetourDebugDraw.h +++ b/DebugUtils/Include/DetourDebugDraw.h @@ -38,6 +38,11 @@ void duDebugDrawNavMeshPortals(struct duDebugDraw* dd, const dtNavMesh& mesh); void duDebugDrawNavMeshPolysWithFlags(struct duDebugDraw* dd, const dtNavMesh& mesh, const unsigned short polyFlags, const unsigned int col); void duDebugDrawNavMeshPoly(struct duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col); -void duDebugDrawTileCacheLayer(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch); +void duDebugDrawTileCacheLayerAreas(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch); +void duDebugDrawTileCacheLayerRegions(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch); +void duDebugDrawTileCacheContours(duDebugDraw* dd, const struct dtTileCacheContourSet& lcset, + const float* orig, const float cs, const float ch); +void duDebugDrawTileCachePolyMesh(duDebugDraw* dd, const struct dtTileCachePolyMesh& lmesh, + const float* orig, const float cs, const float ch); #endif // DETOURDEBUGDRAW_H \ No newline at end of file diff --git a/DebugUtils/Source/DetourDebugDraw.cpp b/DebugUtils/Source/DetourDebugDraw.cpp index f9af0e8..b79ea80 100755 --- a/DebugUtils/Source/DetourDebugDraw.cpp +++ b/DebugUtils/Source/DetourDebugDraw.cpp @@ -493,7 +493,48 @@ void duDebugDrawNavMeshPoly(duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef re } -void duDebugDrawTileCacheLayer(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch) +static void debugDrawTileCachePortals(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch) +{ + const int w = (int)layer.header->width; + const int h = (int)layer.header->height; + const float* bmin = layer.header->bmin; + + // Portals + unsigned int pcol = duRGBA(255,255,255,255); + + const int segs[4*4] = {0,0,0,1, 0,1,1,1, 1,1,1,0, 1,0,0,0}; + + // Layer portals + dd->begin(DU_DRAW_LINES, 2.0f); + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const int idx = x+y*w; + const int h = (int)layer.heights[idx]; + if (h == 0xff) continue; + + for (int dir = 0; dir < 4; ++dir) + { + if (layer.cons[idx] & (1<<(dir+4))) + { + const int* seg = &segs[dir*4]; + const float ax = bmin[0] + (x+seg[0])*cs; + const float ay = bmin[1] + (h+2)*ch; + const float az = bmin[2] + (y+seg[1])*cs; + const float bx = bmin[0] + (x+seg[2])*cs; + const float by = bmin[1] + (h+2)*ch; + const float bz = bmin[2] + (y+seg[3])*cs; + dd->vertex(ax, ay, az, pcol); + dd->vertex(bx, by, bz, pcol); + } + } + } + } + dd->end(); +} + +void duDebugDrawTileCacheLayerAreas(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch) { const int w = (int)layer.header->width; const int h = (int)layer.header->height; @@ -544,13 +585,31 @@ void duDebugDrawTileCacheLayer(struct duDebugDraw* dd, const dtTileCacheLayer& l } dd->end(); - // Portals - unsigned int pcol = duRGBA(255,255,255,255); + debugDrawTileCachePortals(dd, layer, cs, ch); +} + +void duDebugDrawTileCacheLayerRegions(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch) +{ + const int w = (int)layer.header->width; + const int h = (int)layer.header->height; + const float* bmin = layer.header->bmin; + const float* bmax = layer.header->bmax; + const int idx = layer.header->tlayer; - const int segs[4*4] = {0,0,0,1, 0,1,1,1, 1,1,1,0, 1,0,0,0}; + unsigned int color = duIntToCol(idx+1, 255); - // Layer portals - dd->begin(DU_DRAW_LINES, 2.0f); + // Layer bounds + float lbmin[3], lbmax[3]; + lbmin[0] = bmin[0] + layer.header->minx*cs; + lbmin[1] = bmin[1]; + lbmin[2] = bmin[2] + layer.header->miny*cs; + lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs; + lbmax[1] = bmax[1]; + lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs; + duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f); + + // Layer height + dd->begin(DU_DRAW_QUADS); for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) @@ -558,23 +617,255 @@ void duDebugDrawTileCacheLayer(struct duDebugDraw* dd, const dtTileCacheLayer& l const int idx = x+y*w; const int h = (int)layer.heights[idx]; if (h == 0xff) continue; + const unsigned char reg = layer.regs[idx]; - for (int dir = 0; dir < 4; ++dir) + unsigned int col = duLerpCol(color, duIntToCol(reg, 255), 192); + + const float fx = bmin[0] + x*cs; + const float fy = bmin[1] + (h+1)*ch; + const float fz = bmin[2] + y*cs; + + dd->vertex(fx, fy, fz, col); + dd->vertex(fx, fy, fz+cs, col); + dd->vertex(fx+cs, fy, fz+cs, col); + dd->vertex(fx+cs, fy, fz, col); + } + } + dd->end(); + + debugDrawTileCachePortals(dd, layer, cs, ch); +} + + + + +/*struct dtTileCacheContour +{ + int nverts; + unsigned char* verts; + unsigned char reg; + unsigned char area; +}; + +struct dtTileCacheContourSet +{ + int nconts; + dtTileCacheContour* conts; +};*/ + +void duDebugDrawTileCacheContours(duDebugDraw* dd, const struct dtTileCacheContourSet& lcset, + const float* orig, const float cs, const float ch) +{ + if (!dd) return; + + const unsigned char a = 255;// (unsigned char)(alpha*255.0f); + + const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1}; + + dd->begin(DU_DRAW_LINES, 2.0f); + + for (int i = 0; i < lcset.nconts; ++i) + { + const dtTileCacheContour& c = lcset.conts[i]; + unsigned int color = 0; + + color = duIntToCol(i, a); + + for (int j = 0; j < c.nverts; ++j) + { + const int k = (j+1) % c.nverts; + const unsigned char* va = &c.verts[j*4]; + const unsigned char* vb = &c.verts[k*4]; + const float ax = orig[0] + va[0]*cs; + const float ay = orig[1] + (va[1]+1+(i&1))*ch; + const float az = orig[2] + va[2]*cs; + const float bx = orig[0] + vb[0]*cs; + const float by = orig[1] + (vb[1]+1+(i&1))*ch; + const float bz = orig[2] + vb[2]*cs; + unsigned int col = color; + if ((va[3] & 0xf) != 0xf) { - if (layer.cons[idx] & (1<<(dir+4))) - { - const int* seg = &segs[dir*4]; - const float ax = bmin[0] + (x+seg[0])*cs; - const float ay = bmin[1] + (h+2)*ch; - const float az = bmin[2] + (y+seg[1])*cs; - const float bx = bmin[0] + (x+seg[2])*cs; - const float by = bmin[1] + (h+2)*ch; - const float bz = bmin[2] + (y+seg[3])*cs; - dd->vertex(ax, ay, az, pcol); - dd->vertex(bx, by, bz, pcol); - } + // Portal segment + col = duRGBA(255,255,255,128); + int d = va[3] & 0xf; + + const float cx = (ax+bx)*0.5f; + const float cy = (ay+by)*0.5f; + const float cz = (az+bz)*0.5f; + + const float dx = cx + offs[d*2+0]*2*cs; + const float dy = cy; + const float dz = cz + offs[d*2+1]*2*cs; + + dd->vertex(cx,cy,cz,duRGBA(255,0,0,255)); + dd->vertex(dx,dy,dz,duRGBA(255,0,0,255)); } + + duAppendArrow(dd, ax,ay,az, bx,by,bz, 0.0f, cs*0.5f, col); + } + } + dd->end(); + + dd->begin(DU_DRAW_POINTS, 4.0f); + + for (int i = 0; i < lcset.nconts; ++i) + { + const dtTileCacheContour& c = lcset.conts[i]; + unsigned int color = 0; + + for (int j = 0; j < c.nverts; ++j) + { + const unsigned char* va = &c.verts[j*4]; + + color = duDarkenCol(duIntToCol(i, a)); + if (va[3] & 0x80) + { + // Border vertex + color = duRGBA(255,0,0,255); + } + + float fx = orig[0] + va[0]*cs; + float fy = orig[1] + (va[1]+1+(i&1))*ch; + float fz = orig[2] + va[2]*cs; + dd->vertex(fx,fy,fz, color); } } dd->end(); } + +void duDebugDrawTileCachePolyMesh(duDebugDraw* dd, const struct dtTileCachePolyMesh& lmesh, + const float* orig, const float cs, const float ch) +{ + if (!dd) return; + + const int nvp = lmesh.nvp; + + const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1}; + + dd->begin(DU_DRAW_TRIS); + + for (int i = 0; i < lmesh.npolys; ++i) + { + const unsigned short* p = &lmesh.polys[i*nvp*2]; + + unsigned int color; + if (lmesh.areas[i] == DT_TILECACHE_WALKABLE_AREA) + color = duRGBA(0,192,255,64); + else if (lmesh.areas[i] == DT_TILECACHE_NULL_AREA) + color = duRGBA(0,0,0,64); + else + color = duIntToCol(lmesh.areas[i], 255); + + unsigned short vi[3]; + for (int j = 2; j < nvp; ++j) + { + if (p[j] == DT_TILECACHE_NULL_IDX) break; + vi[0] = p[0]; + vi[1] = p[j-1]; + vi[2] = p[j]; + for (int k = 0; k < 3; ++k) + { + const unsigned short* v = &lmesh.verts[vi[k]*3]; + const float x = orig[0] + v[0]*cs; + const float y = orig[1] + (v[1]+1)*ch; + const float z = orig[2] + v[2]*cs; + dd->vertex(x,y,z, color); + } + } + } + dd->end(); + + // Draw neighbours edges + const unsigned int coln = duRGBA(0,48,64,32); + dd->begin(DU_DRAW_LINES, 1.5f); + for (int i = 0; i < lmesh.npolys; ++i) + { + const unsigned short* p = &lmesh.polys[i*nvp*2]; + for (int j = 0; j < nvp; ++j) + { + if (p[j] == DT_TILECACHE_NULL_IDX) break; + if (p[nvp+j] & 0x8000) continue; + const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1; + int vi[2] = {p[j], p[nj]}; + + for (int k = 0; k < 2; ++k) + { + const unsigned short* v = &lmesh.verts[vi[k]*3]; + const float x = orig[0] + v[0]*cs; + const float y = orig[1] + (v[1]+1)*ch + 0.1f; + const float z = orig[2] + v[2]*cs; + dd->vertex(x, y, z, coln); + } + } + } + dd->end(); + + // Draw boundary edges + const unsigned int colb = duRGBA(0,48,64,220); + dd->begin(DU_DRAW_LINES, 2.5f); + for (int i = 0; i < lmesh.npolys; ++i) + { + const unsigned short* p = &lmesh.polys[i*nvp*2]; + for (int j = 0; j < nvp; ++j) + { + if (p[j] == DT_TILECACHE_NULL_IDX) break; + if ((p[nvp+j] & 0x8000) == 0) continue; + const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1; + int vi[2] = {p[j], p[nj]}; + + unsigned int col = colb; + if ((p[nvp+j] & 0xf) != 0xf) + { + const unsigned short* va = &lmesh.verts[vi[0]*3]; + const unsigned short* vb = &lmesh.verts[vi[1]*3]; + + const float ax = orig[0] + va[0]*cs; + const float ay = orig[1] + (va[1]+1+(i&1))*ch; + const float az = orig[2] + va[2]*cs; + const float bx = orig[0] + vb[0]*cs; + const float by = orig[1] + (vb[1]+1+(i&1))*ch; + const float bz = orig[2] + vb[2]*cs; + + const float cx = (ax+bx)*0.5f; + const float cy = (ay+by)*0.5f; + const float cz = (az+bz)*0.5f; + + int d = p[nvp+j] & 0xf; + + const float dx = cx + offs[d*2+0]*2*cs; + const float dy = cy; + const float dz = cz + offs[d*2+1]*2*cs; + + dd->vertex(cx,cy,cz,duRGBA(255,0,0,255)); + dd->vertex(dx,dy,dz,duRGBA(255,0,0,255)); + + col = duRGBA(255,255,255,128); + } + + for (int k = 0; k < 2; ++k) + { + const unsigned short* v = &lmesh.verts[vi[k]*3]; + const float x = orig[0] + v[0]*cs; + const float y = orig[1] + (v[1]+1)*ch + 0.1f; + const float z = orig[2] + v[2]*cs; + dd->vertex(x, y, z, col); + } + } + } + dd->end(); + + dd->begin(DU_DRAW_POINTS, 3.0f); + const unsigned int colv = duRGBA(0,0,0,220); + for (int i = 0; i < lmesh.nverts; ++i) + { + const unsigned short* v = &lmesh.verts[i*3]; + const float x = orig[0] + v[0]*cs; + const float y = orig[1] + (v[1]+1)*ch + 0.1f; + const float z = orig[2] + v[2]*cs; + dd->vertex(x,y,z, colv); + } + dd->end(); +} + + + diff --git a/DetourTileCache/Include/DetourTileCache.h b/DetourTileCache/Include/DetourTileCache.h index 9f30d26..21ee25e 100644 --- a/DetourTileCache/Include/DetourTileCache.h +++ b/DetourTileCache/Include/DetourTileCache.h @@ -61,6 +61,12 @@ struct dtTileCacheParams int maxObstacles; }; +struct dtTileCacheMeshProcess +{ + virtual void process(struct dtNavMeshCreateParams* params, + unsigned char* polyAreas, unsigned short* polyFlags) = 0; +}; + class dtTileCache { @@ -82,7 +88,10 @@ public: dtObstacleRef getObstacleRef(const dtTileCacheObstacle* obmin) const; - dtStatus init(const dtTileCacheParams* params, struct dtTileCacheAlloc* talloc, struct dtTileCacheCompressor* tcomp); + dtStatus init(const dtTileCacheParams* params, + struct dtTileCacheAlloc* talloc, + struct dtTileCacheCompressor* tcomp, + struct dtTileCacheMeshProcess* tmproc); int getTilesAt(const int tx, const int ty, dtCompressedTileRef* tiles, const int maxTiles) const ; @@ -180,6 +189,7 @@ private: dtTileCacheAlloc* m_talloc; dtTileCacheCompressor* m_tcomp; + dtTileCacheMeshProcess* m_tmproc; dtTileCacheObstacle* m_obstacles; dtTileCacheObstacle* m_nextFreeObstacle; diff --git a/DetourTileCache/Include/DetourTileCacheBuilder.h b/DetourTileCache/Include/DetourTileCacheBuilder.h index a9148f9..e2b7984 100644 --- a/DetourTileCache/Include/DetourTileCacheBuilder.h +++ b/DetourTileCache/Include/DetourTileCacheBuilder.h @@ -27,6 +27,7 @@ static const int DT_TILECACHE_VERSION = 1; static const unsigned char DT_TILECACHE_NULL_AREA = 0; static const unsigned char DT_TILECACHE_WALKABLE_AREA = 63; +static const unsigned short DT_TILECACHE_NULL_IDX = 0xffff; struct dtTileCacheLayerHeader { @@ -65,6 +66,7 @@ struct dtTileCacheContourSet struct dtTileCachePolyMesh { + int nvp; int nverts; ///< Number of vertices. int npolys; ///< Number of polygons. unsigned short* verts; ///< Vertices of the mesh, 3 elements per vertex. diff --git a/DetourTileCache/Source/DetourTileCache.cpp b/DetourTileCache/Source/DetourTileCache.cpp index 889848e..7e56f9e 100644 --- a/DetourTileCache/Source/DetourTileCache.cpp +++ b/DetourTileCache/Source/DetourTileCache.cpp @@ -70,6 +70,7 @@ dtTileCache::dtTileCache() : m_tileBits(0), m_talloc(0), m_tcomp(0), + m_tmproc(0), m_obstacles(0), m_nextFreeObstacle(0), m_nreqs(0), @@ -113,10 +114,14 @@ const dtCompressedTile* dtTileCache::getTileByRef(dtCompressedTileRef ref) const } -dtStatus dtTileCache::init(const dtTileCacheParams* params, dtTileCacheAlloc* talloc, dtTileCacheCompressor* tcomp) +dtStatus dtTileCache::init(const dtTileCacheParams* params, + dtTileCacheAlloc* talloc, + dtTileCacheCompressor* tcomp, + dtTileCacheMeshProcess* tmproc) { m_talloc = talloc; m_tcomp = tcomp; + m_tmproc = tmproc; m_nreqs = 0; memcpy(&m_params, params, sizeof(m_params)); @@ -628,48 +633,6 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* if (!bc.lmesh->npolys) return DT_SUCCESS; - - // TODO: fix this, a callback? - 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_ALL = 0xffff // All abilities. - }; - - // Update poly flags from areas. - for (int i = 0; i < bc.lmesh->npolys; ++i) - { - if (bc.lmesh->areas[i] == DT_TILECACHE_WALKABLE_AREA) - bc.lmesh->areas[i] = SAMPLE_POLYAREA_GROUND; - - if (bc.lmesh->areas[i] == SAMPLE_POLYAREA_GROUND || - bc.lmesh->areas[i] == SAMPLE_POLYAREA_GRASS || - bc.lmesh->areas[i] == SAMPLE_POLYAREA_ROAD) - { - bc.lmesh->flags[i] = SAMPLE_POLYFLAGS_WALK; - } - else if (bc.lmesh->areas[i] == SAMPLE_POLYAREA_WATER) - { - bc.lmesh->flags[i] = SAMPLE_POLYFLAGS_SWIM; - } - else if (bc.lmesh->areas[i] == SAMPLE_POLYAREA_DOOR) - { - bc.lmesh->flags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR; - } - } - dtNavMeshCreateParams params; memset(¶ms, 0, sizeof(params)); params.verts = bc.lmesh->verts; @@ -679,15 +642,6 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* params.polyFlags = bc.lmesh->flags; params.polyCount = bc.lmesh->npolys; params.nvp = DT_VERTS_PER_POLYGON; - - /* 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_params.walkableHeight; params.walkableRadius = m_params.walkableRadius; params.walkableClimb = m_params.walkableClimb; @@ -700,6 +654,11 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* dtVcopy(params.bmin, tile->header->bmin); dtVcopy(params.bmax, tile->header->bmax); + if (m_tmproc) + { + m_tmproc->process(¶ms, bc.lmesh->areas, bc.lmesh->flags); + } + unsigned char* navData = 0; int navDataSize = 0; if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize)) diff --git a/DetourTileCache/Source/DetourTileCacheBuilder.cpp b/DetourTileCache/Source/DetourTileCacheBuilder.cpp index 4150638..3921a17 100644 --- a/DetourTileCache/Source/DetourTileCacheBuilder.cpp +++ b/DetourTileCache/Source/DetourTileCacheBuilder.cpp @@ -39,8 +39,6 @@ public: inline int size() const { return m_size; } }; -static const unsigned short DT_TILECACHE_NULL_IDX = 0xffff; - inline int getDirOffsetX(int dir) { const int offset[4] = { -1, 0, 1, 0, }; @@ -116,6 +114,7 @@ struct dtLayerMonotoneRegion unsigned char neis[DT_LAYER_MAX_NEIS]; unsigned char nneis; unsigned char regId; + unsigned char areaId; }; struct dtTempContour @@ -306,6 +305,7 @@ dtStatus dtBuildTileCacheRegions(dtTileCacheAlloc* alloc, // Update area. regs[ri].area++; + regs[ri].areaId = layer.areas[idx]; // Update neighbours const int ymi = x+(y-1)*w; @@ -336,6 +336,8 @@ dtStatus dtBuildTileCacheRegions(dtTileCacheAlloc* alloc, dtLayerMonotoneRegion& regn = regs[nei]; if (reg.regId == regn.regId) continue; + if (reg.areaId != regn.areaId) + continue; if (regn.area > mergea) { if (canMerge(reg.regId, regn.regId, regs, nregs)) @@ -694,6 +696,8 @@ static unsigned char getCornerHeight(dtTileCacheLayer& layer, unsigned char portal = 0xf; unsigned char height = 0; + unsigned char preg = 0xff; + bool allSameReg = true; for (int dz = -1; dz <= 0; ++dz) { @@ -709,6 +713,9 @@ static unsigned char getCornerHeight(dtTileCacheLayer& layer, { height = dtMax(height, (unsigned char)h); portal &= (layer.cons[idx] >> 4); + if (preg != 0xff && preg != layer.regs[idx]) + allSameReg = false; + preg = layer.regs[idx]; n++; } } @@ -721,7 +728,7 @@ static unsigned char getCornerHeight(dtTileCacheLayer& layer, portalCount++; shouldRemove = false; - if (n > 1 && portalCount == 1) + if (n > 1 && portalCount == 1 && allSameReg) { shouldRemove = true; } @@ -1752,6 +1759,8 @@ dtStatus dtBuildTileCachePolyMesh(dtTileCacheAlloc* alloc, // TODO: warn about too many vertices? + mesh.nvp = MAX_VERTS_PER_POLY; + dtFixedArray vflags(alloc, maxVertices); if (!vflags) return DT_FAILURE | DT_OUT_OF_MEMORY; diff --git a/RecastDemo/Build/Xcode/Recast copy-Info.plist b/RecastDemo/Build/Xcode/Recast copy-Info.plist new file mode 100644 index 0000000..4c6f919 --- /dev/null +++ b/RecastDemo/Build/Xcode/Recast copy-Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + Icon.icns + CFBundleIdentifier + com.yourcompany.${PRODUCT_NAME:identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/RecastDemo/Build/Xcode/Recast.xcodeproj/project.pbxproj b/RecastDemo/Build/Xcode/Recast.xcodeproj/project.pbxproj index 2f06ac3..6d63326 100644 --- a/RecastDemo/Build/Xcode/Recast.xcodeproj/project.pbxproj +++ b/RecastDemo/Build/Xcode/Recast.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 45; + objectVersion = 46; objects = { /* Begin PBXBuildFile section */ @@ -20,6 +20,9 @@ 6B137C900F7FCC1100459200 /* RecastMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B137C870F7FCC1100459200 /* RecastMesh.cpp */; }; 6B137C910F7FCC1100459200 /* RecastRasterization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B137C880F7FCC1100459200 /* RecastRasterization.cpp */; }; 6B137C920F7FCC1100459200 /* RecastRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B137C890F7FCC1100459200 /* RecastRegion.cpp */; }; + 6B21B00014139EF8009557F9 /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B21AFFF14139EF8009557F9 /* SDL.framework */; }; + 6B21B00214139EFE009557F9 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B21B00114139EFE009557F9 /* OpenGL.framework */; }; + 6B21B048141CB700009557F9 /* NavmeshPruneTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B21B047141CB700009557F9 /* NavmeshPruneTool.cpp */; }; 6B25B6190FFA62BE004F1BC4 /* Sample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B25B6140FFA62BE004F1BC4 /* Sample.cpp */; }; 6B25B61D0FFA62BE004F1BC4 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B25B6180FFA62BE004F1BC4 /* main.cpp */; }; 6B2AEC530FFB8958005BE9CC /* Sample_TileMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; }; @@ -30,8 +33,6 @@ 6B62416A103434880002E346 /* RecastMeshDetail.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B624169103434880002E346 /* RecastMeshDetail.cpp */; }; 6B8036AE113BAABE005ED67B /* Sample_Debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8036AD113BAABE005ED67B /* Sample_Debug.cpp */; }; 6B847777122D221D00ADF63D /* ValueHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B847776122D221C00ADF63D /* ValueHistory.cpp */; }; - 6B8632DA0F78122C00E2684A /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B8632D90F78122C00E2684A /* SDL.framework */; }; - 6B8632DC0F78123E00E2684A /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B8632DB0F78123E00E2684A /* OpenGL.framework */; }; 6B86C9AA12F69DD500C92D2E /* fastlz.c in Sources */ = {isa = PBXBuildFile; fileRef = 6B86C9A812F69DD500C92D2E /* fastlz.c */; }; 6B8DE88910B69E3E00DF20FB /* DetourNavMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8DE88710B69E3E00DF20FB /* DetourNavMesh.cpp */; }; 6B8DE88A10B69E3E00DF20FB /* DetourNavMeshBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8DE88810B69E3E00DF20FB /* DetourNavMeshBuilder.cpp */; }; @@ -92,6 +93,11 @@ 6B137C870F7FCC1100459200 /* RecastMesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastMesh.cpp; path = ../../../Recast/Source/RecastMesh.cpp; sourceTree = SOURCE_ROOT; }; 6B137C880F7FCC1100459200 /* RecastRasterization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastRasterization.cpp; path = ../../../Recast/Source/RecastRasterization.cpp; sourceTree = SOURCE_ROOT; }; 6B137C890F7FCC1100459200 /* RecastRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastRegion.cpp; path = ../../../Recast/Source/RecastRegion.cpp; sourceTree = SOURCE_ROOT; }; + 6B21AFFF14139EF8009557F9 /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = Library/Frameworks/SDL.framework; sourceTree = SDKROOT; }; + 6B21B00114139EFE009557F9 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 6B21B04514139F75009557F9 /* Recast copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Recast copy-Info.plist"; path = "/Users/memon/Code/recastnavigation/RecastDemo/Build/Xcode/Recast copy-Info.plist"; sourceTree = ""; }; + 6B21B046141CB6E9009557F9 /* NavmeshPruneTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NavmeshPruneTool.h; path = ../../Include/NavmeshPruneTool.h; sourceTree = ""; }; + 6B21B047141CB700009557F9 /* NavmeshPruneTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NavmeshPruneTool.cpp; path = ../../Source/NavmeshPruneTool.cpp; sourceTree = ""; }; 6B25B6100FFA62AD004F1BC4 /* Sample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Sample.h; path = ../../Include/Sample.h; sourceTree = SOURCE_ROOT; }; 6B25B6140FFA62BE004F1BC4 /* Sample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Sample.cpp; path = ../../Source/Sample.cpp; sourceTree = SOURCE_ROOT; }; 6B25B6180FFA62BE004F1BC4 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = ../../Source/main.cpp; sourceTree = SOURCE_ROOT; }; @@ -110,8 +116,6 @@ 6B8036AD113BAABE005ED67B /* Sample_Debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Sample_Debug.cpp; path = ../../Source/Sample_Debug.cpp; sourceTree = SOURCE_ROOT; }; 6B847774122D220D00ADF63D /* ValueHistory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueHistory.h; path = ../../Include/ValueHistory.h; sourceTree = SOURCE_ROOT; }; 6B847776122D221C00ADF63D /* ValueHistory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueHistory.cpp; path = ../../Source/ValueHistory.cpp; sourceTree = SOURCE_ROOT; }; - 6B8632D90F78122C00E2684A /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = Library/Frameworks/SDL.framework; sourceTree = SDKROOT; }; - 6B8632DB0F78123E00E2684A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; 6B86B21213387FB200B14842 /* DetourStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DetourStatus.h; path = ../../../Detour/Include/DetourStatus.h; sourceTree = SOURCE_ROOT; }; 6B86C9A812F69DD500C92D2E /* fastlz.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fastlz.c; path = ../../Contrib/fastlz/fastlz.c; sourceTree = SOURCE_ROOT; }; 6B86C9A912F69DD500C92D2E /* fastlz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fastlz.h; path = ../../Contrib/fastlz/fastlz.h; sourceTree = SOURCE_ROOT; }; @@ -184,9 +188,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 6B21B00214139EFE009557F9 /* OpenGL.framework in Frameworks */, + 6B21B00014139EF8009557F9 /* SDL.framework in Frameworks */, 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, - 6B8632DA0F78122C00E2684A /* SDL.framework in Frameworks */, - 6B8632DC0F78123E00E2684A /* OpenGL.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -236,8 +240,8 @@ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( - 6B8632D90F78122C00E2684A /* SDL.framework */, - 6B8632DB0F78123E00E2684A /* OpenGL.framework */, + 6B21B00114139EFE009557F9 /* OpenGL.framework */, + 6B21AFFF14139EF8009557F9 /* SDL.framework */, 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, ); name = "Linked Frameworks"; @@ -269,6 +273,7 @@ 29B97317FDCFA39411CA2CEA /* Resources */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, + 6B21B04514139F75009557F9 /* Recast copy-Info.plist */, ); name = Recast; sourceTree = ""; @@ -391,6 +396,8 @@ 6BCF32351104CD05009445BF /* OffMeshConnectionTool.cpp */, 6BB7FC0910EBB6AA006DA0A6 /* NavMeshTesterTool.h */, 6BB7FC0A10EBB6AA006DA0A6 /* NavMeshTesterTool.cpp */, + 6B21B046141CB6E9009557F9 /* NavmeshPruneTool.h */, + 6B21B047141CB700009557F9 /* NavmeshPruneTool.cpp */, ); name = Tools; sourceTree = ""; @@ -457,9 +464,16 @@ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; + attributes = { + LastUpgradeCheck = 0410; + }; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Recast" */; - compatibilityVersion = "Xcode 3.1"; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; hasScannedForEncodings = 1; + knownRegions = ( + en, + ); mainGroup = 29B97314FDCFA39411CA2CEA /* Recast */; projectDirPath = ""; projectRoot = ""; @@ -538,6 +552,7 @@ 6BD1B1D01323E2EC00587F83 /* Sample_SoloMesh.cpp in Sources */, 6BC048CA134F23330047265D /* DetourTileCacheBuilder.cpp in Sources */, 6BC048CD134F23620047265D /* DetourTileCache.cpp in Sources */, + 6B21B048141CB700009557F9 /* NavmeshPruneTool.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -570,15 +585,15 @@ CONFIGURATION_BUILD_DIR = ../../Bin; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = Recast_Prefix.pch; - GCC_VERSION = 4.2; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = "/Library/Frameworks/SDL.framework/Headers/**"; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; + MACOSX_DEPLOYMENT_TARGET = 10.6; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-Wreorder", @@ -600,10 +615,11 @@ GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = Recast_Prefix.pch; - GCC_VERSION = 4.2; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = "/Library/Frameworks/SDL.framework/Headers/**"; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; + MACOSX_DEPLOYMENT_TARGET = 10.6; OTHER_CFLAGS = ""; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", @@ -619,26 +635,24 @@ C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_OPTIMIZATION_LEVEL = 0; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; - PREBINDING = NO; - SDKROOT = macosx10.5; + SDKROOT = macosx10.6; }; name = Debug; }; C01FCF5008A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; - PREBINDING = NO; - SDKROOT = macosx10.5; + SDKROOT = macosx10.6; }; name = Release; }; diff --git a/RecastDemo/Include/CrowdTool.h b/RecastDemo/Include/CrowdTool.h index e0d9088..b47faa8 100644 --- a/RecastDemo/Include/CrowdTool.h +++ b/RecastDemo/Include/CrowdTool.h @@ -27,14 +27,8 @@ // Tool to create crowds. -class CrowdTool : public SampleTool +struct CrowdToolParams { - Sample* m_sample; - unsigned char m_oldFlags; - - float m_targetPos[3]; - dtPolyRef m_targetRef; - bool m_expandSelectedDebugDraw; bool m_showCorners; bool m_showCollisionSegments; @@ -42,7 +36,7 @@ class CrowdTool : public SampleTool bool m_showVO; bool m_showOpt; bool m_showNeis; - + bool m_expandDebugDraw; bool m_showLabels; bool m_showGrid; @@ -57,8 +51,14 @@ class CrowdTool : public SampleTool float m_obstacleAvoidanceType; bool m_separation; float m_separationWeight; +}; + +class CrowdToolState : public SampleToolState +{ + Sample* m_sample; - bool m_run; + float m_targetPos[3]; + dtPolyRef m_targetRef; dtCrowdAgentDebugInfo m_agentDebug; dtObstacleAvoidanceDebugData* m_vod; @@ -74,7 +74,40 @@ class CrowdTool : public SampleTool ValueHistory m_crowdTotalTime; ValueHistory m_crowdSampleCount; + + CrowdToolParams m_toolParams; + + bool m_run; + +public: + CrowdToolState(); + virtual ~CrowdToolState(); + virtual void init(class Sample* sample); + virtual void reset(); + virtual void handleRender(); + virtual void handleRenderOverlay(double* proj, double* model, int* view); + virtual void handleUpdate(const float dt); + + inline bool isRunning() const { return m_run; } + inline void setRunning(const bool s) { m_run = s; } + + void addAgent(const float* pos); + void removeAgent(const int idx); + void hilightAgent(const int idx); + void updateAgentParams(); + int hitTestAgents(const float* s, const float* p); + void setMoveTarget(const float* p, bool adjust); + void updateTick(const float dt); + + inline CrowdToolParams* getToolParams() { return &m_toolParams; } +}; + + +class CrowdTool : public SampleTool +{ + Sample* m_sample; + CrowdToolState* m_state; enum ToolMode { @@ -90,7 +123,7 @@ class CrowdTool : public SampleTool public: CrowdTool(); - ~CrowdTool(); + virtual ~CrowdTool(); virtual int type() { return TOOL_CROWD; } virtual void init(Sample* sample); diff --git a/RecastDemo/Include/Sample.h b/RecastDemo/Include/Sample.h index 68b5e7a..827ecbb 100644 --- a/RecastDemo/Include/Sample.h +++ b/RecastDemo/Include/Sample.h @@ -35,6 +35,7 @@ enum SampleToolType TOOL_OFFMESH_CONNECTION, TOOL_CONVEX_VOLUME, TOOL_CROWD, + MAX_TOOLS }; /// These are just sample areas to use consistent values across the samples. @@ -73,6 +74,14 @@ struct SampleTool 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 { @@ -100,6 +109,7 @@ protected: float m_detailSampleMaxError; SampleTool* m_tool; + SampleToolState* m_toolStates[MAX_TOOLS]; BuildContext* m_ctx; @@ -110,6 +120,8 @@ public: 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; } virtual void handleSettings(); virtual void handleTools(); @@ -136,6 +148,12 @@ public: inline unsigned char getNavMeshDrawFlags() const { return m_navMeshDrawFlags; } inline 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(); }; diff --git a/RecastDemo/Include/Sample_TempObstacles.h b/RecastDemo/Include/Sample_TempObstacles.h index 4a334d6..269f809 100644 --- a/RecastDemo/Include/Sample_TempObstacles.h +++ b/RecastDemo/Include/Sample_TempObstacles.h @@ -32,6 +32,7 @@ protected: struct LinearAllocator* m_talloc; struct FastLZCompressor* m_tcomp; + struct MeshProcess* m_tmproc; class dtTileCache* m_tileCache; @@ -75,7 +76,7 @@ public: void getTilePos(const float* pos, int& tx, int& ty); - void renderCachedTile(const int tx, const int ty); + void renderCachedTile(const int tx, const int ty, const int type); void renderCachedTileOverlay(const int tx, const int ty, double* proj, double* model, int* view); void addTempObstacle(const float* pos); diff --git a/RecastDemo/Source/CrowdTool.cpp b/RecastDemo/Source/CrowdTool.cpp index a1bff71..a97e3fc 100644 --- a/RecastDemo/Source/CrowdTool.cpp +++ b/RecastDemo/Source/CrowdTool.cpp @@ -90,33 +90,32 @@ static void getAgentBounds(const dtCrowdAgent* ag, float* bmin, float* bmax) bmax[2] = p[2] + r; } -CrowdTool::CrowdTool() : +CrowdToolState::CrowdToolState() : m_sample(0), - m_oldFlags(0), m_targetRef(0), - m_expandSelectedDebugDraw(true), - m_showCorners(false), - m_showCollisionSegments(false), - m_showPath(false), - m_showVO(false), - m_showOpt(false), - m_showNeis(false), - m_expandDebugDraw(false), - m_showLabels(false), - m_showGrid(false), - m_showNodes(false), - m_showPerfGraph(false), - m_expandOptions(true), - m_anticipateTurns(true), - m_optimizeVis(true), - m_optimizeTopo(true), - m_obstacleAvoidance(true), - m_obstacleAvoidanceType(3.0f), - m_separation(false), - m_separationWeight(2.0f), - m_run(true), - m_mode(TOOLMODE_CREATE) + m_run(true) { + m_toolParams.m_expandSelectedDebugDraw = true; + m_toolParams.m_showCorners = false; + m_toolParams.m_showCollisionSegments = false; + m_toolParams.m_showPath = false; + m_toolParams.m_showVO = false; + m_toolParams.m_showOpt = false; + m_toolParams.m_showNeis = false; + m_toolParams.m_expandDebugDraw = false; + m_toolParams.m_showLabels = false; + m_toolParams.m_showGrid = false; + m_toolParams.m_showNodes = false; + m_toolParams.m_showPerfGraph = false; + m_toolParams.m_expandOptions = true; + m_toolParams.m_anticipateTurns = true; + m_toolParams.m_optimizeVis = true; + m_toolParams.m_optimizeTopo = true; + m_toolParams.m_obstacleAvoidance = true; + m_toolParams.m_obstacleAvoidanceType = 3.0f; + m_toolParams.m_separation = false; + m_toolParams.m_separationWeight = 2.0f; + memset(m_trails, 0, sizeof(m_trails)); m_vod = dtAllocObstacleAvoidanceDebugData(); @@ -127,31 +126,26 @@ CrowdTool::CrowdTool() : m_agentDebug.vod = m_vod; } -CrowdTool::~CrowdTool() +CrowdToolState::~CrowdToolState() { - if (m_sample) - { - m_sample->setNavMeshDrawFlags(m_oldFlags); - } - dtFreeObstacleAvoidanceDebugData(m_vod); } -void CrowdTool::init(Sample* sample) +void CrowdToolState::init(class Sample* sample) { if (m_sample != sample) { m_sample = sample; - m_oldFlags = m_sample->getNavMeshDrawFlags(); - m_sample->setNavMeshDrawFlags(m_oldFlags & ~DU_DRAWNAVMESH_CLOSEDLIST); +// m_oldFlags = m_sample->getNavMeshDrawFlags(); +// m_sample->setNavMeshDrawFlags(m_oldFlags & ~DU_DRAWNAVMESH_CLOSEDLIST); } - + dtNavMesh* nav = m_sample->getNavMesh(); dtCrowd* crowd = m_sample->getCrowd(); if (nav && crowd && crowd->getAgentCount() == 0) { crowd->init(MAX_AGENTS, m_sample->getAgentRadius(), nav); - + // Make polygons with 'disabled' flag invalid. crowd->getEditableFilter()->setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED); @@ -166,7 +160,7 @@ void CrowdTool::init(Sample* sample) params.adaptiveRings = 2; params.adaptiveDepth = 1; crowd->setObstacleAvoidanceParams(0, ¶ms); - + // Medium (22) params.velBias = 0.5f; params.adaptiveDivs = 5; @@ -189,369 +183,13 @@ void CrowdTool::init(Sample* sample) crowd->setObstacleAvoidanceParams(3, ¶ms); } - } -void CrowdTool::reset() +void CrowdToolState::reset() { - m_targetRef = 0; } -void CrowdTool::handleMenu() -{ - - if (imguiCheck("Create Agents", m_mode == TOOLMODE_CREATE)) - m_mode = TOOLMODE_CREATE; - if (imguiCheck("Move Target", m_mode == TOOLMODE_MOVE_TARGET)) - m_mode = TOOLMODE_MOVE_TARGET; - if (imguiCheck("Select Agent", m_mode == TOOLMODE_SELECT)) - m_mode = TOOLMODE_SELECT; - if (imguiCheck("Toggle Polys", m_mode == TOOLMODE_TOGGLE_POLYS)) - m_mode = TOOLMODE_TOGGLE_POLYS; - - imguiSeparatorLine(); - - if (imguiCollapse("Options", 0, m_expandOptions)) - m_expandOptions = !m_expandOptions; - - if (m_expandOptions) - { - imguiIndent(); - if (imguiCheck("Optimize Visibility", m_optimizeVis)) - { - m_optimizeVis = !m_optimizeVis; - updateAgentParams(); - } - if (imguiCheck("Optimize Topology", m_optimizeTopo)) - { - m_optimizeTopo = !m_optimizeTopo; - updateAgentParams(); - } - if (imguiCheck("Anticipate Turns", m_anticipateTurns)) - { - m_anticipateTurns = !m_anticipateTurns; - updateAgentParams(); - } - if (imguiCheck("Obstacle Avoidance", m_obstacleAvoidance)) - { - m_obstacleAvoidance = !m_obstacleAvoidance; - updateAgentParams(); - } - if (imguiSlider("Avoidance Quality", &m_obstacleAvoidanceType, 0.0f, 3.0f, 1.0f)) - { - updateAgentParams(); - } - if (imguiCheck("Separation", m_separation)) - { - m_separation = !m_separation; - updateAgentParams(); - } - if (imguiSlider("Separation Weight", &m_separationWeight, 0.0f, 20.0f, 0.01f)) - { - updateAgentParams(); - } - - imguiUnindent(); - } - - if (imguiCollapse("Selected Debug Draw", 0, m_expandSelectedDebugDraw)) - m_expandSelectedDebugDraw = !m_expandSelectedDebugDraw; - - if (m_expandSelectedDebugDraw) - { - imguiIndent(); - if (imguiCheck("Show Corners", m_showCorners)) - m_showCorners = !m_showCorners; - if (imguiCheck("Show Collision Segs", m_showCollisionSegments)) - m_showCollisionSegments = !m_showCollisionSegments; - if (imguiCheck("Show Path", m_showPath)) - m_showPath = !m_showPath; - if (imguiCheck("Show VO", m_showVO)) - m_showVO = !m_showVO; - if (imguiCheck("Show Path Optimization", m_showOpt)) - m_showOpt = !m_showOpt; - if (imguiCheck("Show Neighbours", m_showNeis)) - m_showNeis = !m_showNeis; - imguiUnindent(); - } - - if (imguiCollapse("Debug Draw", 0, m_expandDebugDraw)) - m_expandDebugDraw = !m_expandDebugDraw; - - if (m_expandDebugDraw) - { - imguiIndent(); - if (imguiCheck("Show Labels", m_showLabels)) - m_showLabels = !m_showLabels; - if (imguiCheck("Show Prox Grid", 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(); - } -} - -void CrowdTool::handleClick(const float* s, const float* p, bool shift) -{ - if (!m_sample) return; - InputGeom* geom = m_sample->getInputGeom(); - if (!geom) return; - dtCrowd* crowd = m_sample->getCrowd(); - if (!crowd) return; - - if (m_mode == TOOLMODE_CREATE) - { - if (shift) - { - // Delete - int isel = -1; - float tsel = FLT_MAX; - - for (int i = 0; i < crowd->getAgentCount(); ++i) - { - const dtCrowdAgent* ag = crowd->getAgent(i); - if (!ag->active) continue; - float bmin[3], bmax[3]; - getAgentBounds(ag, bmin, bmax); - float tmin, tmax; - if (isectSegAABB(s, p, bmin,bmax, tmin, tmax)) - { - if (tmin > 0 && tmin < tsel) - { - isel = i; - tsel = tmin; - } - } - } - if (isel != -1) - { - crowd->removeAgent(isel); - } - } - else - { - // Add - dtCrowdAgentParams ap; - memset(&ap, 0, sizeof(ap)); - ap.radius = m_sample->getAgentRadius(); - ap.height = m_sample->getAgentHeight(); - ap.maxAcceleration = 8.0f; - ap.maxSpeed = 3.5f; - ap.collisionQueryRange = ap.radius * 12.0f; - ap.pathOptimizationRange = ap.radius * 30.0f; - ap.updateFlags = 0; - if (m_anticipateTurns) - ap.updateFlags |= DT_CROWD_ANTICIPATE_TURNS; - if (m_optimizeVis) - ap.updateFlags |= DT_CROWD_OPTIMIZE_VIS; - if (m_optimizeTopo) - ap.updateFlags |= DT_CROWD_OPTIMIZE_TOPO; - if (m_obstacleAvoidance) - ap.updateFlags |= DT_CROWD_OBSTACLE_AVOIDANCE; - if (m_separation) - ap.updateFlags |= DT_CROWD_SEPARATION; - ap.obstacleAvoidanceType = (unsigned char)m_obstacleAvoidanceType; - ap.separationWeight = m_separationWeight; - - int idx = crowd->addAgent(p, &ap); - if (idx != -1) - { - if (m_targetRef) - crowd->requestMoveTarget(idx, m_targetRef, m_targetPos); - - // Init trail - AgentTrail* trail = &m_trails[idx]; - for (int i = 0; i < AGENT_MAX_TRAIL; ++i) - dtVcopy(&trail->trail[i*3], p); - trail->htrail = 0; - } - } - } - else if (m_mode == TOOLMODE_MOVE_TARGET) - { - // Find nearest point on navmesh and set move request to that location. - dtNavMeshQuery* navquery = m_sample->getNavMeshQuery(); - const dtQueryFilter* filter = crowd->getFilter(); - const float* ext = crowd->getQueryExtents(); - - navquery->findNearestPoly(p, ext, filter, &m_targetRef, m_targetPos); - - if (shift) - { - // Adjust target using tiny local search. - if (m_agentDebug.idx != -1) - { - const dtCrowdAgent* ag = crowd->getAgent(m_agentDebug.idx); - if (ag && ag->active) - crowd->adjustMoveTarget(m_agentDebug.idx, m_targetRef, m_targetPos); - } - else - { - for (int i = 0; i < crowd->getAgentCount(); ++i) - { - const dtCrowdAgent* ag = crowd->getAgent(i); - if (!ag->active) continue; - crowd->adjustMoveTarget(i, m_targetRef, m_targetPos); - } - } - } - else - { - // Move target using paht finder - if (m_agentDebug.idx != -1) - { - const dtCrowdAgent* ag = crowd->getAgent(m_agentDebug.idx); - if (ag && ag->active) - crowd->requestMoveTarget(m_agentDebug.idx, m_targetRef, m_targetPos); - } - else - { - for (int i = 0; i < crowd->getAgentCount(); ++i) - { - const dtCrowdAgent* ag = crowd->getAgent(i); - if (!ag->active) continue; - crowd->requestMoveTarget(i, m_targetRef, m_targetPos); - } - } - } - } - else if (m_mode == TOOLMODE_SELECT) - { - // Highlight - m_agentDebug.idx = -1; - - float tsel = FLT_MAX; - for (int i = 0; i < crowd->getAgentCount(); ++i) - { - const dtCrowdAgent* ag = crowd->getAgent(i); - if (!ag->active) continue; - float bmin[3], bmax[3]; - getAgentBounds(ag, bmin, bmax); - float tmin, tmax; - if (isectSegAABB(s, p, bmin,bmax, tmin, tmax)) - { - if (tmin > 0 && tmin < tsel) - { - m_agentDebug.idx = i; - tsel = tmin; - } - } - } - } - else if (m_mode == TOOLMODE_TOGGLE_POLYS) - { - dtNavMesh* nav = m_sample->getNavMesh(); - dtNavMeshQuery* navquery = m_sample->getNavMeshQuery(); - if (nav && navquery) - { - dtQueryFilter filter; - const float* ext = crowd->getQueryExtents(); - float tgt[3]; - dtPolyRef ref; - navquery->findNearestPoly(p, ext, &filter, &ref, tgt); - if (ref) - { - unsigned short flags = 0; - if (dtStatusSucceed(nav->getPolyFlags(ref, &flags))) - { - flags ^= SAMPLE_POLYFLAGS_DISABLED; - nav->setPolyFlags(ref, flags); - } - } - } - } - -} - -void CrowdTool::updateAgentParams() -{ - dtCrowd* crowd = m_sample->getCrowd(); - if (!crowd) return; - - unsigned char updateFlags = 0; - unsigned char obstacleAvoidanceType = 0; - - if (m_anticipateTurns) - updateFlags |= DT_CROWD_ANTICIPATE_TURNS; - if (m_optimizeVis) - updateFlags |= DT_CROWD_OPTIMIZE_VIS; - if (m_optimizeTopo) - updateFlags |= DT_CROWD_OPTIMIZE_TOPO; - if (m_obstacleAvoidance) - updateFlags |= DT_CROWD_OBSTACLE_AVOIDANCE; - if (m_obstacleAvoidance) - updateFlags |= DT_CROWD_OBSTACLE_AVOIDANCE; - if (m_separation) - updateFlags |= DT_CROWD_SEPARATION; - - obstacleAvoidanceType = (unsigned char)m_obstacleAvoidanceType; - - dtCrowdAgentParams params; - - for (int i = 0; i < crowd->getAgentCount(); ++i) - { - const dtCrowdAgent* ag = crowd->getAgent(i); - if (!ag->active) continue; - memcpy(¶ms, &ag->params, sizeof(dtCrowdAgentParams)); - params.updateFlags = updateFlags; - params.obstacleAvoidanceType = obstacleAvoidanceType; - params.separationWeight = m_separationWeight; - crowd->updateAgentParameters(i, ¶ms); - } -} - -void CrowdTool::updateTick(const float dt) -{ - dtNavMesh* nav = m_sample->getNavMesh(); - dtCrowd* crowd = m_sample->getCrowd(); - if (!nav || !crowd) return; - - TimeVal startTime = getPerfTime(); - - crowd->update(dt, &m_agentDebug); - - TimeVal endTime = getPerfTime(); - - // Update agent trails - for (int i = 0; i < crowd->getAgentCount(); ++i) - { - const dtCrowdAgent* ag = crowd->getAgent(i); - AgentTrail* trail = &m_trails[i]; - if (!ag->active) - continue; - // Update agent movement trail. - trail->htrail = (trail->htrail + 1) % AGENT_MAX_TRAIL; - dtVcopy(&trail->trail[trail->htrail*3], ag->npos); - } - - m_agentDebug.vod->normalizeSamples(); - - m_crowdSampleCount.addSample((float)crowd->getVelocitySampleCount()); - m_crowdTotalTime.addSample(getPerfDeltaTimeUsec(startTime, endTime) / 1000.0f); -} - -void CrowdTool::handleStep() -{ - const float dt = 1.0f/20.0f; - updateTick(dt); - m_run = false; -} - -void CrowdTool::handleToggle() -{ - m_run = !m_run; -} - -void CrowdTool::handleUpdate(const float dt) -{ - if (!m_sample) return; - if (m_run) - updateTick(dt); -} - -void CrowdTool::handleRender() +void CrowdToolState::handleRender() { DebugDrawGL dd; const float s = m_sample->getAgentRadius(); @@ -560,8 +198,8 @@ void CrowdTool::handleRender() dtCrowd* crowd = m_sample->getCrowd(); if (!nav || !crowd) return; - - if (m_showNodes && crowd->getPathQueue()) + + if (m_toolParams.m_showNodes && crowd->getPathQueue()) { const dtNavMeshQuery* navquery = crowd->getPathQueue()->getNavQuery(); if (navquery) @@ -571,14 +209,14 @@ void CrowdTool::handleRender() dd.depthMask(false); // Draw paths - if (m_showPath) + if (m_toolParams.m_showPath) { if (m_agentDebug.idx != -1) { const dtCrowdAgent* ag = crowd->getAgent(m_agentDebug.idx); if (ag->active) { - + const dtPolyRef* path = ag->corridor.getPath(); const int npath = ag->corridor.getPathCount(); for (int i = 0; i < npath; ++i) @@ -586,12 +224,12 @@ void CrowdTool::handleRender() } } } - + 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) + if (m_toolParams.m_showGrid) { float gridy = -FLT_MAX; for (int i = 0; i < crowd->getAgentCount(); ++i) @@ -631,7 +269,7 @@ void CrowdTool::handleRender() const AgentTrail* trail = &m_trails[i]; const float* pos = ag->npos; - + dd.begin(DU_DRAW_LINES,3.0f); float prev[3], preva = 1; dtVcopy(prev, pos); @@ -646,20 +284,20 @@ void CrowdTool::handleRender() dtVcopy(prev, v); } dd.end(); - + } - + // Corners & co if (m_agentDebug.idx != -1) { const dtCrowdAgent* ag = crowd->getAgent(m_agentDebug.idx); if (ag->active) { - + const float radius = ag->params.radius; const float* pos = ag->npos; - if (m_showCorners) + if (m_toolParams.m_showCorners) { if (ag->ncorners) { @@ -681,7 +319,7 @@ void CrowdTool::handleRender() dd.end(); - if (m_anticipateTurns) + if (m_toolParams.m_anticipateTurns) { /* float dvel[3], pos[3]; calcSmoothSteerDirection(ag->pos, ag->cornerVerts, ag->ncorners, dvel); @@ -706,7 +344,7 @@ void CrowdTool::handleRender() } } - if (m_showCollisionSegments) + if (m_toolParams.m_showCollisionSegments) { const float* center = ag->boundary.getCenter(); duDebugDrawCross(&dd, center[0],center[1]+radius,center[2], 0.2f, duRGBA(192,0,128,255), 2.0f); @@ -726,7 +364,7 @@ void CrowdTool::handleRender() dd.end(); } - if (m_showNeis) + if (m_toolParams.m_showNeis) { duDebugDrawCircle(&dd, pos[0],pos[1]+radius,pos[2], ag->params.collisionQueryRange, duRGBA(0,192,128,128), 2.0f); @@ -758,7 +396,7 @@ void CrowdTool::handleRender() dd.end(); } - if (m_showOpt) + if (m_toolParams.m_showOpt) { dd.begin(DU_DRAW_LINES, 2.0f); dd.vertex(m_agentDebug.optStart[0],m_agentDebug.optStart[1]+0.3f,m_agentDebug.optStart[2], duRGBA(0,128,0,192)); @@ -779,7 +417,7 @@ void CrowdTool::handleRender() duDebugDrawCircle(&dd, pos[0], pos[1], pos[2], radius, duRGBA(0,0,0,32), 2.0f); } - + for (int i = 0; i < crowd->getAgentCount(); ++i) { const dtCrowdAgent* ag = crowd->getAgent(i); @@ -803,7 +441,7 @@ void CrowdTool::handleRender() const dtCrowdAgent* ag = crowd->getAgent(m_agentDebug.idx); if (ag->active) { - if (m_showVO) + if (m_toolParams.m_showVO) { // Draw detail about agent sela const dtObstacleAvoidanceDebugData* vod = m_agentDebug.vod; @@ -844,39 +482,40 @@ void CrowdTool::handleRender() const float* pos = ag->npos; const float* vel = ag->vel; const float* dvel = ag->dvel; - + unsigned int col = duRGBA(220,220,220,192); if (m_agentDebug.idx == i) col = duRGBA(255,192,0,192); duDebugDrawCircle(&dd, pos[0], pos[1]+height, pos[2], radius, col, 2.0f); - + duDebugDrawArrow(&dd, pos[0],pos[1]+height,pos[2], pos[0]+dvel[0],pos[1]+height+dvel[1],pos[2]+dvel[2], 0.0f, 0.4f, duRGBA(0,192,255,192), (m_agentDebug.idx == i) ? 2.0f : 1.0f); duDebugDrawArrow(&dd, pos[0],pos[1]+height,pos[2], - pos[0]+vel[0],pos[1]+height+vel[1],pos[2]+vel[2], - 0.0f, 0.4f, duRGBA(0,0,0,160), 2.0f); + pos[0]+vel[0],pos[1]+height+vel[1],pos[2]+vel[2], + 0.0f, 0.4f, duRGBA(0,0,0,160), 2.0f); } dd.depthMask(true); } -void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view) + +void CrowdToolState::handleRenderOverlay(double* proj, double* model, int* view) { GLdouble x, y, z; // Draw start and end point labels if (m_targetRef && gluProject((GLdouble)m_targetPos[0], (GLdouble)m_targetPos[1], (GLdouble)m_targetPos[2], - model, proj, view, &x, &y, &z)) + model, proj, view, &x, &y, &z)) { imguiDrawText((int)x, (int)(y+25), IMGUI_ALIGN_CENTER, "TARGET", imguiRGBA(0,0,0,220)); } - + char label[32]; - - if (m_showLabels) + + if (m_toolParams.m_showLabels) { dtCrowd* crowd = m_sample->getCrowd(); if (crowd) @@ -906,7 +545,7 @@ void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view) { const float radius = ag->params.radius; - if (m_showNeis) + if (m_toolParams.m_showNeis) { for (int j = 0; j < ag->nneis; ++j) { @@ -926,12 +565,12 @@ void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view) } - if (m_showPerfGraph) + if (m_toolParams.m_showPerfGraph) { GraphParams gp; gp.setRect(300, 10, 500, 200, 8); gp.setValueRange(0.0f, 2.0f, 4, "ms"); - + drawGraphBackground(&gp); drawGraph(&gp, &m_crowdTotalTime, 1, "Total", duRGBA(255,128,0,255)); @@ -940,6 +579,440 @@ void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view) drawGraph(&gp, &m_crowdSampleCount, 0, "Sample Count", duRGBA(96,96,96,128)); } +} + +void CrowdToolState::handleUpdate(const float dt) +{ + updateTick(dt); +} + +void CrowdToolState::addAgent(const float* p) +{ + if (!m_sample) return; + dtCrowd* crowd = m_sample->getCrowd(); + + dtCrowdAgentParams ap; + memset(&ap, 0, sizeof(ap)); + ap.radius = m_sample->getAgentRadius(); + ap.height = m_sample->getAgentHeight(); + ap.maxAcceleration = 8.0f; + ap.maxSpeed = 3.5f; + ap.collisionQueryRange = ap.radius * 12.0f; + ap.pathOptimizationRange = ap.radius * 30.0f; + ap.updateFlags = 0; + if (m_toolParams.m_anticipateTurns) + ap.updateFlags |= DT_CROWD_ANTICIPATE_TURNS; + if (m_toolParams.m_optimizeVis) + ap.updateFlags |= DT_CROWD_OPTIMIZE_VIS; + if (m_toolParams.m_optimizeTopo) + ap.updateFlags |= DT_CROWD_OPTIMIZE_TOPO; + if (m_toolParams.m_obstacleAvoidance) + ap.updateFlags |= DT_CROWD_OBSTACLE_AVOIDANCE; + if (m_toolParams.m_separation) + ap.updateFlags |= DT_CROWD_SEPARATION; + ap.obstacleAvoidanceType = (unsigned char)m_toolParams.m_obstacleAvoidanceType; + ap.separationWeight = m_toolParams.m_separationWeight; + + int idx = crowd->addAgent(p, &ap); + if (idx != -1) + { + if (m_targetRef) + crowd->requestMoveTarget(idx, m_targetRef, m_targetPos); + + // Init trail + AgentTrail* trail = &m_trails[idx]; + for (int i = 0; i < AGENT_MAX_TRAIL; ++i) + dtVcopy(&trail->trail[i*3], p); + trail->htrail = 0; + } +} + +void CrowdToolState::removeAgent(const int idx) +{ + if (!m_sample) return; + dtCrowd* crowd = m_sample->getCrowd(); + + crowd->removeAgent(idx); + + if (idx == m_agentDebug.idx) + m_agentDebug.idx = -1; +} + +void CrowdToolState::hilightAgent(const int idx) +{ + m_agentDebug.idx = idx; +} + +void CrowdToolState::setMoveTarget(const float* p, bool adjust) +{ + if (!m_sample) return; + + // Find nearest point on navmesh and set move request to that location. + dtNavMeshQuery* navquery = m_sample->getNavMeshQuery(); + dtCrowd* crowd = m_sample->getCrowd(); + const dtQueryFilter* filter = crowd->getFilter(); + const float* ext = crowd->getQueryExtents(); + + navquery->findNearestPoly(p, ext, filter, &m_targetRef, m_targetPos); + + if (adjust) + { + // Adjust target using tiny local search. + if (m_agentDebug.idx != -1) + { + const dtCrowdAgent* ag = crowd->getAgent(m_agentDebug.idx); + if (ag && ag->active) + crowd->adjustMoveTarget(m_agentDebug.idx, m_targetRef, m_targetPos); + } + else + { + for (int i = 0; i < crowd->getAgentCount(); ++i) + { + const dtCrowdAgent* ag = crowd->getAgent(i); + if (!ag->active) continue; + crowd->adjustMoveTarget(i, m_targetRef, m_targetPos); + } + } + } + else + { + // Move target using path finder + if (m_agentDebug.idx != -1) + { + const dtCrowdAgent* ag = crowd->getAgent(m_agentDebug.idx); + if (ag && ag->active) + crowd->requestMoveTarget(m_agentDebug.idx, m_targetRef, m_targetPos); + } + else + { + for (int i = 0; i < crowd->getAgentCount(); ++i) + { + const dtCrowdAgent* ag = crowd->getAgent(i); + if (!ag->active) continue; + crowd->requestMoveTarget(i, m_targetRef, m_targetPos); + } + } + } +} + +int CrowdToolState::hitTestAgents(const float* s, const float* p) +{ + if (!m_sample) return -1; + dtCrowd* crowd = m_sample->getCrowd(); + + int isel = -1; + float tsel = FLT_MAX; + + for (int i = 0; i < crowd->getAgentCount(); ++i) + { + const dtCrowdAgent* ag = crowd->getAgent(i); + if (!ag->active) continue; + float bmin[3], bmax[3]; + getAgentBounds(ag, bmin, bmax); + float tmin, tmax; + if (isectSegAABB(s, p, bmin,bmax, tmin, tmax)) + { + if (tmin > 0 && tmin < tsel) + { + isel = i; + tsel = tmin; + } + } + } + + return isel; +} + +void CrowdToolState::updateAgentParams() +{ + if (!m_sample) return; + dtCrowd* crowd = m_sample->getCrowd(); + if (!crowd) return; + + unsigned char updateFlags = 0; + unsigned char obstacleAvoidanceType = 0; + + if (m_toolParams.m_anticipateTurns) + updateFlags |= DT_CROWD_ANTICIPATE_TURNS; + if (m_toolParams.m_optimizeVis) + updateFlags |= DT_CROWD_OPTIMIZE_VIS; + if (m_toolParams.m_optimizeTopo) + updateFlags |= DT_CROWD_OPTIMIZE_TOPO; + if (m_toolParams.m_obstacleAvoidance) + updateFlags |= DT_CROWD_OBSTACLE_AVOIDANCE; + if (m_toolParams.m_obstacleAvoidance) + updateFlags |= DT_CROWD_OBSTACLE_AVOIDANCE; + if (m_toolParams.m_separation) + updateFlags |= DT_CROWD_SEPARATION; + + obstacleAvoidanceType = (unsigned char)m_toolParams.m_obstacleAvoidanceType; + + dtCrowdAgentParams params; + + for (int i = 0; i < crowd->getAgentCount(); ++i) + { + const dtCrowdAgent* ag = crowd->getAgent(i); + if (!ag->active) continue; + memcpy(¶ms, &ag->params, sizeof(dtCrowdAgentParams)); + params.updateFlags = updateFlags; + params.obstacleAvoidanceType = obstacleAvoidanceType; + params.separationWeight = m_toolParams.m_separationWeight; + crowd->updateAgentParameters(i, ¶ms); + } +} + +void CrowdToolState::updateTick(const float dt) +{ + if (!m_sample) return; + dtNavMesh* nav = m_sample->getNavMesh(); + dtCrowd* crowd = m_sample->getCrowd(); + if (!nav || !crowd) return; + + TimeVal startTime = getPerfTime(); + + crowd->update(dt, &m_agentDebug); + + TimeVal endTime = getPerfTime(); + + // Update agent trails + for (int i = 0; i < crowd->getAgentCount(); ++i) + { + const dtCrowdAgent* ag = crowd->getAgent(i); + AgentTrail* trail = &m_trails[i]; + if (!ag->active) + continue; + // Update agent movement trail. + trail->htrail = (trail->htrail + 1) % AGENT_MAX_TRAIL; + dtVcopy(&trail->trail[trail->htrail*3], ag->npos); + } + + m_agentDebug.vod->normalizeSamples(); + + m_crowdSampleCount.addSample((float)crowd->getVelocitySampleCount()); + m_crowdTotalTime.addSample(getPerfDeltaTimeUsec(startTime, endTime) / 1000.0f); +} + + + + +CrowdTool::CrowdTool() : + m_sample(0), + m_state(0), + m_mode(TOOLMODE_CREATE) +{ +} + +CrowdTool::~CrowdTool() +{ +} + +void CrowdTool::init(Sample* sample) +{ + if (m_sample != sample) + { + m_sample = sample; + } + + if (!sample) + return; + + m_state = (CrowdToolState*)sample->getToolState(type()); + if (!m_state) + { + m_state = new CrowdToolState(); + sample->setToolState(type(), m_state); + } + m_state->init(sample); +} + +void CrowdTool::reset() +{ +} + +void CrowdTool::handleMenu() +{ + if (!m_state) + return; + CrowdToolParams* params = m_state->getToolParams(); + + if (imguiCheck("Create Agents", m_mode == TOOLMODE_CREATE)) + m_mode = TOOLMODE_CREATE; + if (imguiCheck("Move Target", m_mode == TOOLMODE_MOVE_TARGET)) + m_mode = TOOLMODE_MOVE_TARGET; + if (imguiCheck("Select Agent", m_mode == TOOLMODE_SELECT)) + m_mode = TOOLMODE_SELECT; + if (imguiCheck("Toggle Polys", m_mode == TOOLMODE_TOGGLE_POLYS)) + m_mode = TOOLMODE_TOGGLE_POLYS; + + imguiSeparatorLine(); + + if (imguiCollapse("Options", 0, params->m_expandOptions)) + params->m_expandOptions = !params->m_expandOptions; + + if (params->m_expandOptions) + { + imguiIndent(); + if (imguiCheck("Optimize Visibility", params->m_optimizeVis)) + { + params->m_optimizeVis = !params->m_optimizeVis; + m_state->updateAgentParams(); + } + if (imguiCheck("Optimize Topology", params->m_optimizeTopo)) + { + params->m_optimizeTopo = !params->m_optimizeTopo; + m_state->updateAgentParams(); + } + if (imguiCheck("Anticipate Turns", params->m_anticipateTurns)) + { + params->m_anticipateTurns = !params->m_anticipateTurns; + m_state->updateAgentParams(); + } + if (imguiCheck("Obstacle Avoidance", params->m_obstacleAvoidance)) + { + params->m_obstacleAvoidance = !params->m_obstacleAvoidance; + m_state->updateAgentParams(); + } + if (imguiSlider("Avoidance Quality", ¶ms->m_obstacleAvoidanceType, 0.0f, 3.0f, 1.0f)) + { + m_state->updateAgentParams(); + } + if (imguiCheck("Separation", params->m_separation)) + { + params->m_separation = !params->m_separation; + m_state->updateAgentParams(); + } + if (imguiSlider("Separation Weight", ¶ms->m_separationWeight, 0.0f, 20.0f, 0.01f)) + { + m_state->updateAgentParams(); + } + + imguiUnindent(); + } + + if (imguiCollapse("Selected Debug Draw", 0, params->m_expandSelectedDebugDraw)) + params->m_expandSelectedDebugDraw = !params->m_expandSelectedDebugDraw; + + if (params->m_expandSelectedDebugDraw) + { + imguiIndent(); + if (imguiCheck("Show Corners", params->m_showCorners)) + params->m_showCorners = !params->m_showCorners; + if (imguiCheck("Show Collision Segs", params->m_showCollisionSegments)) + params->m_showCollisionSegments = !params->m_showCollisionSegments; + if (imguiCheck("Show Path", params->m_showPath)) + params->m_showPath = !params->m_showPath; + if (imguiCheck("Show VO", params->m_showVO)) + params->m_showVO = !params->m_showVO; + if (imguiCheck("Show Path Optimization", params->m_showOpt)) + params->m_showOpt = !params->m_showOpt; + if (imguiCheck("Show Neighbours", params->m_showNeis)) + params->m_showNeis = !params->m_showNeis; + imguiUnindent(); + } + + if (imguiCollapse("Debug Draw", 0, params->m_expandDebugDraw)) + params->m_expandDebugDraw = !params->m_expandDebugDraw; + + if (params->m_expandDebugDraw) + { + imguiIndent(); + if (imguiCheck("Show Labels", params->m_showLabels)) + params->m_showLabels = !params->m_showLabels; + if (imguiCheck("Show Prox Grid", params->m_showGrid)) + params->m_showGrid = !params->m_showGrid; + if (imguiCheck("Show Nodes", params->m_showNodes)) + params->m_showNodes = !params->m_showNodes; + if (imguiCheck("Show Perf Graph", params->m_showPerfGraph)) + params->m_showPerfGraph = !params->m_showPerfGraph; + imguiUnindent(); + } +} + +void CrowdTool::handleClick(const float* s, const float* p, bool shift) +{ + if (!m_sample) return; + if (!m_state) return; + InputGeom* geom = m_sample->getInputGeom(); + if (!geom) return; + dtCrowd* crowd = m_sample->getCrowd(); + if (!crowd) return; + + if (m_mode == TOOLMODE_CREATE) + { + if (shift) + { + // Delete + int ahit = m_state->hitTestAgents(s,p); + if (ahit != -1) + m_state->removeAgent(ahit); + } + else + { + // Add + m_state->addAgent(p); + } + } + else if (m_mode == TOOLMODE_MOVE_TARGET) + { + m_state->setMoveTarget(p, shift); + } + else if (m_mode == TOOLMODE_SELECT) + { + // Highlight + int ahit = m_state->hitTestAgents(s,p); + m_state->hilightAgent(ahit); + } + else if (m_mode == TOOLMODE_TOGGLE_POLYS) + { + dtNavMesh* nav = m_sample->getNavMesh(); + dtNavMeshQuery* navquery = m_sample->getNavMeshQuery(); + if (nav && navquery) + { + dtQueryFilter filter; + const float* ext = crowd->getQueryExtents(); + float tgt[3]; + dtPolyRef ref; + navquery->findNearestPoly(p, ext, &filter, &ref, tgt); + if (ref) + { + unsigned short flags = 0; + if (dtStatusSucceed(nav->getPolyFlags(ref, &flags))) + { + flags ^= SAMPLE_POLYFLAGS_DISABLED; + nav->setPolyFlags(ref, flags); + } + } + } + } + +} + +void CrowdTool::handleStep() +{ + if (!m_state) return; + + const float dt = 1.0f/20.0f; + m_state->updateTick(dt); + + m_state->setRunning(false); +} + +void CrowdTool::handleToggle() +{ + if (!m_state) return; + m_state->setRunning(!m_state->isRunning()); +} + +void CrowdTool::handleUpdate(const float dt) +{ +} + +void CrowdTool::handleRender() +{ +} + +void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view) +{ // Tool help const int h = view[3]; int ty = h-40; @@ -961,7 +1034,8 @@ void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view) ty -= 20; imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "SPACE: Run/Pause simulation. 1: Step simulation.", imguiRGBA(255,255,255,192)); ty -= 20; - if (m_run) + + if (m_state && m_state->isRunning()) imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "- RUNNING -", imguiRGBA(255,32,16,255)); else imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "- PAUSED -", imguiRGBA(255,255,255,128)); diff --git a/RecastDemo/Source/Sample.cpp b/RecastDemo/Source/Sample.cpp index 4dffe9f..6743e7d 100644 --- a/RecastDemo/Source/Sample.cpp +++ b/RecastDemo/Source/Sample.cpp @@ -47,6 +47,9 @@ Sample::Sample() : resetCommonSettings(); m_navQuery = dtAllocNavMeshQuery(); m_crowd = dtAllocCrowd(); + + for (int i = 0; i < MAX_TOOLS; i++) + m_toolStates[i] = 0; } Sample::~Sample() @@ -55,6 +58,8 @@ Sample::~Sample() dtFreeNavMesh(m_navMesh); dtFreeCrowd(m_crowd); delete m_tool; + for (int i = 0; i < MAX_TOOLS; i++) + delete m_toolStates[i]; } void Sample::setTool(SampleTool* tool) @@ -204,5 +209,52 @@ void Sample::handleUpdate(const float dt) { if (m_tool) m_tool->handleUpdate(dt); + updateToolStates(dt); +} + + +void Sample::updateToolStates(const float dt) +{ + for (int i = 0; i < MAX_TOOLS; i++) + { + if (m_toolStates[i]) + m_toolStates[i]->handleUpdate(dt); + } +} + +void Sample::initToolStates(Sample* sample) +{ + for (int i = 0; i < MAX_TOOLS; i++) + { + if (m_toolStates[i]) + m_toolStates[i]->init(sample); + } +} + +void Sample::resetToolStates() +{ + for (int i = 0; i < MAX_TOOLS; i++) + { + if (m_toolStates[i]) + m_toolStates[i]->reset(); + } +} + +void Sample::renderToolStates() +{ + for (int i = 0; i < MAX_TOOLS; i++) + { + if (m_toolStates[i]) + m_toolStates[i]->handleRender(); + } +} + +void Sample::renderOverlayToolStates(double* proj, double* model, int* view) +{ + for (int i = 0; i < MAX_TOOLS; i++) + { + if (m_toolStates[i]) + m_toolStates[i]->handleRenderOverlay(proj, model, view); + } } diff --git a/RecastDemo/Source/Sample_SoloMesh.cpp b/RecastDemo/Source/Sample_SoloMesh.cpp index db21d92..83a78a0 100644 --- a/RecastDemo/Source/Sample_SoloMesh.cpp +++ b/RecastDemo/Source/Sample_SoloMesh.cpp @@ -320,6 +320,7 @@ void Sample_SoloMesh::handleRender() if (m_tool) m_tool->handleRender(); + renderToolStates(); glDepthMask(GL_TRUE); } @@ -328,6 +329,7 @@ void Sample_SoloMesh::handleRenderOverlay(double* proj, double* model, int* view { if (m_tool) m_tool->handleRenderOverlay(proj, model, view); + renderOverlayToolStates(proj, model, view); } void Sample_SoloMesh::handleMeshChanged(class InputGeom* geom) @@ -342,6 +344,8 @@ void Sample_SoloMesh::handleMeshChanged(class InputGeom* geom) m_tool->reset(); m_tool->init(this); } + resetToolStates(); + initToolStates(this); } @@ -683,6 +687,7 @@ bool Sample_SoloMesh::handleBuild() if (m_tool) m_tool->init(this); + initToolStates(this); return true; } diff --git a/RecastDemo/Source/Sample_TempObstacles.cpp b/RecastDemo/Source/Sample_TempObstacles.cpp index a55c0ab..714c6a1 100644 --- a/RecastDemo/Source/Sample_TempObstacles.cpp +++ b/RecastDemo/Source/Sample_TempObstacles.cpp @@ -167,6 +167,59 @@ struct LinearAllocator : public dtTileCacheAlloc } }; +struct MeshProcess : public dtTileCacheMeshProcess +{ + InputGeom* m_geom; + + inline MeshProcess() : m_geom(0) + { + } + + inline void init(InputGeom* geom) + { + m_geom = geom; + } + + virtual void process(struct dtNavMeshCreateParams* params, + unsigned char* polyAreas, unsigned short* polyFlags) + { + // Update poly flags from areas. + for (int i = 0; i < params->polyCount; ++i) + { + if (polyAreas[i] == DT_TILECACHE_WALKABLE_AREA) + polyAreas[i] = SAMPLE_POLYAREA_GROUND; + + if (polyAreas[i] == SAMPLE_POLYAREA_GROUND || + polyAreas[i] == SAMPLE_POLYAREA_GRASS || + polyAreas[i] == SAMPLE_POLYAREA_ROAD) + { + polyFlags[i] = SAMPLE_POLYFLAGS_WALK; + } + else if (polyAreas[i] == SAMPLE_POLYAREA_WATER) + { + polyFlags[i] = SAMPLE_POLYFLAGS_SWIM; + } + else if (polyAreas[i] == SAMPLE_POLYAREA_DOOR) + { + polyFlags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR; + } + } + + // Pass in off-mesh connections. + if (m_geom) + { + 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(); + } + } +}; + + static const int MAX_TILES = 32; @@ -422,9 +475,36 @@ void drawTiles(duDebugDraw* dd, dtTileCache* tc) } } - -void drawDetail(duDebugDraw* dd, dtTileCache* tc, const int tx, const int ty) + +enum DrawDetailType { + DRAWDETAIL_AREAS, + DRAWDETAIL_REGIONS, + DRAWDETAIL_CONTOURS, + DRAWDETAIL_MESH, +}; + +void drawDetail(duDebugDraw* dd, dtTileCache* tc, const int tx, const int ty, int type) +{ + struct TileCacheBuildContext + { + inline TileCacheBuildContext(struct dtTileCacheAlloc* a) : layer(0), lcset(0), lmesh(0), alloc(a) {} + inline ~TileCacheBuildContext() { purge(); } + void purge() + { + dtFreeTileCacheLayer(alloc, layer); + layer = 0; + dtFreeTileCacheContourSet(alloc, lcset); + lcset = 0; + dtFreeTileCachePolyMesh(alloc, lmesh); + lmesh = 0; + } + struct dtTileCacheLayer* layer; + struct dtTileCacheContourSet* lcset; + struct dtTileCachePolyMesh* lmesh; + struct dtTileCacheAlloc* alloc; + }; + const int MAX_TILES = 32; dtCompressedTileRef tiles[MAX_TILES]; const int ntiles = tc->getTilesAt(tx,ty,tiles,MAX_TILES); @@ -439,15 +519,56 @@ void drawDetail(duDebugDraw* dd, dtTileCache* tc, const int tx, const int ty) talloc->reset(); + TileCacheBuildContext bc(talloc); + const int walkableClimbVx = (int)(params->walkableClimb / params->ch); + dtStatus status; + // Decompress tile layer data. - dtTileCacheLayer* layer = 0; - dtStatus status = dtDecompressTileCacheLayer(talloc, tcomp, tile->data, tile->dataSize, &layer); + status = dtDecompressTileCacheLayer(talloc, tcomp, tile->data, tile->dataSize, &bc.layer); if (dtStatusFailed(status)) return; + if (type == DRAWDETAIL_AREAS) + { + duDebugDrawTileCacheLayerAreas(dd, *bc.layer, params->cs, params->ch); + continue; + } + + // Build navmesh + status = dtBuildTileCacheRegions(talloc, *bc.layer, walkableClimbVx); + if (dtStatusFailed(status)) + return; + if (type == DRAWDETAIL_REGIONS) + { + duDebugDrawTileCacheLayerRegions(dd, *bc.layer, params->cs, params->ch); + continue; + } - duDebugDrawTileCacheLayer(dd, *layer, params->cs, params->ch); + bc.lcset = dtAllocTileCacheContourSet(talloc); + if (!bc.lcset) + return; + status = dtBuildTileCacheContours(talloc, *bc.layer, walkableClimbVx, + params->maxSimplificationError, *bc.lcset); + if (dtStatusFailed(status)) + return; + if (type == DRAWDETAIL_CONTOURS) + { + duDebugDrawTileCacheContours(dd, *bc.lcset, tile->header->bmin, params->cs, params->ch); + continue; + } - dtFreeTileCacheLayer(talloc, layer); + bc.lmesh = dtAllocTileCachePolyMesh(talloc); + if (!bc.lmesh) + return; + status = dtBuildTileCachePolyMesh(talloc, *bc.lcset, *bc.lmesh); + if (dtStatusFailed(status)) + return; + + if (type == DRAWDETAIL_MESH) + { + duDebugDrawTileCachePolyMesh(dd, *bc.lmesh, tile->header->bmin, params->cs, params->ch); + continue; + } + } } @@ -544,13 +665,15 @@ class TempObstacleHilightTool : public SampleTool float m_hitPos[3]; bool m_hitPosSet; float m_agentRadius; + int m_drawType; public: TempObstacleHilightTool() : m_sample(0), m_hitPosSet(false), - m_agentRadius(0) + m_agentRadius(0), + m_drawType(DRAWDETAIL_AREAS) { m_hitPos[0] = m_hitPos[1] = m_hitPos[2] = 0; } @@ -572,6 +695,15 @@ public: { imguiLabel("Highlight Tile Cache"); imguiValue("Click LMB to highlight a tile."); + imguiSeparator(); + if (imguiCheck("Draw Areas", m_drawType == DRAWDETAIL_AREAS)) + m_drawType = DRAWDETAIL_AREAS; + if (imguiCheck("Draw Regions", m_drawType == DRAWDETAIL_REGIONS)) + m_drawType = DRAWDETAIL_REGIONS; + if (imguiCheck("Draw Contours", m_drawType == DRAWDETAIL_CONTOURS)) + m_drawType = DRAWDETAIL_CONTOURS; + if (imguiCheck("Draw Mesh", m_drawType == DRAWDETAIL_MESH)) + m_drawType = DRAWDETAIL_MESH; } virtual void handleClick(const float* /*s*/, const float* p, bool /*shift*/) @@ -607,7 +739,7 @@ public: { int tx=0, ty=0; m_sample->getTilePos(m_hitPos, tx, ty); - m_sample->renderCachedTile(tx,ty); + m_sample->renderCachedTile(tx,ty,m_drawType); } } @@ -703,6 +835,7 @@ Sample_TempObstacles::Sample_TempObstacles() : m_talloc = new LinearAllocator(32000); m_tcomp = new FastLZCompressor; + m_tmproc = new MeshProcess; setTool(new TempObstacleCreateTool); } @@ -915,7 +1048,7 @@ void Sample_TempObstacles::handleRender() m_drawMode == DRAWMODE_NAVMESH_INVIS)) { if (m_drawMode != DRAWMODE_NAVMESH_INVIS) - duDebugDrawNavMeshWithClosedList(&dd, *m_navMesh, *m_navQuery, m_navMeshDrawFlags|DU_DRAWNAVMESH_COLOR_TILES); + duDebugDrawNavMeshWithClosedList(&dd, *m_navMesh, *m_navQuery, m_navMeshDrawFlags/*|DU_DRAWNAVMESH_COLOR_TILES*/); if (m_drawMode == DRAWMODE_NAVMESH_BVTREE) duDebugDrawNavMeshBVTree(&dd, *m_navMesh); if (m_drawMode == DRAWMODE_NAVMESH_PORTALS) @@ -932,15 +1065,16 @@ void Sample_TempObstacles::handleRender() if (m_tool) m_tool->handleRender(); + renderToolStates(); glDepthMask(GL_TRUE); } -void Sample_TempObstacles::renderCachedTile(const int tx, const int ty) +void Sample_TempObstacles::renderCachedTile(const int tx, const int ty, const int type) { DebugDrawGL dd; if (m_tileCache) - drawDetail(&dd,m_tileCache,tx,ty); + drawDetail(&dd,m_tileCache,tx,ty,type); } void Sample_TempObstacles::renderCachedTileOverlay(const int tx, const int ty, double* proj, double* model, int* view) @@ -953,6 +1087,7 @@ void Sample_TempObstacles::handleRenderOverlay(double* proj, double* model, int* { if (m_tool) m_tool->handleRenderOverlay(proj, model, view); + renderOverlayToolStates(proj, model, view); // Stats /* imguiDrawRect(280,10,300,100,imguiRGBA(0,0,0,64)); @@ -992,7 +1127,10 @@ void Sample_TempObstacles::handleMeshChanged(class InputGeom* geom) { m_tool->reset(); m_tool->init(this); + m_tmproc->init(m_geom); } + resetToolStates(); + initToolStates(this); } void Sample_TempObstacles::addTempObstacle(const float* pos) @@ -1034,6 +1172,8 @@ bool Sample_TempObstacles::handleBuild() m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: No vertices and triangles."); return false; } + + m_tmproc->init(m_geom); // Init cache const float* bmin = m_geom->getMeshBoundsMin(); @@ -1090,7 +1230,7 @@ bool Sample_TempObstacles::handleBuild() m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not allocate tile cache."); return false; } - status = m_tileCache->init(&tcparams, m_talloc, m_tcomp); + status = m_tileCache->init(&tcparams, m_talloc, m_tcomp, m_tmproc); if (dtStatusFailed(status)) { m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init tile cache."); @@ -1189,6 +1329,7 @@ bool Sample_TempObstacles::handleBuild() if (m_tool) m_tool->init(this); + initToolStates(this); return true; } diff --git a/RecastDemo/Source/Sample_TileMesh.cpp b/RecastDemo/Source/Sample_TileMesh.cpp index 7a2ab7d..618cdb7 100644 --- a/RecastDemo/Source/Sample_TileMesh.cpp +++ b/RecastDemo/Source/Sample_TileMesh.cpp @@ -651,7 +651,8 @@ void Sample_TileMesh::handleRender() if (m_tool) m_tool->handleRender(); - + renderToolStates(); + glDepthMask(GL_TRUE); } @@ -670,6 +671,7 @@ void Sample_TileMesh::handleRenderOverlay(double* proj, double* model, int* view if (m_tool) m_tool->handleRenderOverlay(proj, model, view); + renderOverlayToolStates(proj, model, view); } void Sample_TileMesh::handleMeshChanged(class InputGeom* geom) @@ -686,6 +688,8 @@ void Sample_TileMesh::handleMeshChanged(class InputGeom* geom) m_tool->reset(); m_tool->init(this); } + resetToolStates(); + initToolStates(this); } bool Sample_TileMesh::handleBuild() @@ -733,6 +737,7 @@ bool Sample_TileMesh::handleBuild() if (m_tool) m_tool->init(this); + initToolStates(this); return true; }