diff --git a/Detour/Include/DetourStatNavMesh.h b/Detour/Include/DetourStatNavMesh.h index 500fca5..281c165 100755 --- a/Detour/Include/DetourStatNavMesh.h +++ b/Detour/Include/DetourStatNavMesh.h @@ -64,11 +64,11 @@ public: dtStatNavMesh(); ~dtStatNavMesh(); - // Initializes the path finder with path data. + // Initializes the navmesh with data. // Params: - // data - (in) Pointer to path data. - // dataSize - (in) size of the path data. - // ownsData - (in) Flag indicating if the pathfinder should delete the data. + // data - (in) Pointer to navmesh data. + // dataSize - (in) size of the navmesh data. + // ownsData - (in) Flag indicating if the navmesh should own and delete the data. bool init(unsigned char* data, int dataSize, bool ownsData); // Finds the nearest navigation polygon around the center location. diff --git a/RecastDemo/Bin/Recast.app/Contents/MacOS/Recast b/RecastDemo/Bin/Recast.app/Contents/MacOS/Recast index 01c0a38..7d19718 100755 Binary files a/RecastDemo/Bin/Recast.app/Contents/MacOS/Recast and b/RecastDemo/Bin/Recast.app/Contents/MacOS/Recast differ diff --git a/RecastDemo/Build/Xcode/Recast.xcodeproj/memon.pbxuser b/RecastDemo/Build/Xcode/Recast.xcodeproj/memon.pbxuser index 052167d..f91b9cb 100644 --- a/RecastDemo/Build/Xcode/Recast.xcodeproj/memon.pbxuser +++ b/RecastDemo/Build/Xcode/Recast.xcodeproj/memon.pbxuser @@ -16,7 +16,7 @@ 8D1107260486CEB800E47090 /* Recast */, ); breakpoints = ( - 6B0249B11003783F00CF7107 /* Sample_TileMesh.cpp:833 */, + 6B0249B11003783F00CF7107 /* Sample_TileMesh.cpp:784 */, 6B0249ED10037C0A00CF7107 /* DetourTileNavMesh.cpp:1 */, 6B0249EF10037C0C00CF7107 /* DetourTileNavMesh.cpp:1 */, 6B024AC01004AB3900CF7107 /* DetourTileNavMesh.cpp:1 */, @@ -610,6 +610,87 @@ 6B555F4E100B4C5800247EA3 /* PBXTextBookmark */ = 6B555F4E100B4C5800247EA3 /* PBXTextBookmark */; 6B555F4F100B4C5800247EA3 /* PBXTextBookmark */ = 6B555F4F100B4C5800247EA3 /* PBXTextBookmark */; 6B555F52100B4CE300247EA3 /* PBXTextBookmark */ = 6B555F52100B4CE300247EA3 /* PBXTextBookmark */; + 6B555F5C100B53F500247EA3 /* PBXTextBookmark */ = 6B555F5C100B53F500247EA3 /* PBXTextBookmark */; + 6B555F5D100B53F500247EA3 /* PBXTextBookmark */ = 6B555F5D100B53F500247EA3 /* PBXTextBookmark */; + 6B555F5E100B53F500247EA3 /* PBXTextBookmark */ = 6B555F5E100B53F500247EA3 /* PBXTextBookmark */; + 6B555F5F100B53F500247EA3 /* PBXTextBookmark */ = 6B555F5F100B53F500247EA3 /* PBXTextBookmark */; + 6B555F60100B53F500247EA3 /* PBXTextBookmark */ = 6B555F60100B53F500247EA3 /* PBXTextBookmark */; + 6B555F61100B53F500247EA3 /* PBXTextBookmark */ = 6B555F61100B53F500247EA3 /* PBXTextBookmark */; + 6B555F62100B53F500247EA3 /* PBXTextBookmark */ = 6B555F62100B53F500247EA3 /* PBXTextBookmark */; + 6B555F63100B53F500247EA3 /* PBXTextBookmark */ = 6B555F63100B53F500247EA3 /* PBXTextBookmark */; + 6B555F64100B53F500247EA3 /* PBXTextBookmark */ = 6B555F64100B53F500247EA3 /* PBXTextBookmark */; + 6B555F65100B53F500247EA3 /* PBXTextBookmark */ = 6B555F65100B53F500247EA3 /* PBXTextBookmark */; + 6B555F66100B53F500247EA3 /* PBXTextBookmark */ = 6B555F66100B53F500247EA3 /* PBXTextBookmark */; + 6B555F67100B53F500247EA3 /* PBXTextBookmark */ = 6B555F67100B53F500247EA3 /* PBXTextBookmark */; + 6B555F68100B53F500247EA3 /* PBXTextBookmark */ = 6B555F68100B53F500247EA3 /* PBXTextBookmark */; + 6B555F69100B53F500247EA3 /* PBXTextBookmark */ = 6B555F69100B53F500247EA3 /* PBXTextBookmark */; + 6B555F6A100B53F500247EA3 /* PBXTextBookmark */ = 6B555F6A100B53F500247EA3 /* PBXTextBookmark */; + 6B555F6B100B53F500247EA3 /* PBXTextBookmark */ = 6B555F6B100B53F500247EA3 /* PBXTextBookmark */; + 6B555F6C100B53F500247EA3 /* PBXTextBookmark */ = 6B555F6C100B53F500247EA3 /* PBXTextBookmark */; + 6B555F6D100B53F500247EA3 /* PBXTextBookmark */ = 6B555F6D100B53F500247EA3 /* PBXTextBookmark */; + 6B555F6E100B53F500247EA3 /* PBXTextBookmark */ = 6B555F6E100B53F500247EA3 /* PBXTextBookmark */; + 6B555F6F100B53F500247EA3 /* PBXTextBookmark */ = 6B555F6F100B53F500247EA3 /* PBXTextBookmark */; + 6B555F70100B53F500247EA3 /* PBXTextBookmark */ = 6B555F70100B53F500247EA3 /* PBXTextBookmark */; + 6B555F71100B53F500247EA3 /* PBXTextBookmark */ = 6B555F71100B53F500247EA3 /* PBXTextBookmark */; + 6B555F72100B53F500247EA3 /* PBXTextBookmark */ = 6B555F72100B53F500247EA3 /* PBXTextBookmark */; + 6B555F73100B53F500247EA3 /* PBXTextBookmark */ = 6B555F73100B53F500247EA3 /* PBXTextBookmark */; + 6B555F74100B541500247EA3 /* PBXTextBookmark */ = 6B555F74100B541500247EA3 /* PBXTextBookmark */; + 6B555F75100B541900247EA3 /* PBXTextBookmark */ = 6B555F75100B541900247EA3 /* PBXTextBookmark */; + 6B555F76100B541900247EA3 /* PBXTextBookmark */ = 6B555F76100B541900247EA3 /* PBXTextBookmark */; + 6B555F77100B54CE00247EA3 /* PBXTextBookmark */ = 6B555F77100B54CE00247EA3 /* PBXTextBookmark */; + 6B555F78100B54CE00247EA3 /* PBXTextBookmark */ = 6B555F78100B54CE00247EA3 /* PBXTextBookmark */; + 6B555F79100B54CE00247EA3 /* PBXTextBookmark */ = 6B555F79100B54CE00247EA3 /* PBXTextBookmark */; + 6B555F7A100B54CE00247EA3 /* PBXTextBookmark */ = 6B555F7A100B54CE00247EA3 /* PBXTextBookmark */; + 6B555F7B100B54CE00247EA3 /* PBXTextBookmark */ = 6B555F7B100B54CE00247EA3 /* PBXTextBookmark */; + 6B555F7C100B54CE00247EA3 /* PBXTextBookmark */ = 6B555F7C100B54CE00247EA3 /* PBXTextBookmark */; + 6B555F82100B557700247EA3 /* PBXTextBookmark */ = 6B555F82100B557700247EA3 /* PBXTextBookmark */; + 6B555F83100B557700247EA3 /* PBXTextBookmark */ = 6B555F83100B557700247EA3 /* PBXTextBookmark */; + 6B555F84100B557700247EA3 /* PBXTextBookmark */ = 6B555F84100B557700247EA3 /* PBXTextBookmark */; + 6B555F85100B557700247EA3 /* PBXTextBookmark */ = 6B555F85100B557700247EA3 /* PBXTextBookmark */; + 6B555F88100B577A00247EA3 /* PBXTextBookmark */ = 6B555F88100B577A00247EA3 /* PBXTextBookmark */; + 6B555F89100B577A00247EA3 /* PBXTextBookmark */ = 6B555F89100B577A00247EA3 /* PBXTextBookmark */; + 6B555F8A100B577A00247EA3 /* PBXTextBookmark */ = 6B555F8A100B577A00247EA3 /* PBXTextBookmark */; + 6B555F8B100B577A00247EA3 /* PBXTextBookmark */ = 6B555F8B100B577A00247EA3 /* PBXTextBookmark */; + 6B555F8C100B577A00247EA3 /* PBXTextBookmark */ = 6B555F8C100B577A00247EA3 /* PBXTextBookmark */; + 6B555F8D100B577A00247EA3 /* PBXTextBookmark */ = 6B555F8D100B577A00247EA3 /* PBXTextBookmark */; + 6B555F8E100B577A00247EA3 /* PBXTextBookmark */ = 6B555F8E100B577A00247EA3 /* PBXTextBookmark */; + 6B555F8F100B577A00247EA3 /* PBXTextBookmark */ = 6B555F8F100B577A00247EA3 /* PBXTextBookmark */; + 6B555F90100B577A00247EA3 /* PBXTextBookmark */ = 6B555F90100B577A00247EA3 /* PBXTextBookmark */; + 6B555F91100B577A00247EA3 /* PBXTextBookmark */ = 6B555F91100B577A00247EA3 /* PBXTextBookmark */; + 6B555F92100B577A00247EA3 /* PBXTextBookmark */ = 6B555F92100B577A00247EA3 /* PBXTextBookmark */; + 6B555F93100B577A00247EA3 /* PBXTextBookmark */ = 6B555F93100B577A00247EA3 /* PBXTextBookmark */; + 6B555F94100B577A00247EA3 /* PBXTextBookmark */ = 6B555F94100B577A00247EA3 /* PBXTextBookmark */; + 6B555F95100B577A00247EA3 /* PBXTextBookmark */ = 6B555F95100B577A00247EA3 /* PBXTextBookmark */; + 6B555F96100B577A00247EA3 /* PBXTextBookmark */ = 6B555F96100B577A00247EA3 /* PBXTextBookmark */; + 6B555F97100B577A00247EA3 /* PBXTextBookmark */ = 6B555F97100B577A00247EA3 /* PBXTextBookmark */; + 6B555F98100B577A00247EA3 /* PBXTextBookmark */ = 6B555F98100B577A00247EA3 /* PBXTextBookmark */; + 6B555F99100B577A00247EA3 /* PBXTextBookmark */ = 6B555F99100B577A00247EA3 /* PBXTextBookmark */; + 6B555F9A100B577A00247EA3 /* PBXTextBookmark */ = 6B555F9A100B577A00247EA3 /* PBXTextBookmark */; + 6B555F9B100B577A00247EA3 /* PBXTextBookmark */ = 6B555F9B100B577A00247EA3 /* PBXTextBookmark */; + 6B555F9E100B57B500247EA3 /* PBXTextBookmark */ = 6B555F9E100B57B500247EA3 /* PBXTextBookmark */; + 6B555F9F100B57B500247EA3 /* PBXTextBookmark */ = 6B555F9F100B57B500247EA3 /* PBXTextBookmark */; + 6B555FA0100B57B500247EA3 /* PBXTextBookmark */ = 6B555FA0100B57B500247EA3 /* PBXTextBookmark */; + 6B555FA1100B57B500247EA3 /* PBXTextBookmark */ = 6B555FA1100B57B500247EA3 /* PBXTextBookmark */; + 6B555FA2100B57CA00247EA3 /* PBXTextBookmark */ = 6B555FA2100B57CA00247EA3 /* PBXTextBookmark */; + 6B555FA3100B57CC00247EA3 /* PBXTextBookmark */ = 6B555FA3100B57CC00247EA3 /* PBXTextBookmark */; + 6B555FA4100B57CC00247EA3 /* PBXTextBookmark */ = 6B555FA4100B57CC00247EA3 /* PBXTextBookmark */; + 6B555FA8100B589200247EA3 /* PBXTextBookmark */ = 6B555FA8100B589200247EA3 /* PBXTextBookmark */; + 6B555FA9100B589200247EA3 /* PBXTextBookmark */ = 6B555FA9100B589200247EA3 /* PBXTextBookmark */; + 6B555FAA100B589200247EA3 /* PBXTextBookmark */ = 6B555FAA100B589200247EA3 /* PBXTextBookmark */; + 6B555FAB100B589200247EA3 /* PBXTextBookmark */ = 6B555FAB100B589200247EA3 /* PBXTextBookmark */; + 6B555FAC100B589200247EA3 /* PBXTextBookmark */ = 6B555FAC100B589200247EA3 /* PBXTextBookmark */; + 6B555FB0100B595C00247EA3 /* PBXTextBookmark */ = 6B555FB0100B595C00247EA3 /* PBXTextBookmark */; + 6B555FB1100B595C00247EA3 /* PBXTextBookmark */ = 6B555FB1100B595C00247EA3 /* PBXTextBookmark */; + 6B555FB2100B595C00247EA3 /* PBXTextBookmark */ = 6B555FB2100B595C00247EA3 /* PBXTextBookmark */; + 6B555FB3100B595C00247EA3 /* PBXTextBookmark */ = 6B555FB3100B595C00247EA3 /* PBXTextBookmark */; + 6B555FB4100B595C00247EA3 /* PBXTextBookmark */ = 6B555FB4100B595C00247EA3 /* PBXTextBookmark */; + 6B555FB5100B595C00247EA3 /* PBXTextBookmark */ = 6B555FB5100B595C00247EA3 /* PBXTextBookmark */; + 6B555FB6100B595C00247EA3 /* PBXTextBookmark */ = 6B555FB6100B595C00247EA3 /* PBXTextBookmark */; + 6B555FB7100B595C00247EA3 /* PBXTextBookmark */ = 6B555FB7100B595C00247EA3 /* PBXTextBookmark */; + 6B555FBA100B598E00247EA3 /* PBXTextBookmark */ = 6B555FBA100B598E00247EA3 /* PBXTextBookmark */; + 6B555FBD100B59B600247EA3 /* PBXTextBookmark */ = 6B555FBD100B59B600247EA3 /* PBXTextBookmark */; + 6B555FBF100B5A0000247EA3 /* PBXTextBookmark */ = 6B555FBF100B5A0000247EA3 /* PBXTextBookmark */; + 6B555FC0100B5A3300247EA3 /* PBXTextBookmark */ = 6B555FC0100B5A3300247EA3 /* PBXTextBookmark */; 6B7707B90FBD66CF00D21BAE = 6B7707B90FBD66CF00D21BAE /* PBXTextBookmark */; 6B7707F00FBD90F100D21BAE = 6B7707F00FBD90F100D21BAE /* PBXTextBookmark */; 6B7707F70FBD90F100D21BAE = 6B7707F70FBD90F100D21BAE /* PBXTextBookmark */; @@ -689,7 +770,7 @@ vrLen = 558; vrLoc = 362; }; - 6B0249B11003783F00CF7107 /* Sample_TileMesh.cpp:833 */ = { + 6B0249B11003783F00CF7107 /* Sample_TileMesh.cpp:784 */ = { isa = PBXFileBreakpoint; actions = ( ); @@ -701,7 +782,7 @@ functionName = "BuilderTiledMesh::toolRecalc()"; hitCount = 0; ignoreCount = 0; - lineNumber = 833; + lineNumber = 784; location = Recast; modificationTime = 268741438.169822; state = 1; @@ -782,7 +863,7 @@ fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; name = "DetourTiledNavMesh.h: 137"; rLen = 0; - rLoc = 5005; + rLoc = 9483; rType = 0; vrLen = 1459; vrLoc = 3572; @@ -1081,7 +1162,7 @@ fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; name = "DetourTiledNavMesh.cpp: 1073"; rLen = 0; - rLoc = 27719; + rLoc = 12201; rType = 0; vrLen = 526; vrLoc = 26309; @@ -1161,7 +1242,7 @@ fRef = 6BDD9E050F91112200904EEF /* DetourStatNavMesh.h */; name = "DetourStatNavMesh.h: 176"; rLen = 0; - rLoc = 7183; + rLoc = 7185; rType = 0; vrLen = 1247; vrLoc = 59; @@ -1171,7 +1252,7 @@ fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; name = "DetourTileNavMesh.h: 19"; rLen = 0; - rLoc = 938; + rLoc = 937; rType = 0; vrLen = 1075; vrLoc = 784; @@ -1546,16 +1627,16 @@ }; 6B25B6150FFA62BE004F1BC4 /* Sample_StatMesh.cpp */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {915, 5568}}"; - sepNavSelRange = "{162, 0}"; - sepNavVisRange = "{0, 498}"; + sepNavIntBoundsRect = "{{0, 0}, {915, 5200}}"; + sepNavSelRange = "{7561, 0}"; + sepNavVisRange = "{7958, 728}"; }; }; 6B25B6160FFA62BE004F1BC4 /* Sample_StatMeshSimple.cpp */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {915, 8588}}"; - sepNavSelRange = "{143, 0}"; - sepNavVisRange = "{0, 513}"; + sepNavIntBoundsRect = "{{0, 0}, {915, 8304}}"; + sepNavSelRange = "{4247, 49}"; + sepNavVisRange = "{3933, 719}"; }; }; 6B25B6180FFA62BE004F1BC4 /* main.cpp */ = { @@ -1585,16 +1666,16 @@ }; 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1223, 14524}}"; - sepNavSelRange = "{1062, 0}"; - sepNavVisRange = "{784, 548}"; + sepNavIntBoundsRect = "{{0, 0}, {915, 14464}}"; + sepNavSelRange = "{14722, 0}"; + sepNavVisRange = "{14230, 802}"; }; }; 6B2AEC550FFB89E7005BE9CC /* Sample_StatMeshTiled.cpp */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {950, 15932}}"; - sepNavSelRange = "{143, 0}"; - sepNavVisRange = "{0, 527}"; + sepNavIntBoundsRect = "{{0, 0}, {915, 15520}}"; + sepNavSelRange = "{5369, 89}"; + sepNavVisRange = "{4879, 630}"; }; }; 6B2AEC570FFB89F4005BE9CC /* Sample_StatMeshTiled.h */ = { @@ -1606,16 +1687,16 @@ }; 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {915, 3296}}"; - sepNavSelRange = "{2613, 0}"; - sepNavVisRange = "{6136, 1040}"; + sepNavIntBoundsRect = "{{0, 0}, {915, 4960}}"; + sepNavSelRange = "{4189, 0}"; + sepNavVisRange = "{3741, 1240}"; }; }; 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {915, 20864}}"; - sepNavSelRange = "{24104, 0}"; - sepNavVisRange = "{23722, 893}"; + sepNavIntBoundsRect = "{{0, 0}, {915, 21872}}"; + sepNavSelRange = "{11834, 0}"; + sepNavVisRange = "{11590, 460}"; }; }; 6B2AEC5C0FFB8AB0005BE9CC /* PBXTextBookmark */ = { @@ -2900,9 +2981,9 @@ }; 6B555DB0100B212E00247EA3 /* imguiRenderGL.cpp */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {915, 7024}}"; - sepNavSelRange = "{919, 0}"; - sepNavVisRange = "{0, 1274}"; + sepNavIntBoundsRect = "{{0, 0}, {1219, 7152}}"; + sepNavSelRange = "{8401, 0}"; + sepNavVisRange = "{7552, 396}"; }; }; 6B555DBD100B236A00247EA3 /* PBXTextBookmark */ = { @@ -3953,7 +4034,7 @@ fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; name = "Sample_TileMesh.cpp: 88"; rLen = 0; - rLoc = 2195; + rLoc = 2233; rType = 0; vrLen = 628; vrLoc = 2008; @@ -4091,7 +4172,7 @@ fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; name = "Sample_TileMesh.cpp: 88"; rLen = 0; - rLoc = 2195; + rLoc = 2233; rType = 0; vrLen = 628; vrLoc = 2008; @@ -4291,7 +4372,7 @@ fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; name = "Sample_TileMesh.cpp: 492"; rLen = 0; - rLoc = 13338; + rLoc = 11518; rType = 0; vrLen = 921; vrLoc = 12886; @@ -4371,7 +4452,7 @@ fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; name = "Sample_TileMesh.cpp: 492"; rLen = 0; - rLoc = 13338; + rLoc = 11518; rType = 0; vrLen = 921; vrLoc = 12886; @@ -4751,7 +4832,7 @@ fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; name = "Sample_TileMesh.cpp: 493"; rLen = 0; - rLoc = 13424; + rLoc = 11604; rType = 0; vrLen = 879; vrLoc = 12888; @@ -4881,7 +4962,7 @@ fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; name = "Sample_TileMesh.cpp: 493"; rLen = 0; - rLoc = 13424; + rLoc = 11604; rType = 0; vrLen = 879; vrLoc = 12888; @@ -5501,7 +5582,7 @@ fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; name = "DetourTileNavMesh.h: 70"; rLen = 0; - rLoc = 2716; + rLoc = 2714; rType = 0; vrLen = 620; vrLoc = 2419; @@ -5511,7 +5592,7 @@ fRef = 6BDD9E050F91112200904EEF /* DetourStatNavMesh.h */; name = "DetourStatNavMesh.h: 179"; rLen = 95; - rLoc = 7147; + rLoc = 7149; rType = 0; vrLen = 1013; vrLoc = 6323; @@ -5619,7 +5700,7 @@ fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; name = "DetourTileNavMesh.h: 70"; rLen = 0; - rLoc = 2716; + rLoc = 2714; rType = 0; vrLen = 620; vrLoc = 2419; @@ -5649,7 +5730,7 @@ fRef = 6BDD9E050F91112200904EEF /* DetourStatNavMesh.h */; name = "DetourStatNavMesh.h: 179"; rLen = 95; - rLoc = 7147; + rLoc = 7149; rType = 0; vrLen = 1013; vrLoc = 6323; @@ -5709,7 +5790,7 @@ fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; name = "DetourTileNavMesh.cpp: 381"; rLen = 0; - rLoc = 10668; + rLoc = 10352; rType = 0; vrLen = 402; vrLoc = 9892; @@ -5767,7 +5848,7 @@ fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; name = "DetourTileNavMesh.cpp: 426"; rLen = 0; - rLoc = 11437; + rLoc = 11589; rType = 0; vrLen = 444; vrLoc = 10615; @@ -5787,7 +5868,7 @@ fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; name = "DetourTileNavMesh.cpp: 382"; rLen = 0; - rLoc = 10669; + rLoc = 10353; rType = 0; vrLen = 370; vrLoc = 9892; @@ -5807,7 +5888,7 @@ fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; name = "DetourTileNavMesh.cpp: 381"; rLen = 0; - rLoc = 10668; + rLoc = 10352; rType = 0; vrLen = 402; vrLoc = 9892; @@ -5857,7 +5938,7 @@ fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; name = "DetourTileNavMesh.h: 61"; rLen = 0; - rLoc = 2613; + rLoc = 2611; rType = 0; vrLen = 1040; vrLoc = 6136; @@ -5867,7 +5948,7 @@ comments = "error: expected `;' before ')' token"; fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; rLen = 1; - rLoc = 283; + rLoc = 278; rType = 1; }; 6B555F45100B4C5800247EA3 /* PBXTextBookmark */ = { @@ -5885,7 +5966,7 @@ fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; name = "DetourTileNavMesh.h: 61"; rLen = 0; - rLoc = 2613; + rLoc = 2611; rType = 0; vrLen = 576; vrLoc = 2212; @@ -5895,7 +5976,7 @@ fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; name = "DetourTileNavMesh.cpp: 376"; rLen = 0; - rLoc = 10580; + rLoc = 10262; rType = 0; vrLen = 693; vrLoc = 9654; @@ -5905,7 +5986,7 @@ fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; name = "DetourTileNavMesh.h: 61"; rLen = 0; - rLoc = 2613; + rLoc = 2611; rType = 0; vrLen = 781; vrLoc = 2058; @@ -5915,7 +5996,7 @@ fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; name = "DetourTileNavMesh.cpp: 378"; rLen = 0; - rLoc = 10610; + rLoc = 10292; rType = 0; vrLen = 548; vrLoc = 9654; @@ -5934,8 +6015,8 @@ isa = PBXTextBookmark; fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; name = "DetourTileNavMesh.cpp: 923"; - rLen = 222; - rLoc = 23882; + rLen = 0; + rLoc = 12201; rType = 0; vrLen = 926; vrLoc = 22891; @@ -5955,7 +6036,7 @@ fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; name = "DetourTileNavMesh.cpp: 922"; rLen = 0; - rLoc = 23848; + rLoc = 12201; rType = 0; vrLen = 926; vrLoc = 22891; @@ -5965,7 +6046,7 @@ fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; name = "DetourTileNavMesh.h: 61"; rLen = 0; - rLoc = 2613; + rLoc = 2611; rType = 0; vrLen = 1040; vrLoc = 6136; @@ -5975,7 +6056,7 @@ fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; name = "DetourTileNavMesh.cpp: 275"; rLen = 0; - rLoc = 7462; + rLoc = 7347; rType = 0; vrLen = 803; vrLoc = 7247; @@ -5985,11 +6066,815 @@ fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; name = "DetourTileNavMesh.cpp: 943"; rLen = 0; - rLoc = 24104; + rLoc = 12201; rType = 0; vrLen = 893; vrLoc = 23722; }; + 6B555F5C100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6BDD9E050F91112200904EEF /* DetourStatNavMesh.h */; + name = "DetourStatNavMesh.h: 67"; + rLen = 0; + rLoc = 1901; + rType = 0; + vrLen = 1236; + vrLoc = 1851; + }; + 6B555F5D100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 636"; + rLen = 0; + rLoc = 14069; + rType = 0; + vrLen = 712; + vrLoc = 16084; + }; + 6B555F5E100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6BDD9E070F91113800904EEF /* DetourDebugDraw.cpp */; + name = "DetourDebugDraw.cpp: 394"; + rLen = 0; + rLoc = 10003; + rType = 0; + vrLen = 771; + vrLoc = 9621; + }; + 6B555F5F100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 241"; + rLen = 0; + rLoc = 9819; + rType = 0; + vrLen = 1166; + vrLoc = 9275; + }; + 6B555F60100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + comments = "error: 'getNeighbourTile' was not declared in this scope"; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + rLen = 1; + rLoc = 381; + rType = 1; + }; + 6B555F61100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 349"; + rLen = 0; + rLoc = 8059; + rType = 0; + vrLen = 869; + vrLoc = 8419; + }; + 6B555F62100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 114"; + rLen = 0; + rLoc = 4092; + rType = 0; + vrLen = 981; + vrLoc = 3430; + }; + 6B555F63100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 327"; + rLen = 0; + rLoc = 8926; + rType = 0; + vrLen = 776; + vrLoc = 8618; + }; + 6B555F64100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 116"; + rLen = 0; + rLoc = 4091; + rType = 0; + vrLen = 1052; + vrLoc = 3452; + }; + 6B555F65100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 329"; + rLen = 0; + rLoc = 9009; + rType = 0; + vrLen = 873; + vrLoc = 9008; + }; + 6B555F66100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 127"; + rLen = 0; + rLoc = 4729; + rType = 0; + vrLen = 1086; + vrLoc = 3462; + }; + 6B555F67100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 437"; + rLen = 0; + rLoc = 11982; + rType = 0; + vrLen = 616; + vrLoc = 10849; + }; + 6B555F68100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 127"; + rLen = 0; + rLoc = 4729; + rType = 0; + vrLen = 1086; + vrLoc = 3462; + }; + 6B555F69100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 434"; + rLen = 0; + rLoc = 11941; + rType = 0; + vrLen = 539; + vrLoc = 10824; + }; + 6B555F6A100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 128"; + rLen = 0; + rLoc = 4730; + rType = 0; + vrLen = 1113; + vrLoc = 3462; + }; + 6B555F6B100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 439"; + rLen = 0; + rLoc = 11982; + rType = 0; + vrLen = 581; + vrLoc = 10824; + }; + 6B555F6C100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 144"; + rLen = 0; + rLoc = 5258; + rType = 0; + vrLen = 1338; + vrLoc = 4292; + }; + 6B555F6D100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 92"; + rLen = 0; + rLoc = 3021; + rType = 0; + vrLen = 705; + vrLoc = 2528; + }; + 6B555F6E100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 636"; + rLen = 0; + rLoc = 14069; + rType = 0; + vrLen = 712; + vrLoc = 16084; + }; + 6B555F6F100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6BDD9E070F91113800904EEF /* DetourDebugDraw.cpp */; + name = "DetourDebugDraw.cpp: 394"; + rLen = 0; + rLoc = 10003; + rType = 0; + vrLen = 771; + vrLoc = 9621; + }; + 6B555F70100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 143"; + rLen = 0; + rLoc = 5219; + rType = 0; + vrLen = 1302; + vrLoc = 4292; + }; + 6B555F71100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 1322"; + rLen = 0; + rLoc = 12201; + rType = 0; + vrLen = 686; + vrLoc = 33504; + }; + 6B555F72100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 241"; + rLen = 0; + rLoc = 9819; + rType = 0; + vrLen = 1166; + vrLoc = 9275; + }; + 6B555F73100B53F500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 370"; + rLen = 0; + rLoc = 10294; + rType = 0; + vrLen = 506; + vrLoc = 9725; + }; + 6B555F74100B541500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 369"; + rLen = 0; + rLoc = 10291; + rType = 0; + vrLen = 535; + vrLoc = 9788; + }; + 6B555F75100B541900247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B555DB0100B212E00247EA3 /* imguiRenderGL.cpp */; + name = "imguiRenderGL.cpp: 360"; + rLen = 0; + rLoc = 8401; + rType = 0; + vrLen = 396; + vrLoc = 7552; + }; + 6B555F76100B541900247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 369"; + rLen = 0; + rLoc = 10291; + rType = 0; + vrLen = 296; + vrLoc = 9863; + }; + 6B555F77100B54CE00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 368"; + rLen = 0; + rLoc = 10262; + rType = 0; + vrLen = 426; + vrLoc = 10066; + }; + 6B555F78100B54CE00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 259"; + rLen = 0; + rLoc = 10547; + rType = 0; + vrLen = 1206; + vrLoc = 9497; + }; + 6B555F79100B54CE00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 368"; + rLen = 0; + rLoc = 10262; + rType = 0; + vrLen = 426; + vrLoc = 10066; + }; + 6B555F7A100B54CE00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 259"; + rLen = 0; + rLoc = 10547; + rType = 0; + vrLen = 1206; + vrLoc = 9497; + }; + 6B555F7B100B54CE00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 368"; + rLen = 0; + rLoc = 10262; + rType = 0; + vrLen = 426; + vrLoc = 10066; + }; + 6B555F7C100B54CE00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 275"; + rLen = 0; + rLoc = 11211; + rType = 0; + vrLen = 1011; + vrLoc = 10070; + }; + 6B555F82100B557700247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 87"; + rLen = 0; + rLoc = 2997; + rType = 0; + vrLen = 680; + vrLoc = 2751; + }; + 6B555F83100B557700247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + comments = "error: 'encodeId' was not declared in this scope"; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + rLen = 0; + rLoc = 490; + rType = 1; + }; + 6B555F84100B557700247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 87"; + rLen = 0; + rLoc = 2997; + rType = 0; + vrLen = 680; + vrLoc = 2751; + }; + 6B555F85100B557700247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 441"; + rLen = 0; + rLoc = 12049; + rType = 0; + vrLen = 650; + vrLoc = 11119; + }; + 6B555F88100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6BDD9E080F91113800904EEF /* DetourStatNavMesh.cpp */; + name = "DetourStatNavMesh.cpp: 46"; + rLen = 8; + rLoc = 1455; + rType = 0; + vrLen = 650; + vrLoc = 1708; + }; + 6B555F89100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6BDD9E050F91112200904EEF /* DetourStatNavMesh.h */; + name = "DetourStatNavMesh.h: 71"; + rLen = 0; + rLoc = 2105; + rType = 0; + vrLen = 1005; + vrLoc = 1851; + }; + 6B555F8A100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 631"; + rLen = 0; + rLoc = 13994; + rType = 0; + vrLen = 591; + vrLoc = 16086; + }; + 6B555F8B100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 124"; + rLen = 0; + rLoc = 4189; + rType = 0; + vrLen = 1240; + vrLoc = 3741; + }; + 6B555F8C100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 83"; + rLen = 0; + rLoc = 2739; + rType = 0; + vrLen = 551; + vrLoc = 2447; + }; + 6B555F8D100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 441"; + rLen = 0; + rLoc = 12049; + rType = 0; + vrLen = 650; + vrLoc = 11119; + }; + 6B555F8E100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6BDD9E050F91112200904EEF /* DetourStatNavMesh.h */; + name = "DetourStatNavMesh.h: 67"; + rLen = 0; + rLoc = 1901; + rType = 0; + vrLen = 1003; + vrLoc = 1851; + }; + 6B555F8F100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 441"; + rLen = 0; + rLoc = 12049; + rType = 0; + vrLen = 650; + vrLoc = 11119; + }; + 6B555F90100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 83"; + rLen = 0; + rLoc = 2892; + rType = 0; + vrLen = 418; + vrLoc = 2613; + }; + 6B555F91100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6BDD9E050F91112200904EEF /* DetourStatNavMesh.h */; + name = "DetourStatNavMesh.h: 71"; + rLen = 83; + rLoc = 2039; + rType = 0; + vrLen = 997; + vrLoc = 1851; + }; + 6B555F92100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6BDD9E080F91113800904EEF /* DetourStatNavMesh.cpp */; + name = "DetourStatNavMesh.cpp: 706"; + rLen = 0; + rLoc = 17464; + rType = 0; + vrLen = 1261; + vrLoc = 17259; + }; + 6B555F93100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6BDD9E050F91112200904EEF /* DetourStatNavMesh.h */; + name = "DetourStatNavMesh.h: 73"; + rLen = 0; + rLoc = 2184; + rType = 0; + vrLen = 997; + vrLoc = 1851; + }; + 6B555F94100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6BDD9E080F91113800904EEF /* DetourStatNavMesh.cpp */; + name = "DetourStatNavMesh.cpp: 46"; + rLen = 8; + rLoc = 1455; + rType = 0; + vrLen = 650; + vrLoc = 1708; + }; + 6B555F95100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 126"; + rLen = 8; + rLoc = 4301; + rType = 0; + vrLen = 1276; + vrLoc = 3705; + }; + 6B555F96100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6BDD9E050F91112200904EEF /* DetourStatNavMesh.h */; + name = "DetourStatNavMesh.h: 71"; + rLen = 0; + rLoc = 2105; + rType = 0; + vrLen = 1005; + vrLoc = 1851; + }; + 6B555F97100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 124"; + rLen = 0; + rLoc = 4189; + rType = 0; + vrLen = 1240; + vrLoc = 3741; + }; + 6B555F98100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 83"; + rLen = 0; + rLoc = 2739; + rType = 0; + vrLen = 622; + vrLoc = 2376; + }; + 6B555F99100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 631"; + rLen = 0; + rLoc = 13994; + rType = 0; + vrLen = 591; + vrLoc = 16086; + }; + 6B555F9A100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC580FFB8A68005BE9CC /* DetourTileNavMesh.h */; + name = "DetourTileNavMesh.h: 124"; + rLen = 0; + rLoc = 4189; + rType = 0; + vrLen = 1240; + vrLoc = 3741; + }; + 6B555F9B100B577A00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 446"; + rLen = 0; + rLoc = 11713; + rType = 0; + vrLen = 483; + vrLoc = 11267; + }; + 6B555F9E100B57B500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 446"; + rLen = 0; + rLoc = 11713; + rType = 0; + vrLen = 483; + vrLoc = 11267; + }; + 6B555F9F100B57B500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + comments = "error: no matching function for call to 'dtTiledNavMesh::addTileAt(const int&, const int&, unsigned char*&, int&)'"; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + rLen = 1; + rLoc = 549; + rType = 1; + }; + 6B555FA0100B57B500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 446"; + rLen = 0; + rLoc = 11713; + rType = 0; + vrLen = 483; + vrLoc = 11267; + }; + 6B555FA1100B57B500247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 606"; + rLen = 0; + rLoc = 14034; + rType = 0; + vrLen = 627; + vrLoc = 15489; + }; + 6B555FA2100B57CA00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 608"; + rLen = 0; + rLoc = 14069; + rType = 0; + vrLen = 681; + vrLoc = 15489; + }; + 6B555FA3100B57CC00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 380"; + rLen = 0; + rLoc = 10291; + rType = 0; + vrLen = 534; + vrLoc = 9692; + }; + 6B555FA4100B57CC00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 608"; + rLen = 0; + rLoc = 14069; + rType = 0; + vrLen = 431; + vrLoc = 15559; + }; + 6B555FA8100B589200247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 469"; + rLen = 0; + rLoc = 11834; + rType = 0; + vrLen = 460; + vrLoc = 11590; + }; + 6B555FA9100B589200247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 608"; + rLen = 0; + rLoc = 14069; + rType = 0; + vrLen = 681; + vrLoc = 15489; + }; + 6B555FAA100B589200247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 608"; + rLen = 0; + rLoc = 14069; + rType = 0; + vrLen = 681; + vrLoc = 15489; + }; + 6B555FAB100B589200247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC590FFB8A7A005BE9CC /* DetourTileNavMesh.cpp */; + name = "DetourTileNavMesh.cpp: 469"; + rLen = 0; + rLoc = 11834; + rType = 0; + vrLen = 460; + vrLoc = 11590; + }; + 6B555FAC100B589200247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 605"; + rLen = 0; + rLoc = 13992; + rType = 0; + vrLen = 655; + vrLoc = 15489; + }; + 6B555FB0100B595C00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC550FFB89E7005BE9CC /* Sample_StatMeshTiled.cpp */; + name = "Sample_StatMeshTiled.cpp: 175"; + rLen = 89; + rLoc = 5369; + rType = 0; + vrLen = 630; + vrLoc = 4879; + }; + 6B555FB1100B595C00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B25B6150FFA62BE004F1BC4 /* Sample_StatMesh.cpp */; + name = "Sample_StatMesh.cpp: 303"; + rLen = 0; + rLoc = 7561; + rType = 0; + vrLen = 728; + vrLoc = 7958; + }; + 6B555FB2100B595C00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B25B6160FFA62BE004F1BC4 /* Sample_StatMeshSimple.cpp */; + name = "Sample_StatMeshSimple.cpp: 130"; + rLen = 49; + rLoc = 4247; + rType = 0; + vrLen = 719; + vrLoc = 3933; + }; + 6B555FB3100B595C00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 207"; + rLen = 0; + rLoc = 5427; + rType = 0; + vrLen = 600; + vrLoc = 4992; + }; + 6B555FB4100B595C00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 207"; + rLen = 0; + rLoc = 5427; + rType = 0; + vrLen = 621; + vrLoc = 4992; + }; + 6B555FB5100B595C00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B25B6150FFA62BE004F1BC4 /* Sample_StatMesh.cpp */; + name = "Sample_StatMesh.cpp: 303"; + rLen = 0; + rLoc = 7561; + rType = 0; + vrLen = 728; + vrLoc = 7958; + }; + 6B555FB6100B595C00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B25B6160FFA62BE004F1BC4 /* Sample_StatMeshSimple.cpp */; + name = "Sample_StatMeshSimple.cpp: 130"; + rLen = 49; + rLoc = 4247; + rType = 0; + vrLen = 719; + vrLoc = 3933; + }; + 6B555FB7100B595C00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 210"; + rLen = 0; + rLoc = 5423; + rType = 0; + vrLen = 582; + vrLoc = 4992; + }; + 6B555FBA100B598E00247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 210"; + rLen = 0; + rLoc = 5364; + rType = 0; + vrLen = 601; + vrLoc = 4992; + }; + 6B555FBD100B59B600247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 209"; + rLen = 0; + rLoc = 5285; + rType = 0; + vrLen = 594; + vrLoc = 4992; + }; + 6B555FBF100B5A0000247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 572"; + rLen = 0; + rLoc = 14636; + rType = 0; + vrLen = 719; + vrLoc = 14230; + }; + 6B555FC0100B5A3300247EA3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 6B2AEC520FFB8958005BE9CC /* Sample_TileMesh.cpp */; + name = "Sample_TileMesh.cpp: 575"; + rLen = 0; + rLoc = 14722; + rType = 0; + vrLen = 802; + vrLoc = 14230; + }; 6B7707B90FBD66CF00D21BAE /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 6B137C6D0F7FCBBB00459200 /* MeshLoaderObj.cpp */; @@ -6479,9 +7364,9 @@ }; 6BDD9E050F91112200904EEF /* DetourStatNavMesh.h */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {915, 3424}}"; - sepNavSelRange = "{7147, 95}"; - sepNavVisRange = "{6323, 1013}"; + sepNavIntBoundsRect = "{{0, 0}, {915, 3488}}"; + sepNavSelRange = "{2105, 0}"; + sepNavVisRange = "{1851, 1005}"; }; }; 6BDD9E060F91112200904EEF /* DetourStatNavMeshBuilder.h */ = { @@ -6493,16 +7378,16 @@ }; 6BDD9E070F91113800904EEF /* DetourDebugDraw.cpp */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {915, 6752}}"; - sepNavSelRange = "{4897, 0}"; - sepNavVisRange = "{4634, 519}"; + sepNavIntBoundsRect = "{{0, 0}, {915, 6568}}"; + sepNavSelRange = "{10003, 0}"; + sepNavVisRange = "{9621, 835}"; }; }; 6BDD9E080F91113800904EEF /* DetourStatNavMesh.cpp */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {915, 12688}}"; - sepNavSelRange = "{17533, 0}"; - sepNavVisRange = "{17287, 1201}"; + sepNavIntBoundsRect = "{{0, 0}, {915, 12400}}"; + sepNavSelRange = "{1455, 8}"; + sepNavVisRange = "{1708, 650}"; }; }; 6BDD9E090F91113800904EEF /* DetourStatNavMeshBuilder.cpp */ = { diff --git a/RecastDemo/Build/Xcode/Recast.xcodeproj/memon.perspectivev3 b/RecastDemo/Build/Xcode/Recast.xcodeproj/memon.perspectivev3 index 910458e..9a1016b 100644 --- a/RecastDemo/Build/Xcode/Recast.xcodeproj/memon.perspectivev3 +++ b/RecastDemo/Build/Xcode/Recast.xcodeproj/memon.perspectivev3 @@ -270,6 +270,7 @@ 080E96DDFE201D6D7F000001 6BDD9E030F91110C00904EEF 6B137C7D0F7FCBE800459200 + 6B555DF5100B25FC00247EA3 29B97315FDCFA39411CA2CEA 29B97317FDCFA39411CA2CEA 1C37FBAC04509CD000000102 @@ -278,14 +279,14 @@ PBXSmartGroupTreeModuleOutlineStateSelectionKey - 11 - 3 + 36 + 32 1 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey - {{0, 0}, {282, 628}} + {{0, 104}, {282, 628}} PBXTopSmartGroupGIDs @@ -320,7 +321,7 @@ PBXProjectModuleGUID 6B8632A30F78115100E2684A PBXProjectModuleLabel - DetourTileNavMesh.cpp + Sample_TileMesh.cpp PBXSplitModuleInNavigatorKey Split0 @@ -328,11 +329,11 @@ PBXProjectModuleGUID 6B8632A40F78115100E2684A PBXProjectModuleLabel - DetourTileNavMesh.cpp + Sample_TileMesh.cpp _historyCapacity 0 bookmark - 6B555F52100B4CE300247EA3 + 6B555FC0100B5A3300247EA3 history 6BB87E0B0F9DE8A300E33F12 @@ -385,16 +386,16 @@ 6B555F11100B473F00247EA3 6B555F12100B473F00247EA3 6B555F13100B473F00247EA3 - 6B555F15100B473F00247EA3 - 6B555F2A100B499000247EA3 - 6B555F2B100B499000247EA3 - 6B555F2C100B499000247EA3 - 6B555F2D100B499000247EA3 - 6B555F40100B4C5800247EA3 - 6B555F41100B4C5800247EA3 6B555F42100B4C5800247EA3 - 6B555F43100B4C5800247EA3 - 6B555F44100B4C5800247EA3 + 6B555F5E100B53F500247EA3 + 6B555F88100B577A00247EA3 + 6B555F89100B577A00247EA3 + 6B555F8B100B577A00247EA3 + 6B555FA8100B589200247EA3 + 6B555FB0100B595C00247EA3 + 6B555FB1100B595C00247EA3 + 6B555FB2100B595C00247EA3 + 6B555FB3100B595C00247EA3 prevStack @@ -435,7 +436,6 @@ 6B0249051001EABD00CF7107 6B02498D1003751300CF7107 6B024A721004A2FE00CF7107 - 6B024BBB1005DF5700CF7107 6B024BCF1005DFAB00CF7107 6B024C041006098300CF7107 6B024C1310060C7600CF7107 @@ -445,7 +445,6 @@ 6B1186401006945C0018F96F 6B1186411006945C0018F96F 6B1186581006945C0018F96F - 6B1186591006945C0018F96F 6B118672100694C40018F96F 6B555D15100B125300247EA3 6B555D26100B136A00247EA3 @@ -465,7 +464,6 @@ 6B555D50100B175F00247EA3 6B555D53100B175F00247EA3 6B555D54100B175F00247EA3 - 6B555D55100B175F00247EA3 6B555D5D100B17DB00247EA3 6B555D5E100B17DB00247EA3 6B555D5F100B17DB00247EA3 @@ -482,7 +480,6 @@ 6B555D97100B1B6900247EA3 6B555D9E100B1C2400247EA3 6B555DA0100B1C2400247EA3 - 6B555DAB100B1E6500247EA3 6B555DC3100B236A00247EA3 6B555DC4100B236A00247EA3 6B555DC5100B236A00247EA3 @@ -519,7 +516,6 @@ 6B555E09100B285300247EA3 6B555E0A100B285300247EA3 6B555E0B100B285300247EA3 - 6B555E0C100B285300247EA3 6B555E0D100B285300247EA3 6B555E0E100B285300247EA3 6B555E0F100B285300247EA3 @@ -537,7 +533,6 @@ 6B555E47100B311B00247EA3 6B555E48100B311B00247EA3 6B555E49100B311B00247EA3 - 6B555E4A100B311B00247EA3 6B555E4B100B311B00247EA3 6B555E4C100B311B00247EA3 6B555E4D100B311B00247EA3 @@ -554,7 +549,6 @@ 6B555E67100B334900247EA3 6B555E68100B334900247EA3 6B555E69100B334900247EA3 - 6B555E6A100B334900247EA3 6B555E6B100B334900247EA3 6B555E6C100B334900247EA3 6B555E6D100B334900247EA3 @@ -581,7 +575,6 @@ 6B555EA9100B37AB00247EA3 6B555EAA100B37AB00247EA3 6B555EAB100B37AB00247EA3 - 6B555EAC100B37AB00247EA3 6B555EAF100B37AB00247EA3 6B555EB1100B37AB00247EA3 6B555EB2100B37AB00247EA3 @@ -600,29 +593,45 @@ 6B555F1D100B473F00247EA3 6B555F1E100B473F00247EA3 6B555F1F100B473F00247EA3 - 6B555F20100B473F00247EA3 6B555F21100B473F00247EA3 6B555F22100B473F00247EA3 6B555F23100B473F00247EA3 6B555F30100B499000247EA3 6B555F31100B499000247EA3 - 6B555F32100B499000247EA3 6B555F33100B499000247EA3 - 6B555F34100B499000247EA3 6B555F35100B499000247EA3 - 6B555F36100B499000247EA3 6B555F37100B499000247EA3 - 6B555F38100B499000247EA3 6B555F45100B4C5800247EA3 - 6B555F46100B4C5800247EA3 - 6B555F47100B4C5800247EA3 - 6B555F48100B4C5800247EA3 - 6B555F49100B4C5800247EA3 6B555F4A100B4C5800247EA3 - 6B555F4B100B4C5800247EA3 6B555F4C100B4C5800247EA3 - 6B555F4D100B4C5800247EA3 - 6B555F4E100B4C5800247EA3 + 6B555F63100B53F500247EA3 + 6B555F65100B53F500247EA3 + 6B555F67100B53F500247EA3 + 6B555F69100B53F500247EA3 + 6B555F6B100B53F500247EA3 + 6B555F6D100B53F500247EA3 + 6B555F6F100B53F500247EA3 + 6B555F71100B53F500247EA3 + 6B555F79100B54CE00247EA3 + 6B555F7B100B54CE00247EA3 + 6B555F8D100B577A00247EA3 + 6B555F8E100B577A00247EA3 + 6B555F8F100B577A00247EA3 + 6B555F90100B577A00247EA3 + 6B555F91100B577A00247EA3 + 6B555F92100B577A00247EA3 + 6B555F93100B577A00247EA3 + 6B555F94100B577A00247EA3 + 6B555F95100B577A00247EA3 + 6B555F96100B577A00247EA3 + 6B555F97100B577A00247EA3 + 6B555F98100B577A00247EA3 + 6B555F9A100B577A00247EA3 + 6B555FA0100B57B500247EA3 + 6B555FAB100B589200247EA3 + 6B555FB4100B595C00247EA3 + 6B555FB5100B595C00247EA3 + 6B555FB6100B595C00247EA3 SplitCount @@ -636,18 +645,18 @@ GeometryConfiguration Frame - {{0, 0}, {976, 443}} + {{0, 0}, {976, 462}} RubberWindowFrame 0 91 1280 687 0 0 1280 778 Module PBXNavigatorGroup Proportion - 443pt + 462pt Proportion - 198pt + 179pt Tabs @@ -661,7 +670,7 @@ GeometryConfiguration Frame - {{10, 27}, {976, -27}} + {{10, 27}, {976, 85}} Module XCDetailModule @@ -677,7 +686,7 @@ GeometryConfiguration Frame - {{10, 27}, {976, 244}} + {{10, 27}, {976, 196}} Module PBXProjectFindModule @@ -715,7 +724,7 @@ GeometryConfiguration Frame - {{10, 27}, {976, 171}} + {{10, 27}, {976, 152}} RubberWindowFrame 0 91 1280 687 0 0 1280 778 diff --git a/RecastDemo/Include/Sample.h b/RecastDemo/Include/Sample.h new file mode 100644 index 0000000..7706f8a --- /dev/null +++ b/RecastDemo/Include/Sample.h @@ -0,0 +1,50 @@ +#ifndef RECASTSAMPLE_H +#define RECASTSAMPLE_H + + +class Sample +{ +protected: + const float* m_verts; + int m_nverts; + const int* m_tris; + const float* m_trinorms; + int m_ntris; + float m_bmin[3], m_bmax[3]; + + float m_cellSize; + float m_cellHeight; + float m_agentHeight; + float m_agentRadius; + float m_agentMaxClimb; + float m_agentMaxSlope; + float m_regionMinSize; + float m_regionMergeSize; + float m_edgeMaxLen; + float m_edgeMaxError; + float m_vertsPerPoly; + +public: + Sample(); + virtual ~Sample(); + + virtual void handleSettings(); + virtual void handleTools(); + virtual void handleDebugMode(); + + virtual void setToolStartPos(const float* p); + virtual void setToolEndPos(const float* p); + + virtual void handleRender(); + virtual void handleRenderOverlay(double* proj, double* model, int* view); + virtual void handleMeshChanged(const float* verts, int nverts, + const int* tris, const float* trinorms, int ntris, + const float* bmin, const float* bmax); + virtual bool handleBuild(); + + void resetCommonSettings(); + void handleCommonSettings(); +}; + + +#endif // RECASTSAMPLE_H diff --git a/RecastDemo/Include/Sample_StatMesh.h b/RecastDemo/Include/Sample_StatMesh.h new file mode 100644 index 0000000..59e0c70 --- /dev/null +++ b/RecastDemo/Include/Sample_StatMesh.h @@ -0,0 +1,70 @@ +#ifndef RECASTSAMPLESTATMESH_H +#define RECASTSAMPLESTATMESH_H + +#include "Sample.h" +#include "DetourStatNavMesh.h" +#include "Recast.h" +#include "RecastLog.h" + +class Sample_StatMesh : public Sample +{ +protected: + + dtStatNavMesh* m_navMesh; + + enum ToolMode + { + TOOLMODE_PATHFIND, + TOOLMODE_RAYCAST, + TOOLMODE_DISTANCE_TO_WALL, + TOOLMODE_FIND_POLYS_AROUND, + }; + + ToolMode m_toolMode; + + static const int MAX_POLYS = 256; + + dtStatPolyRef m_startRef; + dtStatPolyRef m_endRef; + dtStatPolyRef m_polys[MAX_POLYS]; + dtStatPolyRef m_parent[MAX_POLYS]; + int m_npolys; + float m_straightPath[MAX_POLYS*3]; + int m_nstraightPath; + float m_polyPickExt[3]; + + float m_spos[3]; + float m_epos[3]; + float m_hitPos[3]; + float m_hitNormal[3]; + float m_distanceToWall; + bool m_sposSet; + bool m_eposSet; + + enum ToolRenderFlags + { + NAVMESH_POLYS = 0x01, + NAVMESH_BVTREE = 0x02, + NAVMESH_TOOLS = 0x04, + }; + + void toolCleanup(); + void toolReset(); + void toolRecalc(); + void toolRender(int flags); + void toolRenderOverlay(double* proj, double* model, int* view); + + void drawAgent(const float* pos, float r, float h, float c, const float* col); + + +public: + Sample_StatMesh(); + virtual ~Sample_StatMesh(); + + virtual void handleTools(); + virtual void setToolStartPos(const float* p); + virtual void setToolEndPos(const float* p); +}; + + +#endif // RECASTSAMPLESTATMESH_H diff --git a/RecastDemo/Include/Sample_StatMeshSimple.h b/RecastDemo/Include/Sample_StatMeshSimple.h new file mode 100644 index 0000000..c381df6 --- /dev/null +++ b/RecastDemo/Include/Sample_StatMeshSimple.h @@ -0,0 +1,63 @@ +#ifndef RECASTSAMPLESTATMESHSIMPLE_H +#define RECASTSAMPLESTATMESHSIMPLE_H + +#include "Sample_StatMesh.h" +#include "DetourStatNavMesh.h" +#include "Recast.h" +#include "RecastLog.h" + +class Sample_StatMeshSimple : public Sample_StatMesh +{ +protected: + + bool m_keepInterResults; + rcBuildTimes m_buildTimes; + + unsigned char* m_triflags; + rcHeightfield* m_solid; + rcCompactHeightfield* m_chf; + rcContourSet* m_cset; + rcPolyMesh* m_polyMesh; + rcConfig m_cfg; + + enum DrawMode + { + DRAWMODE_NAVMESH, + DRAWMODE_NAVMESH_TRANS, + DRAWMODE_NAVMESH_BVTREE, + DRAWMODE_NAVMESH_INVIS, + DRAWMODE_MESH, + DRAWMODE_VOXELS, + DRAWMODE_VOXELS_WALKABLE, + DRAWMODE_COMPACT, + DRAWMODE_COMPACT_DISTANCE, + DRAWMODE_COMPACT_REGIONS, + DRAWMODE_REGION_CONNECTIONS, + DRAWMODE_RAW_CONTOURS, + DRAWMODE_BOTH_CONTOURS, + DRAWMODE_CONTOURS, + DRAWMODE_POLYMESH, + MAX_DRAWMODE + }; + + DrawMode m_drawMode; + + void cleanup(); + +public: + Sample_StatMeshSimple(); + virtual ~Sample_StatMeshSimple(); + + virtual void handleSettings(); + virtual void handleDebugMode(); + + virtual void handleRender(); + virtual void handleRenderOverlay(double* proj, double* model, int* view); + virtual void handleMeshChanged(const float* verts, int nverts, + const int* tris, const float* trinorms, int ntris, + const float* bmin, const float* bmax); + virtual bool handleBuild(); +}; + + +#endif // RECASTSAMPLESTATMESHSIMPLE_H diff --git a/RecastDemo/Include/Sample_StatMeshTiled.h b/RecastDemo/Include/Sample_StatMeshTiled.h new file mode 100644 index 0000000..0db0bb0 --- /dev/null +++ b/RecastDemo/Include/Sample_StatMeshTiled.h @@ -0,0 +1,91 @@ +#ifndef RECASTSAMPLESTATMESHTILED_H +#define RECASTSAMPLESTATMESHTILED_H + +#include "Sample_StatMesh.h" +#include "DetourStatNavMesh.h" +#include "Recast.h" +#include "RecastLog.h" +#include "ChunkyTriMesh.h" + +class Sample_StatMeshTiled : public Sample_StatMesh +{ +protected: + + struct Tile + { + inline Tile() : chf(0), cset(0), solid(0), buildTime(0) {} + inline ~Tile() { delete chf; delete cset; delete solid; } + rcCompactHeightfield* chf; + rcHeightfield* solid; + rcContourSet* cset; + int buildTime; + }; + + struct TileSet + { + inline TileSet() : width(0), height(0), tiles(0) {} + inline ~TileSet() { delete [] tiles; } + int width, height; + float bmin[3], bmax[3]; + float cs, ch; + Tile* tiles; + }; + + bool m_measurePerTileTimings; + bool m_keepInterResults; + float m_tileSize; + rcBuildTimes m_buildTimes; + + rcChunkyTriMesh* m_chunkyMesh; + rcPolyMesh* m_polyMesh; + rcConfig m_cfg; + TileSet* m_tileSet; + + static const int MAX_STAT_BUCKETS = 1000; + int m_statPolysPerTile[MAX_STAT_BUCKETS]; + int m_statPolysPerTileSamples; + int m_statTimePerTile[MAX_STAT_BUCKETS]; + int m_statTimePerTileSamples; + + + enum DrawMode + { + DRAWMODE_NAVMESH, + DRAWMODE_NAVMESH_TRANS, + DRAWMODE_NAVMESH_BVTREE, + DRAWMODE_NAVMESH_INVIS, + DRAWMODE_MESH, + DRAWMODE_VOXELS, + DRAWMODE_VOXELS_WALKABLE, + DRAWMODE_COMPACT, + DRAWMODE_COMPACT_DISTANCE, + DRAWMODE_COMPACT_REGIONS, + DRAWMODE_REGION_CONNECTIONS, + DRAWMODE_RAW_CONTOURS, + DRAWMODE_BOTH_CONTOURS, + DRAWMODE_CONTOURS, + DRAWMODE_POLYMESH, + MAX_DRAWMODE + }; + + DrawMode m_drawMode; + + void cleanup(); + +public: + Sample_StatMeshTiled(); + virtual ~Sample_StatMeshTiled(); + + virtual void handleSettings(); + virtual void handleDebugMode(); + + virtual void handleRender(); + virtual void handleRenderOverlay(double* proj, double* model, int* view); + virtual void handleMeshChanged(const float* verts, int nverts, + const int* tris, const float* trinorms, int ntris, + const float* bmin, const float* bmax); + virtual bool handleBuild(); +}; + + +#endif // RECASTSAMPLESTATMESHTILED_H diff --git a/RecastDemo/Include/Sample_TileMesh.h b/RecastDemo/Include/Sample_TileMesh.h new file mode 100644 index 0000000..b957312 --- /dev/null +++ b/RecastDemo/Include/Sample_TileMesh.h @@ -0,0 +1,113 @@ +// +// Copyright (c) 2009 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#ifndef RECASTSAMPLETILEDMESH_H +#define RECASTSAMPLETILEDMESH_H + +#include "Sample.h" +#include "DetourTileNavMesh.h" +#include "Recast.h" +#include "RecastLog.h" +#include "ChunkyTriMesh.h" + +class Sample_TileMesh : public Sample +{ +protected: + + bool m_keepInterResults; + rcBuildTimes m_buildTimes; + + dtTiledNavMesh* m_navMesh; + rcChunkyTriMesh* m_chunkyMesh; + unsigned char* m_triflags; + rcHeightfield* m_solid; + rcCompactHeightfield* m_chf; + rcContourSet* m_cset; + rcPolyMesh* m_polyMesh; + rcConfig m_cfg; + + float m_tileSize; + + float m_spos[3]; + float m_epos[3]; + bool m_sposSet; + bool m_eposSet; + + float m_tileCol[4]; + float m_tileBmin[3]; + float m_tileBmax[3]; + float m_tileBuildTime; + float m_tileMemUsage; + int m_tileTriCount; + + enum ToolMode + { + TOOLMODE_CREATE_TILES, + TOOLMODE_PATHFIND, + TOOLMODE_RAYCAST, + TOOLMODE_DISTANCE_TO_WALL, + TOOLMODE_FIND_POLYS_AROUND, + }; + + dtTilePolyRef m_startRef; + dtTilePolyRef m_endRef; + float m_polyPickExt[3]; + + static const int MAX_POLYS = 256; + + dtTilePolyRef m_polys[MAX_POLYS]; + dtTilePolyRef m_parent[MAX_POLYS]; + int m_npolys; + float m_straightPath[MAX_POLYS*3]; + int m_nstraightPath; + float m_hitPos[3]; + float m_hitNormal[3]; + float m_distanceToWall; + + ToolMode m_toolMode; + + void toolRecalc(); + + void buildTile(const float* pos); + void removeTile(const float* pos); + + unsigned char* buildTileMesh(const float* bmin, const float* bmax, int& dataSize); + + void cleanup(); + +public: + Sample_TileMesh(); + virtual ~Sample_TileMesh(); + + virtual void handleSettings(); + virtual void handleTools(); + virtual void handleDebugMode(); + + virtual void setToolStartPos(const float* p); + virtual void setToolEndPos(const float* p); + + virtual void handleRender(); + virtual void handleRenderOverlay(double* proj, double* model, int* view); + virtual void handleMeshChanged(const float* verts, int nverts, + const int* tris, const float* trinorms, int ntris, + const float* bmin, const float* bmax); + virtual bool handleBuild(); +}; + + +#endif // RECASTBUILDERTILEDMESH_H diff --git a/RecastDemo/Source/Sample.cpp b/RecastDemo/Source/Sample.cpp new file mode 100644 index 0000000..1219547 --- /dev/null +++ b/RecastDemo/Source/Sample.cpp @@ -0,0 +1,123 @@ +#define _USE_MATH_DEFINES +#include +#include +#include "Sample.h" +#include "Recast.h" +#include "RecastDebugDraw.h" +#include "imgui.h" + +#ifdef WIN32 +# define snprintf _snprintf +#endif + + +Sample::Sample() : + m_verts(0), m_nverts(0), m_tris(0), m_trinorms(0), m_ntris(0) +{ + resetCommonSettings(); +} + +Sample::~Sample() +{ +} + +void Sample::handleSettings() +{ +} + +void Sample::handleTools() +{ +} + +void Sample::handleDebugMode() +{ +} + +void Sample::handleRender() +{ + if (!m_verts || !m_tris || !m_trinorms) + return; + // Draw mesh + rcDebugDrawMesh(m_verts, m_nverts, m_tris, m_trinorms, m_ntris, 0); + // Draw bounds + float col[4] = {1,1,1,0.5f}; + rcDebugDrawBoxWire(m_bmin[0],m_bmin[1],m_bmin[2], m_bmax[0],m_bmax[1],m_bmax[2], col); +} + +void Sample::handleRenderOverlay(double* proj, double* model, int* view) +{ +} + +void Sample::handleMeshChanged(const float* verts, int nverts, + const int* tris, const float* trinorms, int ntris, + const float* bmin, const float* bmax) +{ + m_verts = verts; + m_nverts = nverts; + m_tris = tris; + m_trinorms = trinorms; + m_ntris = ntris; + vcopy(m_bmin, bmin); + vcopy(m_bmax, bmax); +} + +void Sample::resetCommonSettings() +{ + m_cellSize = 0.3f; + m_cellHeight = 0.2f; + m_agentHeight = 2.0f; + m_agentRadius = 0.6f; + m_agentMaxClimb = 0.9f; + m_agentMaxSlope = 45.0f; + m_regionMinSize = 50; + m_regionMergeSize = 20; + m_edgeMaxLen = 12.0f; + m_edgeMaxError = 1.3f; + m_vertsPerPoly = 6.0f; +} + +void Sample::handleCommonSettings() +{ + imguiLabel("Rasterization"); + imguiSlider("Cell Size", &m_cellSize, 0.1f, 1.0f, 0.01f); + imguiSlider("Cell Height", &m_cellHeight, 0.1f, 1.0f, 0.01f); + + int gw = 0, gh = 0; + rcCalcGridSize(m_bmin, m_bmax, m_cellSize, &gw, &gh); + char text[64]; + snprintf(text, 64, "Voxels %d x %d", gw, gh); + imguiValue(text); + + imguiSeparator(); + imguiLabel("Agent"); + imguiSlider("Height", &m_agentHeight, 0.1f, 5.0f, 0.1f); + imguiSlider("Radius", &m_agentRadius, 0.0f, 5.0f, 0.1f); + imguiSlider("Max Climb", &m_agentMaxClimb, 0.1f, 5.0f, 0.1f); + imguiSlider("Max Slope", &m_agentMaxSlope, 0.0f, 90.0f, 1.0f); + + imguiSeparator(); + imguiLabel("Region"); + imguiSlider("Min Region Size", &m_regionMinSize, 0.0f, 150.0f, 1.0f); + imguiSlider("Merged Region Size", &m_regionMergeSize, 0.0f, 150.0f, 1.0f); + + imguiSeparator(); + imguiLabel("Polygonization"); + imguiSlider("Max Edge Length", &m_edgeMaxLen, 0.0f, 50.0f, 1.0f); + imguiSlider("Max Edge Error", &m_edgeMaxError, 0.1f, 3.0f, 0.1f); + imguiSlider("Verts Per Poly", &m_vertsPerPoly, 3.0f, 12.0f, 1.0f); + + imguiSeparator(); +} + +void Sample::setToolStartPos(const float* p) +{ +} + +void Sample::setToolEndPos(const float* p) +{ +} + +bool Sample::handleBuild() +{ + return true; +} diff --git a/RecastDemo/Source/Sample_StatMesh.cpp b/RecastDemo/Source/Sample_StatMesh.cpp new file mode 100644 index 0000000..4063389 --- /dev/null +++ b/RecastDemo/Source/Sample_StatMesh.cpp @@ -0,0 +1,336 @@ +#define _USE_MATH_DEFINES +#include +#include +#include +#include "SDL.h" +#include "SDL_Opengl.h" +#include "imgui.h" +#include "Sample.h" +#include "Sample_StatMesh.h" +#include "Recast.h" +#include "RecastTimer.h" +#include "RecastDebugDraw.h" +#include "DetourStatNavMesh.h" +#include "DetourStatNavMeshBuilder.h" +#include "DetourDebugDraw.h" + +#ifdef WIN32 +# define snprintf _snprintf +#endif + +Sample_StatMesh::Sample_StatMesh() : + m_navMesh(0), + m_toolMode(TOOLMODE_PATHFIND), + m_sposSet(false), + m_eposSet(false) +{ + toolReset(); + m_polyPickExt[0] = 2; + m_polyPickExt[1] = 4; + m_polyPickExt[2] = 2; +} + +Sample_StatMesh::~Sample_StatMesh() +{ + toolCleanup(); +} + +void Sample_StatMesh::handleTools() +{ + if (imguiCheck("Pathfind", m_toolMode == TOOLMODE_PATHFIND)) + { + m_toolMode = TOOLMODE_PATHFIND; + toolRecalc(); + } + if (imguiCheck("Distance to Wall", m_toolMode == TOOLMODE_DISTANCE_TO_WALL)) + { + m_toolMode = TOOLMODE_DISTANCE_TO_WALL; + toolRecalc(); + } + if (imguiCheck("Raycast", m_toolMode == TOOLMODE_RAYCAST)) + { + m_toolMode = TOOLMODE_RAYCAST; + toolRecalc(); + } + if (imguiCheck("Find Polys Around", m_toolMode == TOOLMODE_FIND_POLYS_AROUND)) + { + m_toolMode = TOOLMODE_FIND_POLYS_AROUND; + toolRecalc(); + } +} + +void Sample_StatMesh::setToolStartPos(const float* p) +{ + m_sposSet = true; + vcopy(m_spos, p); + toolRecalc(); +} + +void Sample_StatMesh::setToolEndPos(const float* p) +{ + m_eposSet = true; + vcopy(m_epos, p); + toolRecalc(); +} + +void Sample_StatMesh::toolCleanup() +{ + delete m_navMesh; + m_navMesh = 0; +} + +void Sample_StatMesh::toolReset() +{ + m_startRef = 0; + m_endRef = 0; + m_npolys = 0; + m_nstraightPath = 0; + memset(m_hitPos, 0, sizeof(m_hitPos)); + memset(m_hitNormal, 0, sizeof(m_hitNormal)); + m_distanceToWall = 0; +} + +void Sample_StatMesh::toolRecalc() +{ + if (!m_navMesh) + return; + + if (m_sposSet) + m_startRef = m_navMesh->findNearestPoly(m_spos, m_polyPickExt); + else + m_startRef = 0; + + if (m_eposSet) + m_endRef = m_navMesh->findNearestPoly(m_epos, m_polyPickExt); + else + m_endRef = 0; + + if (m_toolMode == TOOLMODE_PATHFIND) + { + if (m_sposSet && m_eposSet && m_startRef && m_endRef) + { + m_npolys = m_navMesh->findPath(m_startRef, m_endRef, m_polys, MAX_POLYS); + if (m_npolys) + m_nstraightPath = m_navMesh->findStraightPath(m_spos, m_epos, m_polys, m_npolys, m_straightPath, MAX_POLYS); + } + else + { + m_npolys = 0; + m_nstraightPath = 0; + } + } + else if (m_toolMode == TOOLMODE_RAYCAST) + { + m_nstraightPath = 0; + if (m_sposSet && m_eposSet && m_startRef) + { + float t = 0; + m_npolys = 0; + m_nstraightPath = 2; + m_straightPath[0] = m_spos[0]; + m_straightPath[1] = m_spos[1]; + m_straightPath[2] = m_spos[2]; + m_npolys = m_navMesh->raycast(m_startRef, m_spos, m_epos, t, m_polys, MAX_POLYS); + if (t < 1) + { + m_straightPath[3] = m_spos[0] + (m_epos[0] - m_spos[0]) * t; + m_straightPath[4] = m_spos[1] + (m_epos[1] - m_spos[1]) * t; + m_straightPath[5] = m_spos[2] + (m_epos[2] - m_spos[2]) * t; + } + else + { + m_straightPath[3] = m_epos[0]; + m_straightPath[4] = m_epos[1]; + m_straightPath[5] = m_epos[2]; + } + } + } + else if (m_toolMode == TOOLMODE_DISTANCE_TO_WALL) + { + m_distanceToWall = 0; + if (m_sposSet && m_startRef) + m_distanceToWall = m_navMesh->findDistanceToWall(m_startRef, m_spos, 100.0f, m_hitPos, m_hitNormal); + } + else if (m_toolMode == TOOLMODE_FIND_POLYS_AROUND) + { + if (m_sposSet && m_startRef && m_eposSet) + { + const float dx = m_epos[0] - m_spos[0]; + const float dz = m_epos[2] - m_spos[2]; + float dist = sqrtf(dx*dx + dz*dz); + m_npolys = m_navMesh->findPolysAround(m_startRef, m_spos, dist, m_polys, m_parent, 0, MAX_POLYS); + } + } +} + +static void getPolyCenter(dtStatNavMesh* navMesh, dtStatPolyRef ref, float* center) +{ + const dtStatPoly* p = navMesh->getPolyByRef(ref); + if (!p) return; + center[0] = 0; + center[1] = 0; + center[2] = 0; + for (int i = 0; i < (int)p->nv; ++i) + { + const float* v = navMesh->getVertex(p->v[i]); + center[0] += v[0]; + center[1] += v[1]; + center[2] += v[2]; + } + const float s = 1.0f / p->nv; + center[0] *= s; + center[1] *= s; + center[2] *= s; +} + +void Sample_StatMesh::toolRender(int flags) +{ + if (!m_navMesh) + return; + + static const float startCol[4] = { 0.5f, 0.1f, 0.0f, 0.75f }; + static const float endCol[4] = { 0.2f, 0.4f, 0.0f, 0.75f }; + static const float pathCol[4] = {0,0,0,0.25f}; + + glDepthMask(GL_FALSE); + + if (flags & NAVMESH_POLYS) + dtDebugDrawStatNavMesh(m_navMesh); + + if (flags & NAVMESH_BVTREE) + dtDebugDrawStatNavMeshBVTree(m_navMesh); + + if (flags & NAVMESH_TOOLS) + { + if (m_toolMode == TOOLMODE_PATHFIND) + { + dtDebugDrawStatNavMeshPoly(m_navMesh, m_startRef, startCol); + dtDebugDrawStatNavMeshPoly(m_navMesh, m_endRef, endCol); + + if (m_npolys) + { + for (int i = 1; i < m_npolys-1; ++i) + dtDebugDrawStatNavMeshPoly(m_navMesh, m_polys[i], pathCol); + } + if (m_nstraightPath) + { + glColor4ub(128,16,0,220); + glLineWidth(3.0f); + glBegin(GL_LINE_STRIP); + for (int i = 0; i < m_nstraightPath; ++i) + glVertex3f(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2]); + glEnd(); + glLineWidth(1.0f); + glPointSize(4.0f); + glBegin(GL_POINTS); + for (int i = 0; i < m_nstraightPath; ++i) + glVertex3f(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2]); + glEnd(); + glPointSize(1.0f); + } + } + else if (m_toolMode == TOOLMODE_RAYCAST) + { + dtDebugDrawStatNavMeshPoly(m_navMesh, m_startRef, startCol); + + if (m_nstraightPath) + { + for (int i = 1; i < m_npolys; ++i) + dtDebugDrawStatNavMeshPoly(m_navMesh, m_polys[i], pathCol); + + glColor4ub(128,16,0,220); + glLineWidth(3.0f); + glBegin(GL_LINE_STRIP); + for (int i = 0; i < m_nstraightPath; ++i) + glVertex3f(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2]); + glEnd(); + glLineWidth(1.0f); + glPointSize(4.0f); + glBegin(GL_POINTS); + for (int i = 0; i < m_nstraightPath; ++i) + glVertex3f(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2]); + glEnd(); + glPointSize(1.0f); + } + } + else if (m_toolMode == TOOLMODE_DISTANCE_TO_WALL) + { + dtDebugDrawStatNavMeshPoly(m_navMesh, m_startRef, startCol); + const float col[4] = {1,1,1,0.5f}; + rcDebugDrawCylinderWire(m_spos[0]-m_distanceToWall, m_spos[1]+0.02f, m_spos[2]-m_distanceToWall, + m_spos[0]+m_distanceToWall, m_spos[1]+m_agentHeight, m_spos[2]+m_distanceToWall, col); + glLineWidth(3.0f); + glColor4fv(col); + glBegin(GL_LINES); + glVertex3f(m_hitPos[0], m_hitPos[1] + 0.02f, m_hitPos[2]); + glVertex3f(m_hitPos[0], m_hitPos[1] + m_agentHeight, m_hitPos[2]); + glEnd(); + glLineWidth(1.0f); + } + else if (m_toolMode == TOOLMODE_FIND_POLYS_AROUND) + { + glLineWidth(2.0f); + for (int i = 0; i < m_npolys; ++i) + { + dtDebugDrawStatNavMeshPoly(m_navMesh, m_polys[i], pathCol); + if (m_parent[i]) + { + float p0[3], p1[3]; + getPolyCenter(m_navMesh, m_polys[i], p0); + getPolyCenter(m_navMesh, m_parent[i], p1); + glColor4ub(0,0,0,128); + rcDrawArc(p0, p1); + } + } + glLineWidth(1.0f); + + const float dx = m_epos[0] - m_spos[0]; + const float dz = m_epos[2] - m_spos[2]; + float dist = sqrtf(dx*dx + dz*dz); + const float col[4] = {1,1,1,0.5f}; + rcDebugDrawCylinderWire(m_spos[0]-dist, m_spos[1]+0.02f, m_spos[2]-dist, + m_spos[0]+dist, m_spos[1]+m_agentHeight, m_spos[2]+dist, col); + } + } + + glDepthMask(GL_TRUE); +} + +void Sample_StatMesh::toolRenderOverlay(double* proj, double* model, int* view) +{ + GLdouble x, y, z; + + // Draw start and end point labels + if (m_sposSet && gluProject((GLdouble)m_spos[0], (GLdouble)m_spos[1], (GLdouble)m_spos[2], + model, proj, view, &x, &y, &z)) + { + imguiDrawText((int)x, (int)(y-25), IMGUI_ALIGN_CENTER, "Start", imguiRGBA(0,0,0,220)); + } + if (m_eposSet && gluProject((GLdouble)m_epos[0], (GLdouble)m_epos[1], (GLdouble)m_epos[2], + model, proj, view, &x, &y, &z)) + { + imguiDrawText((int)x, (float)(y-25), IMGUI_ALIGN_CENTER, "End", imguiRGBA(0,0,0,220)); + } +} + +void Sample_StatMesh::drawAgent(const float* pos, float r, float h, float c, const float* col) +{ + glDepthMask(GL_FALSE); + + // Agent dimensions. + glLineWidth(2.0f); + rcDebugDrawCylinderWire(pos[0]-r, pos[1]+0.02f, pos[2]-r, pos[0]+r, pos[1]+h, pos[2]+r, col); + glLineWidth(1.0f); + + glColor4ub(0,0,0,196); + glBegin(GL_LINES); + glVertex3f(pos[0], pos[1]-c, pos[2]); + glVertex3f(pos[0], pos[1]+c, pos[2]); + glVertex3f(pos[0]-r/2, pos[1]+0.02f, pos[2]); + glVertex3f(pos[0]+r/2, pos[1]+0.02f, pos[2]); + glVertex3f(pos[0], pos[1]+0.02f, pos[2]-r/2); + glVertex3f(pos[0], pos[1]+0.02f, pos[2]+r/2); + glEnd(); + + glDepthMask(GL_TRUE); +} diff --git a/RecastDemo/Source/Sample_StatMeshSimple.cpp b/RecastDemo/Source/Sample_StatMeshSimple.cpp new file mode 100644 index 0000000..9decb0a --- /dev/null +++ b/RecastDemo/Source/Sample_StatMeshSimple.cpp @@ -0,0 +1,499 @@ +#define _USE_MATH_DEFINES +#include +#include +#include +#include "SDL.h" +#include "SDL_Opengl.h" +#include "imgui.h" +#include "Sample.h" +#include "Sample_StatMeshSimple.h" +#include "Recast.h" +#include "RecastTimer.h" +#include "RecastDebugDraw.h" +#include "DetourStatNavMesh.h" +#include "DetourStatNavMeshBuilder.h" +#include "DetourDebugDraw.h" + +#ifdef WIN32 +# define snprintf _snprintf +#endif + +Sample_StatMeshSimple::Sample_StatMeshSimple() : + m_keepInterResults(false), + m_triflags(0), + m_solid(0), + m_chf(0), + m_cset(0), + m_polyMesh(0), + m_drawMode(DRAWMODE_NAVMESH) +{ +} + +Sample_StatMeshSimple::~Sample_StatMeshSimple() +{ + cleanup(); +} + +void Sample_StatMeshSimple::cleanup() +{ + delete [] m_triflags; + m_triflags = 0; + delete m_solid; + m_solid = 0; + delete m_chf; + m_chf = 0; + delete m_cset; + m_cset = 0; + delete m_polyMesh; + m_polyMesh = 0; + toolCleanup(); +} + +void Sample_StatMeshSimple::handleSettings() +{ + Sample::handleCommonSettings(); + + if (imguiCheck("Keep Itermediate Results", m_keepInterResults)) + m_keepInterResults = !m_keepInterResults; + + imguiSeparator(); +} + +void Sample_StatMeshSimple::handleDebugMode() +{ + // Check which modes are valid. + bool valid[MAX_DRAWMODE]; + for (int i = 0; i < MAX_DRAWMODE; ++i) + valid[i] = false; + + if (m_verts && m_tris) + { + valid[DRAWMODE_NAVMESH] = m_navMesh != 0; + valid[DRAWMODE_NAVMESH_TRANS] = m_navMesh != 0; + valid[DRAWMODE_NAVMESH_BVTREE] = m_navMesh != 0; + valid[DRAWMODE_NAVMESH_INVIS] = m_navMesh != 0; + valid[DRAWMODE_MESH] = true; + valid[DRAWMODE_VOXELS] = m_solid != 0; + valid[DRAWMODE_VOXELS_WALKABLE] = m_solid != 0; + valid[DRAWMODE_COMPACT] = m_chf != 0; + valid[DRAWMODE_COMPACT_DISTANCE] = m_chf != 0; + valid[DRAWMODE_COMPACT_REGIONS] = m_chf != 0; + valid[DRAWMODE_REGION_CONNECTIONS] = m_cset != 0; + valid[DRAWMODE_RAW_CONTOURS] = m_cset != 0; + valid[DRAWMODE_BOTH_CONTOURS] = m_cset != 0; + valid[DRAWMODE_CONTOURS] = m_cset != 0; + valid[DRAWMODE_POLYMESH] = m_polyMesh != 0; + } + + int unavail = 0; + for (int i = 0; i < MAX_DRAWMODE; ++i) + if (!valid[i]) unavail++; + + if (unavail == MAX_DRAWMODE) + return; + + imguiLabel("Draw"); + if (imguiCheck("Input Mesh", m_drawMode == DRAWMODE_MESH, valid[DRAWMODE_MESH])) + m_drawMode = DRAWMODE_MESH; + if (imguiCheck("Navmesh", m_drawMode == DRAWMODE_NAVMESH, valid[DRAWMODE_NAVMESH])) + m_drawMode = DRAWMODE_NAVMESH; + if (imguiCheck("Navmesh Invis", m_drawMode == DRAWMODE_NAVMESH_INVIS, valid[DRAWMODE_NAVMESH_INVIS])) + m_drawMode = DRAWMODE_NAVMESH_INVIS; + if (imguiCheck("Navmesh Trans", m_drawMode == DRAWMODE_NAVMESH_TRANS, valid[DRAWMODE_NAVMESH_TRANS])) + m_drawMode = DRAWMODE_NAVMESH_TRANS; + if (imguiCheck("Navmesh BVTree", m_drawMode == DRAWMODE_NAVMESH_BVTREE, valid[DRAWMODE_NAVMESH_BVTREE])) + m_drawMode = DRAWMODE_NAVMESH_BVTREE; + if (imguiCheck("Voxels", m_drawMode == DRAWMODE_VOXELS, valid[DRAWMODE_VOXELS])) + m_drawMode = DRAWMODE_VOXELS; + if (imguiCheck("Walkable Voxels", m_drawMode == DRAWMODE_VOXELS_WALKABLE, valid[DRAWMODE_VOXELS_WALKABLE])) + m_drawMode = DRAWMODE_VOXELS_WALKABLE; + if (imguiCheck("Compact", m_drawMode == DRAWMODE_COMPACT, valid[DRAWMODE_COMPACT])) + m_drawMode = DRAWMODE_COMPACT; + if (imguiCheck("Compact Distance", m_drawMode == DRAWMODE_COMPACT_DISTANCE, valid[DRAWMODE_COMPACT_DISTANCE])) + m_drawMode = DRAWMODE_COMPACT_DISTANCE; + if (imguiCheck("Compact Regions", m_drawMode == DRAWMODE_COMPACT_REGIONS, valid[DRAWMODE_COMPACT_REGIONS])) + m_drawMode = DRAWMODE_COMPACT_REGIONS; + if (imguiCheck("Region Connections", m_drawMode == DRAWMODE_REGION_CONNECTIONS, valid[DRAWMODE_REGION_CONNECTIONS])) + m_drawMode = DRAWMODE_REGION_CONNECTIONS; + if (imguiCheck("Raw Contours", m_drawMode == DRAWMODE_RAW_CONTOURS, valid[DRAWMODE_RAW_CONTOURS])) + m_drawMode = DRAWMODE_RAW_CONTOURS; + if (imguiCheck("Both Contours", m_drawMode == DRAWMODE_BOTH_CONTOURS, valid[DRAWMODE_BOTH_CONTOURS])) + m_drawMode = DRAWMODE_BOTH_CONTOURS; + if (imguiCheck("Contours", m_drawMode == DRAWMODE_CONTOURS, valid[DRAWMODE_CONTOURS])) + m_drawMode = DRAWMODE_CONTOURS; + if (imguiCheck("Poly Mesh", m_drawMode == DRAWMODE_POLYMESH, valid[DRAWMODE_POLYMESH])) + m_drawMode = DRAWMODE_POLYMESH; + + if (unavail) + { + imguiValue("Tick 'Keep Itermediate Results'"); + imguiValue("to see more debug mode options."); + } +} + +void Sample_StatMeshSimple::handleRender() +{ + if (!m_verts || !m_tris || !m_trinorms) + return; + + float col[4]; + + glEnable(GL_FOG); + glDepthMask(GL_TRUE); + + if (m_drawMode == DRAWMODE_MESH) + { + // Draw mesh + rcDebugDrawMeshSlope(m_verts, m_nverts, m_tris, m_trinorms, m_ntris, m_agentMaxSlope); + } + else if (m_drawMode != DRAWMODE_NAVMESH_TRANS) + { + // Draw mesh + rcDebugDrawMesh(m_verts, m_nverts, m_tris, m_trinorms, m_ntris, 0); + } + + glDisable(GL_FOG); + glDepthMask(GL_FALSE); + + // Draw bounds + col[0] = 1; col[1] = 1; col[2] = 1; col[3] = 0.5f; + rcDebugDrawBoxWire(m_bmin[0],m_bmin[1],m_bmin[2], m_bmax[0],m_bmax[1],m_bmax[2], col); + + if (m_navMesh && + (m_drawMode == DRAWMODE_NAVMESH || + m_drawMode == DRAWMODE_NAVMESH_TRANS || + m_drawMode == DRAWMODE_NAVMESH_BVTREE || + m_drawMode == DRAWMODE_NAVMESH_INVIS)) + { + int flags = NAVMESH_TOOLS; + if (m_drawMode != DRAWMODE_NAVMESH_INVIS) + flags |= NAVMESH_POLYS; + if (m_drawMode == DRAWMODE_NAVMESH_BVTREE) + flags |= NAVMESH_BVTREE; + toolRender(flags); + } + + glDepthMask(GL_TRUE); + + if (m_chf && m_drawMode == DRAWMODE_COMPACT) + rcDebugDrawCompactHeightfieldSolid(*m_chf); + + if (m_chf && m_drawMode == DRAWMODE_COMPACT_DISTANCE) + rcDebugDrawCompactHeightfieldDistance(*m_chf); + if (m_chf && m_drawMode == DRAWMODE_COMPACT_REGIONS) + rcDebugDrawCompactHeightfieldRegions(*m_chf); + if (m_solid && m_drawMode == DRAWMODE_VOXELS) + { + glEnable(GL_FOG); + rcDebugDrawHeightfieldSolid(*m_solid); + glDisable(GL_FOG); + } + if (m_solid && m_drawMode == DRAWMODE_VOXELS_WALKABLE) + { + glEnable(GL_FOG); + rcDebugDrawHeightfieldWalkable(*m_solid); + glDisable(GL_FOG); + } + if (m_cset && m_drawMode == DRAWMODE_RAW_CONTOURS) + { + glDepthMask(GL_FALSE); + rcDebugDrawRawContours(*m_cset, m_cfg.bmin, m_cfg.cs, m_cfg.ch); + glDepthMask(GL_TRUE); + } + if (m_cset && m_drawMode == DRAWMODE_BOTH_CONTOURS) + { + glDepthMask(GL_FALSE); + rcDebugDrawRawContours(*m_cset, m_cfg.bmin, m_cfg.cs, m_cfg.ch, 0.5f); + rcDebugDrawContours(*m_cset, m_cfg.bmin, m_cfg.cs, m_cfg.ch); + glDepthMask(GL_TRUE); + } + if (m_cset && m_drawMode == DRAWMODE_CONTOURS) + { + glDepthMask(GL_FALSE); + rcDebugDrawContours(*m_cset, m_cfg.bmin, m_cfg.cs, m_cfg.ch); + glDepthMask(GL_TRUE); + } + if (m_chf && m_cset && m_drawMode == DRAWMODE_REGION_CONNECTIONS) + { + rcDebugDrawCompactHeightfieldRegions(*m_chf); + + glDepthMask(GL_FALSE); + rcDebugDrawRegionConnections(*m_cset, m_cfg.bmin, m_cfg.cs, m_cfg.ch); + glDepthMask(GL_TRUE); + } + if (m_polyMesh && m_drawMode == DRAWMODE_POLYMESH) + { + glDepthMask(GL_FALSE); + rcDebugDrawPolyMesh(*m_polyMesh); + glDepthMask(GL_TRUE); + } + + static const float startCol[4] = { 0.5f, 0.1f, 0.0f, 0.75f }; + static const float endCol[4] = { 0.2f, 0.4f, 0.0f, 0.75f }; + if (m_sposSet) + drawAgent(m_spos, m_agentRadius, m_agentHeight, m_agentMaxClimb, startCol); + if (m_eposSet) + drawAgent(m_epos, m_agentRadius, m_agentHeight, m_agentMaxClimb, endCol); + +} + +void Sample_StatMeshSimple::handleRenderOverlay(double* proj, double* model, int* view) +{ + toolRenderOverlay(proj, model, view); +} + +void Sample_StatMeshSimple::handleMeshChanged(const float* verts, int nverts, + const int* tris, const float* trinorms, int ntris, + const float* bmin, const float* bmax) +{ + Sample::handleMeshChanged(verts, nverts, tris, trinorms, ntris, bmin, bmax); + toolCleanup(); + toolReset(); +} + +bool Sample_StatMeshSimple::handleBuild() +{ + if (!m_verts || ! m_tris) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Input mesh is not specified."); + return false; + } + + cleanup(); + toolCleanup(); + + // Init build configuration from GUI + memset(&m_cfg, 0, sizeof(m_cfg)); + m_cfg.cs = m_cellSize; + m_cfg.ch = m_cellHeight; + m_cfg.walkableSlopeAngle = m_agentMaxSlope; + m_cfg.walkableHeight = (int)ceilf(m_agentHeight / m_cfg.ch); + m_cfg.walkableClimb = (int)ceilf(m_agentMaxClimb / m_cfg.ch); + m_cfg.walkableRadius = (int)ceilf(m_agentRadius / m_cfg.cs); + m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize); + m_cfg.maxSimplificationError = m_edgeMaxError; + m_cfg.minRegionSize = (int)rcSqr(m_regionMinSize); + m_cfg.mergeRegionSize = (int)rcSqr(m_regionMergeSize); + m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly; + + // Set the area where the navigation will be build. + // Here the bounds of the input mesh are used, but the + // area could be specified by an user defined box, etc. + vcopy(m_cfg.bmin, m_bmin); + vcopy(m_cfg.bmax, m_bmax); + rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height); + + // Reset build times gathering. + memset(&m_buildTimes, 0, sizeof(m_buildTimes)); + rcSetBuildTimes(&m_buildTimes); + + // Start the build process. + rcTimeVal totStartTime = rcGetPerformanceTimer(); + + if (rcGetLog()) + { + rcGetLog()->log(RC_LOG_PROGRESS, "Building navigation:"); + rcGetLog()->log(RC_LOG_PROGRESS, " - %d x %d cells", m_cfg.width, m_cfg.height); + rcGetLog()->log(RC_LOG_PROGRESS, " - %.1fK verts, %.1fK tris", m_nverts/1000.0f, m_ntris/1000.0f); + } + + // Allocate voxel heighfield where we rasterize our input data to. + m_solid = new rcHeightfield; + if (!m_solid) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'."); + return false; + } + if (!rcCreateHeightfield(*m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not create solid heightfield."); + return false; + } + + // Allocate array that can hold triangle flags. + // If you have multiple meshes you need to process, allocate + // and array which can hold the max number of triangles you need to process. + m_triflags = new unsigned char[m_ntris]; + if (!m_triflags) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'triangleFlags' (%d).", m_ntris); + return false; + } + + + // Find triangles which are walkable based on their slope and rasterize them. + // If your input data is multiple meshes, you can transform them here, calculate + // the flags for each of the meshes and rasterize them. + memset(m_triflags, 0, m_ntris*sizeof(unsigned char)); + rcMarkWalkableTriangles(m_cfg.walkableSlopeAngle, m_verts, m_nverts, m_tris, m_ntris, m_triflags); + rcRasterizeTriangles(m_verts, m_nverts, m_tris, m_triflags, m_ntris, *m_solid); + + if (!m_keepInterResults) + { + delete [] m_triflags; + m_triflags = 0; + } + + // Once all geoemtry is rasterized, we do initial pass of filtering to + // remove unwanted overhangs caused by the conservative rasterization + // as well as filter spans where the character cannot possibly stand. + rcFilterLedgeSpans(m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid); + rcFilterWalkableLowHeightSpans(m_cfg.walkableHeight, *m_solid); + + // Compact the heightfield so that it is faster to handle from now on. + // This will result more cache coherent data as well as the neighbours + // between walkable cells will be calculated. + m_chf = new rcCompactHeightfield; + if (!m_chf) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'."); + return false; + } + if (!rcBuildCompactHeightfield(m_cfg.walkableHeight, m_cfg.walkableClimb, RC_WALKABLE, *m_solid, *m_chf)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not build compact data."); + return false; + } + + if (!m_keepInterResults) + { + delete m_solid; + m_solid = 0; + } + + // Prepare for region partitioning, by calculating distance field along the walkable surface. + if (!rcBuildDistanceField(*m_chf)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not build distance field."); + return false; + } + + // Partition the walkable surface into simple regions without holes. + if (!rcBuildRegions(*m_chf, m_cfg.walkableRadius, m_cfg.borderSize, m_cfg.minRegionSize, m_cfg.mergeRegionSize)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not build regions."); + } + + // Create contours. + m_cset = new rcContourSet; + if (!m_cset) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'."); + return false; + } + if (!rcBuildContours(*m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not create contours."); + return false; + } + + if (!m_keepInterResults) + { + delete m_chf; + m_chf = 0; + } + + // Build polygon navmesh from the contours. + m_polyMesh = new rcPolyMesh; + if (!m_polyMesh) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'polyMesh'."); + return false; + } + if (!rcBuildPolyMesh(*m_cset, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch, m_cfg.maxVertsPerPoly, *m_polyMesh)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not triangulate contours."); + return false; + } + + if (!m_keepInterResults) + { + delete m_cset; + m_cset = 0; + } + + if (m_cfg.maxVertsPerPoly == DT_STAT_VERTS_PER_POLYGON) + { + unsigned char* navData = 0; + int navDataSize = 0; + if (!dtCreateNavMeshData(m_polyMesh->verts, m_polyMesh->nverts, + m_polyMesh->polys, m_polyMesh->npolys, m_polyMesh->nvp, + m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch, &navData, &navDataSize)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "Could not build Detour navmesh."); + return false; + } + + m_navMesh = new dtStatNavMesh; + if (!m_navMesh) + { + delete [] navData; + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "Could not create Detour navmesh"); + return false; + } + + if (!m_navMesh->init(navData, navDataSize, true)) + { + delete [] navData; + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "Could not init Detour navmesh"); + return false; + } + } + + rcTimeVal totEndTime = rcGetPerformanceTimer(); + + // Show performance stats. + if (rcGetLog()) + { + const float pc = 100.0f / rcGetDeltaTimeUsec(totStartTime, totEndTime); + + rcGetLog()->log(RC_LOG_PROGRESS, "Rasterize: %.1fms (%.1f%%)", m_buildTimes.rasterizeTriangles/1000.0f, m_buildTimes.rasterizeTriangles*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Compact: %.1fms (%.1f%%)", m_buildTimes.buildCompact/1000.0f, m_buildTimes.buildCompact*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Filter Border: %.1fms (%.1f%%)", m_buildTimes.filterBorder/1000.0f, m_buildTimes.filterBorder*pc); + rcGetLog()->log(RC_LOG_PROGRESS, "Filter Walkable: %.1fms (%.1f%%)", m_buildTimes.filterWalkable/1000.0f, m_buildTimes.filterWalkable*pc); + rcGetLog()->log(RC_LOG_PROGRESS, "Filter Reachable: %.1fms (%.1f%%)", m_buildTimes.filterMarkReachable/1000.0f, m_buildTimes.filterMarkReachable*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Distancefield: %.1fms (%.1f%%)", m_buildTimes.buildDistanceField/1000.0f, m_buildTimes.buildDistanceField*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - distance: %.1fms (%.1f%%)", m_buildTimes.buildDistanceFieldDist/1000.0f, m_buildTimes.buildDistanceFieldDist*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - blur: %.1fms (%.1f%%)", m_buildTimes.buildDistanceFieldBlur/1000.0f, m_buildTimes.buildDistanceFieldBlur*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Regions: %.1fms (%.1f%%)", m_buildTimes.buildRegions/1000.0f, m_buildTimes.buildRegions*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - watershed: %.1fms (%.1f%%)", m_buildTimes.buildRegionsReg/1000.0f, m_buildTimes.buildRegionsReg*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - expand: %.1fms (%.1f%%)", m_buildTimes.buildRegionsExp/1000.0f, m_buildTimes.buildRegionsExp*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - find catchment basins: %.1fms (%.1f%%)", m_buildTimes.buildRegionsFlood/1000.0f, m_buildTimes.buildRegionsFlood*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - filter: %.1fms (%.1f%%)", m_buildTimes.buildRegionsFilter/1000.0f, m_buildTimes.buildRegionsFilter*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Contours: %.1fms (%.1f%%)", m_buildTimes.buildContours/1000.0f, m_buildTimes.buildContours*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - trace: %.1fms (%.1f%%)", m_buildTimes.buildContoursTrace/1000.0f, m_buildTimes.buildContoursTrace*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - simplify: %.1fms (%.1f%%)", m_buildTimes.buildContoursSimplify/1000.0f, m_buildTimes.buildContoursSimplify*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Fixup contours: %.1fms (%.1f%%)", m_buildTimes.fixupContours/1000.0f, m_buildTimes.fixupContours*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Polymesh: %.1fms (%.1f%%)", m_buildTimes.buildPolymesh/1000.0f, m_buildTimes.buildPolymesh*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Polymesh: Verts:%d Polys:%d", m_polyMesh->nverts, m_polyMesh->npolys); + + rcGetLog()->log(RC_LOG_PROGRESS, "TOTAL: %.1fms", rcGetDeltaTimeUsec(totStartTime, totEndTime)/1000.0f); + } + + toolRecalc(); + + return true; +} diff --git a/RecastDemo/Source/Sample_StatMeshTiled.cpp b/RecastDemo/Source/Sample_StatMeshTiled.cpp new file mode 100644 index 0000000..c245a89 --- /dev/null +++ b/RecastDemo/Source/Sample_StatMeshTiled.cpp @@ -0,0 +1,973 @@ +#define _USE_MATH_DEFINES +#include +#include +#include +#include "SDL.h" +#include "SDL_Opengl.h" +#include "imgui.h" +#include "Sample.h" +#include "Sample_StatMeshTiled.h" +#include "Recast.h" +#include "RecastTimer.h" +#include "RecastDebugDraw.h" +#include "DetourStatNavMesh.h" +#include "DetourStatNavMeshBuilder.h" +#include "DetourDebugDraw.h" + +#ifdef WIN32 +# define snprintf _snprintf +#endif + +Sample_StatMeshTiled::Sample_StatMeshTiled() : + m_keepInterResults(false), + m_measurePerTileTimings(false), + m_tileSize(64), + m_chunkyMesh(0), + m_tileSet(0), + m_polyMesh(0), + m_drawMode(DRAWMODE_NAVMESH), + m_statTimePerTileSamples(0), + m_statPolysPerTileSamples(0) +{ +} + +Sample_StatMeshTiled::~Sample_StatMeshTiled() +{ + cleanup(); +} + +void Sample_StatMeshTiled::cleanup() +{ + delete m_chunkyMesh; + m_chunkyMesh = 0; + delete m_tileSet; + m_tileSet = 0; + delete m_polyMesh; + m_polyMesh = 0; + toolCleanup(); + m_statTimePerTileSamples = 0; + m_statPolysPerTileSamples = 0; +} + +void Sample_StatMeshTiled::handleSettings() +{ + Sample::handleCommonSettings(); + + imguiLabel("Tiling"); + imguiSlider("TileSize", &m_tileSize, 16.0f, 1024.0f, 16.0f); + + char text[64]; + int gw = 0, gh = 0; + rcCalcGridSize(m_bmin, m_bmax, m_cellSize, &gw, &gh); + const int ts = (int)m_tileSize; + const int tw = (gw + ts-1) / ts; + const int th = (gh + ts-1) / ts; + snprintf(text, 64, "Tiles %d x %d", tw, th); + imguiValue(text); + + imguiSeparator(); + if (imguiCheck("Keep Itermediate Results", m_keepInterResults)) + m_keepInterResults = !m_keepInterResults; + if (imguiCheck("Measure Per Tile Timings", m_measurePerTileTimings)) + m_measurePerTileTimings = !m_measurePerTileTimings; + + imguiSeparator(); +} + +void Sample_StatMeshTiled::handleDebugMode() +{ + // Check which modes are valid. + bool valid[MAX_DRAWMODE]; + for (int i = 0; i < MAX_DRAWMODE; ++i) + valid[i] = false; + + bool hasChf = false; + bool hasSolid = false; + bool hasCset = false; + if (m_tileSet) + { + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].solid) hasSolid = true; + if (m_tileSet->tiles[i].chf) hasChf = true; + if (m_tileSet->tiles[i].cset) hasCset = true; + } + } + + if (m_verts && m_tris) + { + valid[DRAWMODE_NAVMESH] = m_navMesh != 0; + valid[DRAWMODE_NAVMESH_TRANS] = m_navMesh != 0; + valid[DRAWMODE_NAVMESH_BVTREE] = m_navMesh != 0; + valid[DRAWMODE_NAVMESH_INVIS] = m_navMesh != 0; + valid[DRAWMODE_MESH] = true; + valid[DRAWMODE_VOXELS] = hasSolid; + valid[DRAWMODE_VOXELS_WALKABLE] = hasSolid; + valid[DRAWMODE_COMPACT] = hasChf; + valid[DRAWMODE_COMPACT_DISTANCE] = hasChf; + valid[DRAWMODE_COMPACT_REGIONS] = hasChf; + valid[DRAWMODE_REGION_CONNECTIONS] = hasCset; + valid[DRAWMODE_RAW_CONTOURS] = hasCset; + valid[DRAWMODE_BOTH_CONTOURS] = hasCset; + valid[DRAWMODE_CONTOURS] = hasCset; + valid[DRAWMODE_POLYMESH] = m_polyMesh != 0; + } + + int unavail = 0; + for (int i = 0; i < MAX_DRAWMODE; ++i) + if (!valid[i]) unavail++; + + if (unavail == MAX_DRAWMODE) + return; + + imguiLabel("Draw"); + if (imguiCheck("Input Mesh", m_drawMode == DRAWMODE_MESH, valid[DRAWMODE_MESH])) + m_drawMode = DRAWMODE_MESH; + if (imguiCheck("Navmesh", m_drawMode == DRAWMODE_NAVMESH, valid[DRAWMODE_NAVMESH])) + m_drawMode = DRAWMODE_NAVMESH; + if (imguiCheck("Navmesh Invis", m_drawMode == DRAWMODE_NAVMESH_INVIS, valid[DRAWMODE_NAVMESH_INVIS])) + m_drawMode = DRAWMODE_NAVMESH_INVIS; + if (imguiCheck("Navmesh Trans", m_drawMode == DRAWMODE_NAVMESH_TRANS, valid[DRAWMODE_NAVMESH_TRANS])) + m_drawMode = DRAWMODE_NAVMESH_TRANS; + if (imguiCheck("Navmesh BVTree", m_drawMode == DRAWMODE_NAVMESH_BVTREE, valid[DRAWMODE_NAVMESH_BVTREE])) + m_drawMode = DRAWMODE_NAVMESH_BVTREE; + if (imguiCheck("Voxels", m_drawMode == DRAWMODE_VOXELS, valid[DRAWMODE_VOXELS])) + m_drawMode = DRAWMODE_VOXELS; + if (imguiCheck("Walkable Voxels", m_drawMode == DRAWMODE_VOXELS_WALKABLE, valid[DRAWMODE_VOXELS_WALKABLE])) + m_drawMode = DRAWMODE_VOXELS_WALKABLE; + if (imguiCheck("Compact", m_drawMode == DRAWMODE_COMPACT, valid[DRAWMODE_COMPACT])) + m_drawMode = DRAWMODE_COMPACT; + if (imguiCheck("Compact Distance", m_drawMode == DRAWMODE_COMPACT_DISTANCE, valid[DRAWMODE_COMPACT_DISTANCE])) + m_drawMode = DRAWMODE_COMPACT_DISTANCE; + if (imguiCheck("Compact Regions", m_drawMode == DRAWMODE_COMPACT_REGIONS, valid[DRAWMODE_COMPACT_REGIONS])) + m_drawMode = DRAWMODE_COMPACT_REGIONS; + if (imguiCheck("Region Connections", m_drawMode == DRAWMODE_REGION_CONNECTIONS, valid[DRAWMODE_REGION_CONNECTIONS])) + m_drawMode = DRAWMODE_REGION_CONNECTIONS; + if (imguiCheck("Raw Contours", m_drawMode == DRAWMODE_RAW_CONTOURS, valid[DRAWMODE_RAW_CONTOURS])) + m_drawMode = DRAWMODE_RAW_CONTOURS; + if (imguiCheck("Both Contours", m_drawMode == DRAWMODE_BOTH_CONTOURS, valid[DRAWMODE_BOTH_CONTOURS])) + m_drawMode = DRAWMODE_BOTH_CONTOURS; + if (imguiCheck("Contours", m_drawMode == DRAWMODE_CONTOURS, valid[DRAWMODE_CONTOURS])) + m_drawMode = DRAWMODE_CONTOURS; + if (imguiCheck("Poly Mesh", m_drawMode == DRAWMODE_POLYMESH, valid[DRAWMODE_POLYMESH])) + m_drawMode = DRAWMODE_POLYMESH; + + if (unavail) + { + imguiValue("Tick 'Keep Itermediate Results'"); + imguiValue("to see more debug mode options."); + } +} + +void Sample_StatMeshTiled::handleRender() +{ + if (!m_verts || !m_tris || !m_trinorms) + return; + + float col[4]; + + glEnable(GL_FOG); + glDepthMask(GL_TRUE); + + if (m_drawMode == DRAWMODE_MESH) + { + // Draw mesh + rcDebugDrawMeshSlope(m_verts, m_nverts, m_tris, m_trinorms, m_ntris, m_agentMaxSlope); + } + else if (m_drawMode != DRAWMODE_NAVMESH_TRANS) + { + // Draw mesh + rcDebugDrawMesh(m_verts, m_nverts, m_tris, m_trinorms, m_ntris, 0); + } + + glDisable(GL_FOG); + glDepthMask(GL_FALSE); + + // Draw bounds + col[0] = 1; col[1] = 1; col[2] = 1; col[3] = 0.5f; + rcDebugDrawBoxWire(m_bmin[0],m_bmin[1],m_bmin[2], m_bmax[0],m_bmax[1],m_bmax[2], col); + + // Tiling grid. + const int ts = (int)m_tileSize; + int gw = 0, gh = 0; + rcCalcGridSize(m_bmin, m_bmax, m_cellSize, &gw, &gh); + int tw = (gw + ts-1) / ts; + int th = (gh + ts-1) / ts; + const float s = ts*m_cellSize; + glBegin(GL_LINES); + glColor4ub(0,0,0,64); + for (int y = 0; y < th; ++y) + { + for (int x = 0; x < tw; ++x) + { + float fx, fy, fz; + fx = m_bmin[0] + x*s; + fy = m_bmin[1]; + fz = m_bmin[2] + y*s; + + glVertex3f(fx,fy,fz); + glVertex3f(fx+s,fy,fz); + glVertex3f(fx,fy,fz); + glVertex3f(fx,fy,fz+s); + + if (x+1 >= tw) + { + glVertex3f(fx+s,fy,fz); + glVertex3f(fx+s,fy,fz+s); + } + if (y+1 >= th) + { + glVertex3f(fx,fy,fz+s); + glVertex3f(fx+s,fy,fz+s); + } + } + } + glEnd(); + + + if (m_navMesh && + (m_drawMode == DRAWMODE_NAVMESH || + m_drawMode == DRAWMODE_NAVMESH_TRANS || + m_drawMode == DRAWMODE_NAVMESH_BVTREE || + m_drawMode == DRAWMODE_NAVMESH_INVIS)) + { + int flags = NAVMESH_TOOLS; + if (m_drawMode != DRAWMODE_NAVMESH_INVIS) + flags |= NAVMESH_POLYS; + if (m_drawMode == DRAWMODE_NAVMESH_BVTREE) + flags |= NAVMESH_BVTREE; + toolRender(flags); + } + + glDepthMask(GL_TRUE); + + if (m_tileSet) + { + if (m_drawMode == DRAWMODE_COMPACT) + { + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].chf) + rcDebugDrawCompactHeightfieldSolid(*m_tileSet->tiles[i].chf); + } + } + + if (m_drawMode == DRAWMODE_COMPACT_DISTANCE) + { + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].chf) + rcDebugDrawCompactHeightfieldDistance(*m_tileSet->tiles[i].chf); + } + } + if (m_drawMode == DRAWMODE_COMPACT_REGIONS) + { + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].chf) + rcDebugDrawCompactHeightfieldRegions(*m_tileSet->tiles[i].chf); + } + } + + if (m_drawMode == DRAWMODE_VOXELS) + { + glEnable(GL_FOG); + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].solid) + rcDebugDrawHeightfieldSolid(*m_tileSet->tiles[i].solid); + } + glDisable(GL_FOG); + } + if (m_drawMode == DRAWMODE_VOXELS_WALKABLE) + { + glEnable(GL_FOG); + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].solid) + rcDebugDrawHeightfieldWalkable(*m_tileSet->tiles[i].solid); + } + glDisable(GL_FOG); + } + if (m_drawMode == DRAWMODE_RAW_CONTOURS) + { + glDepthMask(GL_FALSE); + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].cset) + rcDebugDrawRawContours(*m_tileSet->tiles[i].cset, m_cfg.bmin, m_cfg.cs, m_cfg.ch); + } + glDepthMask(GL_TRUE); + } + if (m_drawMode == DRAWMODE_BOTH_CONTOURS) + { + glDepthMask(GL_FALSE); + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].cset) + { + rcDebugDrawRawContours(*m_tileSet->tiles[i].cset, m_cfg.bmin, m_cfg.cs, m_cfg.ch, 0.5f); + rcDebugDrawContours(*m_tileSet->tiles[i].cset, m_cfg.bmin, m_cfg.cs, m_cfg.ch); + } + } + glDepthMask(GL_TRUE); + } + if (m_drawMode == DRAWMODE_CONTOURS) + { + glDepthMask(GL_FALSE); + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].cset) + rcDebugDrawContours(*m_tileSet->tiles[i].cset, m_cfg.bmin, m_cfg.cs, m_cfg.ch); + } + glDepthMask(GL_TRUE); + } + if (m_drawMode == DRAWMODE_REGION_CONNECTIONS) + { + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].chf) + rcDebugDrawCompactHeightfieldRegions(*m_tileSet->tiles[i].chf); + } + + glDepthMask(GL_FALSE); + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].cset) + rcDebugDrawRegionConnections(*m_tileSet->tiles[i].cset, m_cfg.bmin, m_cfg.cs, m_cfg.ch); + } + glDepthMask(GL_TRUE); + } + if (m_polyMesh && m_drawMode == DRAWMODE_POLYMESH) + { + glDepthMask(GL_FALSE); + rcDebugDrawPolyMesh(*m_polyMesh); + glDepthMask(GL_TRUE); + } + } + + static const float startCol[4] = { 0.5f, 0.1f, 0.0f, 0.75f }; + static const float endCol[4] = { 0.2f, 0.4f, 0.0f, 0.75f }; + if (m_sposSet) + drawAgent(m_spos, m_agentRadius, m_agentHeight, m_agentMaxClimb, startCol); + if (m_eposSet) + drawAgent(m_epos, m_agentRadius, m_agentHeight, m_agentMaxClimb, endCol); + +} + +static float nicenum(float x, int round) +{ + float expv = floorf(log10f(x)); + float f = x / powf(10.0f, expv); + float nf; + if (round) + { + if (f < 1.5f) nf = 1.0f; + else if (f < 3.0f) nf = 2.0f; + else if (f < 7.0f) nf = 5.0f; + else nf = 10.0f; + } + else + { + if (f <= 1.0f) nf = 1.0f; + else if (f <= 2.0f) nf = 2.0f; + else if (f <= 5.0f) nf = 5.0f; + else nf = 10.0f; + } + return nf*powf(10.0f, expv); +} + +static void drawLabels(int x, int y, int w, int h, + int nticks, float vmin, float vmax, const char* unit) +{ + char str[8], temp[32]; + + float range = nicenum(vmax-vmin, 0); + float d = nicenum(range/(float)(nticks-1), 1); + float graphmin = floorf(vmin/d)*d; + float graphmax = ceilf(vmax/d)*d; + int nfrac = (int)-floorf(log10f(d)); + if (nfrac < 0) nfrac = 0; + snprintf(str, 6, "%%.%df %%s", nfrac); + + for (float v = graphmin; v < graphmax+d/2; v += d) + { + float lx = x + (v-vmin)/(vmax-vmin)*w; + if (lx < 0 || lx > w) continue; + snprintf(temp, 20, str, v, unit); + imguiDrawText((int)lx+2, (int)y+2, IMGUI_ALIGN_LEFT, temp, imguiRGBA(255,255,255)); + glColor4ub(0,0,0,64); + glBegin(GL_LINES); + glVertex2f(lx,(float)y); + glVertex2f(lx,(float)(y+h)); + glEnd(); + } +} + +static void drawGraph(const char* name, int x, int y, int w, int h, float sd, + const int* samples, int n, int nsamples, const char* unit) +{ + char text[64]; + int first, last, maxval; + first = 0; + last = n-1; + while (first < n && samples[first] == 0) + first++; + while (last >= 0 && samples[last] == 0) + last--; + if (first == last) + return; + maxval = 1; + for (int i = first; i <= last; ++i) + { + if (samples[i] > maxval) + maxval = samples[i]; + } + const float sx = (float)w / (float)(last-first); + const float sy = (float)h / (float)maxval; + + glBegin(GL_QUADS); + glColor4ub(32,32,32,64); + glVertex2i(x,y); + glVertex2i(x+w,y); + glVertex2i(x+w,y+h); + glVertex2i(x,y+h); + glEnd(); + + glColor4ub(255,255,255,64); + glBegin(GL_LINES); + for (int i = 0; i <= 4; ++i) + { + int yy = y+i*h/4; + glVertex2i(x,yy); + glVertex2i(x+w,yy); + } + glEnd(); + + glColor4ub(0,196,255,255); + glBegin(GL_LINE_STRIP); + for (int i = first; i <= last; ++i) + { + float fx = x + (i-first)*sx; + float fy = y + samples[i]*sy; + glVertex2f(fx,fy); + } + glEnd(); + + snprintf(text,64,"%d", maxval); + imguiDrawText((int)x+w-2, (int)y+h-20, IMGUI_ALIGN_RIGHT, text, imguiRGBA(0,0,0)); + imguiDrawText((int)x+2, (int)y+h-20, IMGUI_ALIGN_LEFT, name, imguiRGBA(255,255,255)); + + drawLabels(x, y, w, h, 10, first*sd, last*sd, unit); +} + +void Sample_StatMeshTiled::handleRenderOverlay(double* proj, double* model, int* view) +{ + toolRenderOverlay(proj, model, view); + + if (m_measurePerTileTimings) + { + if (m_statTimePerTileSamples) + drawGraph("Build Time/Tile", 10, 10, 500, 100, 1.0f, m_statTimePerTile, MAX_STAT_BUCKETS, m_statTimePerTileSamples, "ms"); + + if (m_statPolysPerTileSamples) + drawGraph("Polygons/Tile", 10, 120, 500, 100, 1.0f, m_statPolysPerTile, MAX_STAT_BUCKETS, m_statPolysPerTileSamples, ""); + + int validTiles = 0; + if (m_tileSet) + { + for (int i = 0; i < m_tileSet->width*m_tileSet->height; ++i) + { + if (m_tileSet->tiles[i].buildTime > 0) + validTiles++; + } + } + char text[64]; + snprintf(text,64,"Tiles %d\n", validTiles); + imguiDrawText(10, 240, IMGUI_ALIGN_LEFT, text, imguiRGBA(255,255,255)); + } +} + +void Sample_StatMeshTiled::handleMeshChanged(const float* verts, int nverts, + const int* tris, const float* trinorms, int ntris, + const float* bmin, const float* bmax) +{ + Sample::handleMeshChanged(verts, nverts, tris, trinorms, ntris, bmin, bmax); + toolCleanup(); + toolReset(); + m_statTimePerTileSamples = 0; + m_statPolysPerTileSamples = 0; +} + +bool Sample_StatMeshTiled::handleBuild() +{ + if (!m_verts || ! m_tris) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Input mesh is not specified."); + return false; + } + + if (m_measurePerTileTimings) + { + memset(m_statPolysPerTile, 0, sizeof(m_statPolysPerTile)); + memset(m_statTimePerTile, 0, sizeof(m_statTimePerTile)); + m_statPolysPerTileSamples = 0; + m_statTimePerTileSamples = 0; + } + + cleanup(); + toolCleanup(); + toolReset(); + + // Init build configuration from GUI + memset(&m_cfg, 0, sizeof(m_cfg)); + m_cfg.cs = m_cellSize; + m_cfg.ch = m_cellHeight; + m_cfg.walkableSlopeAngle = m_agentMaxSlope; + m_cfg.walkableHeight = (int)ceilf(m_agentHeight / m_cfg.ch); + m_cfg.walkableClimb = (int)ceilf(m_agentMaxClimb / m_cfg.ch); + m_cfg.walkableRadius = (int)ceilf(m_agentRadius / m_cfg.cs); + m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize); + m_cfg.maxSimplificationError = m_edgeMaxError; + m_cfg.minRegionSize = (int)rcSqr(m_regionMinSize); + m_cfg.mergeRegionSize = (int)rcSqr(m_regionMergeSize); + m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly; + m_cfg.tileSize = (int)m_tileSize; + m_cfg.borderSize = m_cfg.walkableRadius*2 + 2; // Reserve enough padding. + + // Set the area where the navigation will be build. + // Here the bounds of the input mesh are used, but the + // area could be specified by an user defined box, etc. + vcopy(m_cfg.bmin, m_bmin); + vcopy(m_cfg.bmax, m_bmax); + rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height); + + // Reset build times gathering. + memset(&m_buildTimes, 0, sizeof(m_buildTimes)); + rcSetBuildTimes(&m_buildTimes); + + // Start the build process. + rcTimeVal totStartTime = rcGetPerformanceTimer(); + + // Calculate the number of tiles in the output and initialize tiles. + m_tileSet = new TileSet; + if (!m_tileSet) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: Out of memory 'tileSet'."); + return false; + } + vcopy(m_tileSet->bmin, m_cfg.bmin); + vcopy(m_tileSet->bmax, m_cfg.bmax); + m_tileSet->cs = m_cfg.cs; + m_tileSet->ch = m_cfg.ch; + m_tileSet->width = (m_cfg.width + m_cfg.tileSize-1) / m_cfg.tileSize; + m_tileSet->height = (m_cfg.height + m_cfg.tileSize-1) / m_cfg.tileSize; + m_tileSet->tiles = new Tile[m_tileSet->height * m_tileSet->width]; + if (!m_tileSet->tiles) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: Out of memory 'tileSet->tiles' (%d).", m_tileSet->height * m_tileSet->width); + return false; + } + + // Build chunky trimesh for local polygon queries. + rcTimeVal chunkyStartTime = rcGetPerformanceTimer(); + m_chunkyMesh = new rcChunkyTriMesh; + if (!m_chunkyMesh) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: Out of memory 'm_chunkyMesh'."); + return false; + } + if (!rcCreateChunkyTriMesh(m_verts, m_tris, m_ntris, 256, m_chunkyMesh)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: Could not build chunky mesh."); + return false; + } + rcTimeVal chunkyEndTime = rcGetPerformanceTimer(); + + if (rcGetLog()) + { + rcGetLog()->log(RC_LOG_PROGRESS, "Building navigation:"); + rcGetLog()->log(RC_LOG_PROGRESS, " - %d x %d cells", m_cfg.width, m_cfg.height); + rcGetLog()->log(RC_LOG_PROGRESS, " - %d x %d tiles", m_tileSet->width, m_tileSet->height); + rcGetLog()->log(RC_LOG_PROGRESS, " - %.1f verts, %.1f tris", m_nverts/1000.0f, m_ntris/1000.0f); + } + + // Initialize per tile config. + rcConfig tileCfg; + memcpy(&tileCfg, &m_cfg, sizeof(rcConfig)); + tileCfg.width = m_cfg.tileSize + m_cfg.borderSize*2; + tileCfg.height = m_cfg.tileSize + m_cfg.borderSize*2; + + // Allocate array that can hold triangle flags for all geom chunks. + unsigned char* triangleFlags = new unsigned char[m_chunkyMesh->maxTrisPerChunk]; + if (!triangleFlags) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: Out of memory 'triangleFlags' (%d).", m_chunkyMesh->maxTrisPerChunk); + return false; + } + + rcHeightfield* solid = 0; + rcCompactHeightfield* chf = 0; + rcContourSet* cset = 0; + + for (int y = 0; y < m_tileSet->height; ++y) + { + for (int x = 0; x < m_tileSet->width; ++x) + { + rcTimeVal startTime = rcGetPerformanceTimer(); + + Tile& tile = m_tileSet->tiles[x + y*m_tileSet->width]; + + // Calculate the per tile bounding box. + tileCfg.bmin[0] = m_cfg.bmin[0] + (x*m_cfg.tileSize - m_cfg.borderSize)*m_cfg.cs; + tileCfg.bmin[2] = m_cfg.bmin[2] + (y*m_cfg.tileSize - m_cfg.borderSize)*m_cfg.cs; + tileCfg.bmax[0] = m_cfg.bmin[0] + ((x+1)*m_cfg.tileSize + m_cfg.borderSize)*m_cfg.cs; + tileCfg.bmax[2] = m_cfg.bmin[2] + ((y+1)*m_cfg.tileSize + m_cfg.borderSize)*m_cfg.cs; + + delete solid; + delete chf; + solid = 0; + chf = 0; + + float tbmin[2], tbmax[2]; + tbmin[0] = tileCfg.bmin[0]; + tbmin[1] = tileCfg.bmin[2]; + tbmax[0] = tileCfg.bmax[0]; + tbmax[1] = tileCfg.bmax[2]; + int cid[256];// TODO: Make grow when returning too many items. + const int ncid = rcGetChunksInRect(m_chunkyMesh, tbmin, tbmax, cid, 256); + if (!ncid) + continue; + + solid = new rcHeightfield; + if (!solid) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: [%d,%d] Out of memory 'solid'.", x, y); + continue; + } + if (!rcCreateHeightfield(*solid, tileCfg.width, tileCfg.height, tileCfg.bmin, tileCfg.bmax, tileCfg.cs, tileCfg.ch)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: [%d,%d] Could not create solid heightfield.", x, y); + continue; + } + + for (int i = 0; i < ncid; ++i) + { + const rcChunkyTriMeshNode& node = m_chunkyMesh->nodes[cid[i]]; + const int* tris = &m_chunkyMesh->tris[node.i*3]; + const int ntris = node.n; + + memset(triangleFlags, 0, ntris*sizeof(unsigned char)); + rcMarkWalkableTriangles(tileCfg.walkableSlopeAngle, + m_verts, m_nverts, tris, ntris, triangleFlags); + + rcRasterizeTriangles(m_verts, m_nverts, tris, triangleFlags, ntris, *solid); + } + + rcFilterLedgeSpans(tileCfg.walkableHeight, tileCfg.walkableClimb, *solid); + + rcFilterWalkableLowHeightSpans(tileCfg.walkableHeight, *solid); + + chf = new rcCompactHeightfield; + if (!chf) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: [%d,%d] Out of memory 'chf'.", x, y); + continue; + } + if (!rcBuildCompactHeightfield(tileCfg.walkableHeight, tileCfg.walkableClimb, + RC_WALKABLE, *solid, *chf)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: [%d,%d] Could not build compact data.", x, y); + continue; + } + + if (!rcBuildDistanceField(*chf)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: [%d,%d] Could not build distance fields.", x, y); + continue; + } + + if (!rcBuildRegions(*chf, tileCfg.walkableRadius, tileCfg.borderSize, tileCfg.minRegionSize, tileCfg.mergeRegionSize)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: [%d,%d] Could not build regions.", x, y); + continue; + } + + cset = new rcContourSet; + if (!cset) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: [%d,%d] Out of memory 'cset'.", x, y); + continue; + } + if (!rcBuildContours(*chf, tileCfg.maxSimplificationError, tileCfg.maxEdgeLen, *cset)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: [%d,%d] Could not create contours.", x, y); + continue; + } + + if (m_keepInterResults) + { + tile.solid = solid; + solid = 0; + tile.chf = chf; + chf = 0; + } + + if (!cset->nconts) + { + delete cset; + cset = 0; + continue; + } + + tile.cset = cset; + // Offset the vertices in the cset. + rcTranslateContours(tile.cset, x*tileCfg.tileSize - tileCfg.borderSize, 0, y*tileCfg.tileSize - tileCfg.borderSize); + + rcTimeVal endTime = rcGetPerformanceTimer(); + tile.buildTime += rcGetDeltaTimeUsec(startTime, endTime); + } + } + + delete [] triangleFlags; + delete solid; + delete chf; + + + // Some extra code to measure some per tile statistics, + // such as build time and how many polygons there are per tile. + if (m_measurePerTileTimings) + { + for (int y = 0; y < m_tileSet->height; ++y) + { + for (int x = 0; x < m_tileSet->width; ++x) + { + Tile& tile = m_tileSet->tiles[x + y*m_tileSet->width]; + + if (!tile.cset) + continue; + + rcTimeVal startTime = rcGetPerformanceTimer(); + rcPolyMesh* polyMesh = new rcPolyMesh; + if (!polyMesh) + continue; + if (rcBuildPolyMesh(*tile.cset, m_cfg.bmin, m_cfg.bmax, + m_cfg.cs, m_cfg.ch, m_cfg.maxVertsPerPoly, *polyMesh)) + { + int bucket = polyMesh->npolys; + if (bucket < 0) bucket = 0; + if (bucket >= MAX_STAT_BUCKETS) bucket = MAX_STAT_BUCKETS-1; + m_statPolysPerTile[bucket]++; + m_statPolysPerTileSamples++; + } + delete polyMesh; + + rcTimeVal endTime = rcGetPerformanceTimer(); + int time = tile.buildTime += rcGetDeltaTimeUsec(startTime, endTime); + + int bucket = (time+500)/1000; + if (bucket < 0) bucket = 0; + if (bucket >= MAX_STAT_BUCKETS) bucket = MAX_STAT_BUCKETS-1; + m_statTimePerTile[bucket]++; + m_statTimePerTileSamples++; + } + } + } + + // Make sure that the vertices along the tile edges match, + // so that they can be later properly stitched together. + for (int y = 0; y < m_tileSet->height; ++y) + { + for (int x = 0; x < m_tileSet->width; ++x) + { + rcTimeVal startTime = rcGetPerformanceTimer(); + if ((x+1) < m_tileSet->width) + { + if (!rcFixupAdjacentContours(m_tileSet->tiles[x + y*m_tileSet->width].cset, + m_tileSet->tiles[x+1 + y*m_tileSet->width].cset, + m_cfg.walkableClimb, (x+1)*m_cfg.tileSize, -1)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: [%d,%d] Could not fixup x+1.", x, y); + return false; + } + } + + if ((y+1) < m_tileSet->height) + { + if (!rcFixupAdjacentContours(m_tileSet->tiles[x + y*m_tileSet->width].cset, + m_tileSet->tiles[x + (y+1)*m_tileSet->width].cset, + m_cfg.walkableClimb, -1, (y+1)*m_cfg.tileSize)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: [%d,%d] Could not fixup y+1.", x, y); + return false; + } + } + rcTimeVal endTime = rcGetPerformanceTimer(); + m_tileSet->tiles[x+y*m_tileSet->width].buildTime += rcGetDeltaTimeUsec(startTime, endTime); + } + } + + + // Combine contours. + rcContourSet combSet; + + combSet.nconts = 0; + for (int y = 0; y < m_tileSet->height; ++y) + { + for (int x = 0; x < m_tileSet->width; ++x) + { + Tile& tile = m_tileSet->tiles[x + y*m_tileSet->width]; + if (!tile.cset) continue; + combSet.nconts += tile.cset->nconts; + } + } + combSet.conts = new rcContour[combSet.nconts]; + if (!combSet.conts) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: Out of memory 'combSet.conts' (%d).", combSet.nconts); + return false; + } + int n = 0; + for (int y = 0; y < m_tileSet->height; ++y) + { + for (int x = 0; x < m_tileSet->width; ++x) + { + Tile& tile = m_tileSet->tiles[x + y*m_tileSet->width]; + if (!tile.cset) continue; + for (int i = 0; i < tile.cset->nconts; ++i) + { + combSet.conts[n].verts = tile.cset->conts[i].verts; + combSet.conts[n].nverts = tile.cset->conts[i].nverts; + combSet.conts[n].reg = tile.cset->conts[i].reg; + n++; + } + } + } + + m_polyMesh = new rcPolyMesh; + if (!m_polyMesh) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'polyMesh'."); + return false; + } + + bool polyRes = rcBuildPolyMesh(combSet, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch, m_cfg.maxVertsPerPoly, *m_polyMesh); + + // Remove vertex binding to avoid double deletion. + for (int i = 0; i < combSet.nconts; ++i) + { + combSet.conts[i].verts = 0; + combSet.conts[i].nverts = 0; + } + + if (!polyRes) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: Could not triangulate contours."); + return false; + } + + if (!m_keepInterResults) + { + for (int y = 0; y < m_tileSet->height; ++y) + { + for (int x = 0; x < m_tileSet->width; ++x) + { + Tile& tile = m_tileSet->tiles[x + y*m_tileSet->width]; + delete tile.cset; + tile.cset = 0; + } + } + } + + if (m_cfg.maxVertsPerPoly == DT_STAT_VERTS_PER_POLYGON) + { + unsigned char* navData = 0; + int navDataSize = 0; + if (!dtCreateNavMeshData(m_polyMesh->verts, m_polyMesh->nverts, + m_polyMesh->polys, m_polyMesh->npolys, m_polyMesh->nvp, + m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch, &navData, &navDataSize)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "Could not build Detour navmesh."); + return false; + } + + m_navMesh = new dtStatNavMesh; + if (!m_navMesh) + { + delete [] navData; + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "Could not create Detour navmesh"); + return false; + } + + if (!m_navMesh->init(navData, navDataSize, true)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "Could not init Detour navmesh"); + return false; + } + } + + rcTimeVal totEndTime = rcGetPerformanceTimer(); + + if (rcGetLog()) + { + const float pc = 100.0f / rcGetDeltaTimeUsec(totStartTime, totEndTime); + + rcGetLog()->log(RC_LOG_PROGRESS, "Chunky Mesh: %.1fms (%.1f%%)", rcGetDeltaTimeUsec(chunkyStartTime, chunkyEndTime)/1000.0f, rcGetDeltaTimeUsec(chunkyStartTime, chunkyEndTime)*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Rasterize: %.1fms (%.1f%%)", m_buildTimes.rasterizeTriangles/1000.0f, m_buildTimes.rasterizeTriangles*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Compact: %.1fms (%.1f%%)", m_buildTimes.buildCompact/1000.0f, m_buildTimes.buildCompact*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Filter Border: %.1fms (%.1f%%)", m_buildTimes.filterBorder/1000.0f, m_buildTimes.filterBorder*pc); + rcGetLog()->log(RC_LOG_PROGRESS, "Filter Walkable: %.1fms (%.1f%%)", m_buildTimes.filterWalkable/1000.0f, m_buildTimes.filterWalkable*pc); + rcGetLog()->log(RC_LOG_PROGRESS, "Filter Reachable: %.1fms (%.1f%%)", m_buildTimes.filterMarkReachable/1000.0f, m_buildTimes.filterMarkReachable*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Distancefield: %.1fms (%.1f%%)", m_buildTimes.buildDistanceField/1000.0f, m_buildTimes.buildDistanceField*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - distance: %.1fms (%.1f%%)", m_buildTimes.buildDistanceFieldDist/1000.0f, m_buildTimes.buildDistanceFieldDist*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - blur: %.1fms (%.1f%%)", m_buildTimes.buildDistanceFieldBlur/1000.0f, m_buildTimes.buildDistanceFieldBlur*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Regions: %.1fms (%.1f%%)", m_buildTimes.buildRegions/1000.0f, m_buildTimes.buildRegions*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - watershed: %.1fms (%.1f%%)", m_buildTimes.buildRegionsReg/1000.0f, m_buildTimes.buildRegionsReg*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - expand: %.1fms (%.1f%%)", m_buildTimes.buildRegionsExp/1000.0f, m_buildTimes.buildRegionsExp*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - find catchment basins: %.1fms (%.1f%%)", m_buildTimes.buildRegionsFlood/1000.0f, m_buildTimes.buildRegionsFlood*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - filter: %.1fms (%.1f%%)", m_buildTimes.buildRegionsFilter/1000.0f, m_buildTimes.buildRegionsFilter*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Contours: %.1fms (%.1f%%)", m_buildTimes.buildContours/1000.0f, m_buildTimes.buildContours*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - trace: %.1fms (%.1f%%)", m_buildTimes.buildContoursTrace/1000.0f, m_buildTimes.buildContoursTrace*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - simplify: %.1fms (%.1f%%)", m_buildTimes.buildContoursSimplify/1000.0f, m_buildTimes.buildContoursSimplify*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Fixup contours: %.1fms (%.1f%%)", m_buildTimes.fixupContours/1000.0f, m_buildTimes.fixupContours*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Polymesh: %.1fms (%.1f%%)", m_buildTimes.buildPolymesh/1000.0f, m_buildTimes.buildPolymesh*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Polymesh: Verts:%d Polys:%d", m_polyMesh->nverts, m_polyMesh->npolys); + + rcGetLog()->log(RC_LOG_PROGRESS, "TOTAL: %.1fms", rcGetDeltaTimeUsec(totStartTime, totEndTime)/1000.0f); + } + + toolRecalc(); + + return true; +} diff --git a/RecastDemo/Source/Sample_TileMesh.cpp b/RecastDemo/Source/Sample_TileMesh.cpp new file mode 100644 index 0000000..5f23106 --- /dev/null +++ b/RecastDemo/Source/Sample_TileMesh.cpp @@ -0,0 +1,847 @@ +// +// Copyright (c) 2009 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#define _USE_MATH_DEFINES +#include +#include +#include +#include "SDL.h" +#include "SDL_Opengl.h" +#include "imgui.h" +#include "Sample.h" +#include "Sample_TileMesh.h" +#include "Recast.h" +#include "RecastTimer.h" +#include "RecastDebugDraw.h" +#include "DetourTileNavMesh.h" +#include "DetourTileNavMeshBuilder.h" +#include "DetourDebugDraw.h" + +#ifdef WIN32 +# define snprintf _snprintf +#endif + +Sample_TileMesh::Sample_TileMesh() : + m_tileSize(32), + m_navMesh(0), + m_chunkyMesh(0), + m_keepInterResults(true), + m_tileBuildTime(0), + m_tileMemUsage(0), + m_triflags(0), + m_solid(0), + m_chf(0), + m_cset(0), + m_polyMesh(0), + m_tileTriCount(0), + m_toolMode(TOOLMODE_CREATE_TILES), + m_startRef(0), + m_endRef(0), + m_npolys(0), + m_nstraightPath(0), + m_sposSet(false), + m_eposSet(false) +{ + resetCommonSettings(); + memset(m_tileBmin, 0, sizeof(m_tileBmin)); + memset(m_tileBmax, 0, sizeof(m_tileBmax)); + m_polyPickExt[0] = 2; + m_polyPickExt[1] = 4; + m_polyPickExt[2] = 2; +} + +Sample_TileMesh::~Sample_TileMesh() +{ + cleanup(); + delete m_navMesh; + delete m_chunkyMesh; +} + +void Sample_TileMesh::cleanup() +{ + delete [] m_triflags; + m_triflags = 0; + delete m_solid; + m_solid = 0; + delete m_chf; + m_chf = 0; + delete m_cset; + m_cset = 0; + delete m_polyMesh; + m_polyMesh = 0; +} + +void Sample_TileMesh::handleSettings() +{ + Sample::handleCommonSettings(); + + imguiLabel("Tiling"); + imguiSlider("TileSize", &m_tileSize, 16.0f, 1024.0f, 16.0f); + + char text[64]; + int gw = 0, gh = 0; + rcCalcGridSize(m_bmin, m_bmax, m_cellSize, &gw, &gh); + const int ts = (int)m_tileSize; + const int tw = (gw + ts-1) / ts; + const int th = (gh + ts-1) / ts; + snprintf(text, 64, "Tiles %d x %d", tw, th); + imguiValue(text); +} + +void Sample_TileMesh::toolRecalc() +{ + m_startRef = 0; + if (m_sposSet) + m_startRef = m_navMesh->findNearestPoly(m_spos, m_polyPickExt); + + m_endRef = 0; + if (m_eposSet) + m_endRef = m_navMesh->findNearestPoly(m_epos, m_polyPickExt); + + if (m_toolMode == TOOLMODE_PATHFIND) + { + if (m_sposSet && m_eposSet && m_startRef && m_endRef) + { + m_npolys = m_navMesh->findPath(m_startRef, m_endRef, m_polys, MAX_POLYS); + if (m_npolys) + m_nstraightPath = m_navMesh->findStraightPath(m_spos, m_epos, m_polys, m_npolys, m_straightPath, MAX_POLYS); + } + else + { + m_npolys = 0; + m_nstraightPath = 0; + } + } + else if (m_toolMode == TOOLMODE_RAYCAST) + { + m_nstraightPath = 0; + if (m_sposSet && m_eposSet && m_startRef) + { + float t = 0; + m_npolys = 0; + m_nstraightPath = 2; + m_straightPath[0] = m_spos[0]; + m_straightPath[1] = m_spos[1]; + m_straightPath[2] = m_spos[2]; + m_npolys = m_navMesh->raycast(m_startRef, m_spos, m_epos, t, m_polys, MAX_POLYS); + if (m_npolys && t < 1) + { + m_straightPath[3] = m_spos[0] + (m_epos[0] - m_spos[0]) * t; + m_straightPath[4] = m_spos[1] + (m_epos[1] - m_spos[1]) * t; + m_straightPath[5] = m_spos[2] + (m_epos[2] - m_spos[2]) * t; + } + else + { + m_straightPath[3] = m_epos[0]; + m_straightPath[4] = m_epos[1]; + m_straightPath[5] = m_epos[2]; + } + } + } + else if (m_toolMode == TOOLMODE_DISTANCE_TO_WALL) + { + m_distanceToWall = 0; + if (m_sposSet && m_startRef) + m_distanceToWall = m_navMesh->findDistanceToWall(m_startRef, m_spos, 100.0f, m_hitPos, m_hitNormal); + } + else if (m_toolMode == TOOLMODE_FIND_POLYS_AROUND) + { + if (m_sposSet && m_startRef && m_eposSet) + { + const float dx = m_epos[0] - m_spos[0]; + const float dz = m_epos[2] - m_spos[2]; + float dist = sqrtf(dx*dx + dz*dz); + m_npolys = m_navMesh->findPolysAround(m_startRef, m_spos, dist, m_polys, m_parent, 0, MAX_POLYS); + } + } + +} + +void Sample_TileMesh::handleTools() +{ + if (imguiCheck("Create Tiles", m_toolMode == TOOLMODE_CREATE_TILES)) + { + m_toolMode = TOOLMODE_CREATE_TILES; + toolRecalc(); + } + if (imguiCheck("Pathfind", m_toolMode == TOOLMODE_PATHFIND)) + { + m_toolMode = TOOLMODE_PATHFIND; + toolRecalc(); + } + if (imguiCheck("Distance to Wall", m_toolMode == TOOLMODE_DISTANCE_TO_WALL)) + { + m_toolMode = TOOLMODE_DISTANCE_TO_WALL; + toolRecalc(); + } + if (imguiCheck("Raycast", m_toolMode == TOOLMODE_RAYCAST)) + { + m_toolMode = TOOLMODE_RAYCAST; + toolRecalc(); + } + if (imguiCheck("Find Polys Around", m_toolMode == TOOLMODE_FIND_POLYS_AROUND)) + { + m_toolMode = TOOLMODE_FIND_POLYS_AROUND; + toolRecalc(); + } +} + +void Sample_TileMesh::handleDebugMode() +{ + if (m_navMesh) + { + imguiValue("Navmesh ready."); + imguiValue("Use 'Create Tiles' tool to experiment."); + imguiValue("LMB: (Re)Create tiles."); + imguiValue("LMB+SHIFT: Remove tiles."); + } + +} + +static void getPolyCenter(dtTiledNavMesh* navMesh, dtTilePolyRef ref, float* center) +{ + const dtTilePoly* p = navMesh->getPolyByRef(ref); + if (!p) return; + const float* verts = navMesh->getPolyVertsByRef(ref); + center[0] = 0; + center[1] = 0; + center[2] = 0; + for (int i = 0; i < (int)p->nv; ++i) + { + const float* v = &verts[p->v[i]*3]; + center[0] += v[0]; + center[1] += v[1]; + center[2] += v[2]; + } + const float s = 1.0f / p->nv; + center[0] *= s; + center[1] *= s; + center[2] *= s; +} + +void Sample_TileMesh::handleRender() +{ + if (!m_verts || !m_tris || !m_trinorms) + return; + + // Draw mesh + if (m_navMesh) + rcDebugDrawMesh(m_verts, m_nverts, m_tris, m_trinorms, m_ntris, 0); + else + rcDebugDrawMeshSlope(m_verts, m_nverts, m_tris, m_trinorms, m_ntris, m_agentMaxSlope); + + glDepthMask(GL_FALSE); + + // Draw bounds + float col[4] = {1,1,1,0.5f}; + rcDebugDrawBoxWire(m_bmin[0],m_bmin[1],m_bmin[2], m_bmax[0],m_bmax[1],m_bmax[2], col); + + // Tiling grid. + const int ts = (int)m_tileSize; + int gw = 0, gh = 0; + rcCalcGridSize(m_bmin, m_bmax, m_cellSize, &gw, &gh); + int tw = (gw + ts-1) / ts; + int th = (gh + ts-1) / ts; + const float s = ts*m_cellSize; + glBegin(GL_LINES); + glColor4ub(0,0,0,64); + for (int y = 0; y < th; ++y) + { + for (int x = 0; x < tw; ++x) + { + float fx, fy, fz; + fx = m_bmin[0] + x*s; + fy = m_bmin[1]; + fz = m_bmin[2] + y*s; + + glVertex3f(fx,fy,fz); + glVertex3f(fx+s,fy,fz); + glVertex3f(fx,fy,fz); + glVertex3f(fx,fy,fz+s); + + if (x+1 >= tw) + { + glVertex3f(fx+s,fy,fz); + glVertex3f(fx+s,fy,fz+s); + } + if (y+1 >= th) + { + glVertex3f(fx,fy,fz+s); + glVertex3f(fx+s,fy,fz+s); + } + } + } + glEnd(); + + // Draw active tile + rcDebugDrawBoxWire(m_tileBmin[0],m_tileBmin[1],m_tileBmin[2], m_tileBmax[0],m_tileBmax[1],m_tileBmax[2], m_tileCol); + + if (m_navMesh) + dtDebugDrawTiledNavMesh(m_navMesh); + + if (m_sposSet) + { + const float s = 0.5f; + glColor4ub(128,0,0,255); + glBegin(GL_LINES); + glVertex3f(m_spos[0]-s,m_spos[1],m_spos[2]); + glVertex3f(m_spos[0]+s,m_spos[1],m_spos[2]); + glVertex3f(m_spos[0],m_spos[1]-s,m_spos[2]); + glVertex3f(m_spos[0],m_spos[1]+s,m_spos[2]); + glVertex3f(m_spos[0],m_spos[1],m_spos[2]-s); + glVertex3f(m_spos[0],m_spos[1],m_spos[2]+s); + glEnd(); + } + if (m_eposSet) + { + const float s = 0.5f; + glColor4ub(0,128,0,255); + glBegin(GL_LINES); + glVertex3f(m_epos[0]-s,m_epos[1],m_epos[2]); + glVertex3f(m_epos[0]+s,m_epos[1],m_epos[2]); + glVertex3f(m_epos[0],m_epos[1]-s,m_epos[2]); + glVertex3f(m_epos[0],m_epos[1]+s,m_epos[2]); + glVertex3f(m_epos[0],m_epos[1],m_epos[2]-s); + glVertex3f(m_epos[0],m_epos[1],m_epos[2]+s); + glEnd(); + } + + static const float startCol[4] = { 0.5f, 0.1f, 0.0f, 0.75f }; + static const float endCol[4] = { 0.2f, 0.4f, 0.0f, 0.75f }; + static const float pathCol[4] = {0,0,0,0.25f}; + + if (m_toolMode == TOOLMODE_PATHFIND) + { + dtDebugDrawTiledNavMeshPoly(m_navMesh, m_startRef, startCol); + dtDebugDrawTiledNavMeshPoly(m_navMesh, m_endRef, endCol); + + if (m_npolys) + { + for (int i = 1; i < m_npolys-1; ++i) + dtDebugDrawTiledNavMeshPoly(m_navMesh, m_polys[i], pathCol); + } + if (m_nstraightPath) + { + glColor4ub(128,16,0,220); + glLineWidth(3.0f); + glBegin(GL_LINE_STRIP); + for (int i = 0; i < m_nstraightPath; ++i) + glVertex3f(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2]); + glEnd(); + glLineWidth(1.0f); + glPointSize(4.0f); + glBegin(GL_POINTS); + for (int i = 0; i < m_nstraightPath; ++i) + glVertex3f(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2]); + glEnd(); + glPointSize(1.0f); + } + } + else if (m_toolMode == TOOLMODE_RAYCAST) + { + dtDebugDrawTiledNavMeshPoly(m_navMesh, m_startRef, startCol); + + if (m_nstraightPath) + { + for (int i = 1; i < m_npolys; ++i) + dtDebugDrawTiledNavMeshPoly(m_navMesh, m_polys[i], pathCol); + + glColor4ub(128,16,0,220); + glLineWidth(3.0f); + glBegin(GL_LINE_STRIP); + for (int i = 0; i < m_nstraightPath; ++i) + glVertex3f(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2]); + glEnd(); + glLineWidth(1.0f); + glPointSize(4.0f); + glBegin(GL_POINTS); + for (int i = 0; i < m_nstraightPath; ++i) + glVertex3f(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2]); + glEnd(); + glPointSize(1.0f); + } + } + else if (m_toolMode == TOOLMODE_DISTANCE_TO_WALL) + { + dtDebugDrawTiledNavMeshPoly(m_navMesh, m_startRef, startCol); + const float col[4] = {1,1,1,0.5f}; + rcDebugDrawCylinderWire(m_spos[0]-m_distanceToWall, m_spos[1]+0.02f, m_spos[2]-m_distanceToWall, + m_spos[0]+m_distanceToWall, m_spos[1]+m_agentHeight, m_spos[2]+m_distanceToWall, col); + glLineWidth(3.0f); + glColor4fv(col); + glBegin(GL_LINES); + glVertex3f(m_hitPos[0], m_hitPos[1] + 0.02f, m_hitPos[2]); + glVertex3f(m_hitPos[0], m_hitPos[1] + m_agentHeight, m_hitPos[2]); + glEnd(); + glLineWidth(1.0f); + } + else if (m_toolMode == TOOLMODE_FIND_POLYS_AROUND) + { + glLineWidth(2.0f); + for (int i = 0; i < m_npolys; ++i) + { + dtDebugDrawTiledNavMeshPoly(m_navMesh, m_polys[i], pathCol); + if (m_parent[i]) + { + float p0[3], p1[3]; + getPolyCenter(m_navMesh, m_polys[i], p0); + getPolyCenter(m_navMesh, m_parent[i], p1); + glColor4ub(0,0,0,128); + rcDrawArc(p0, p1); + } + } + glLineWidth(1.0f); + + const float dx = m_epos[0] - m_spos[0]; + const float dz = m_epos[2] - m_spos[2]; + float dist = sqrtf(dx*dx + dz*dz); + const float col[4] = {1,1,1,0.5f}; + rcDebugDrawCylinderWire(m_spos[0]-dist, m_spos[1]+0.02f, m_spos[2]-dist, + m_spos[0]+dist, m_spos[1]+m_agentHeight, m_spos[2]+dist, col); + } + + glDepthMask(GL_TRUE); + +} + +void Sample_TileMesh::handleRenderOverlay(double* proj, double* model, int* view) +{ + GLdouble x, y, z; + + // Draw start and end point labels + if (m_tileBuildTime > 0.0f && gluProject((GLdouble)(m_tileBmin[0]+m_tileBmax[0])/2, (GLdouble)(m_tileBmin[1]+m_tileBmax[1])/2, (GLdouble)(m_tileBmin[2]+m_tileBmax[2])/2, + model, proj, view, &x, &y, &z)) + { + char text[32]; + snprintf(text,32,"%.3fms / %dTris / %.1fkB", m_tileBuildTime, m_tileTriCount, m_tileMemUsage); + imguiDrawText((int)x, (int)y-25, IMGUI_ALIGN_CENTER, text, imguiRGBA(0,0,0,220)); + } +} + +void Sample_TileMesh::handleMeshChanged(const float* verts, int nverts, + const int* tris, const float* trinorms, int ntris, + const float* bmin, const float* bmax) +{ + m_verts = verts; + m_nverts = nverts; + m_tris = tris; + m_trinorms = trinorms; + m_ntris = ntris; + vcopy(m_bmin, bmin); + vcopy(m_bmax, bmax); + + delete m_chunkyMesh; + m_chunkyMesh = 0; + delete m_navMesh; + m_navMesh = 0; + cleanup(); +} + +void Sample_TileMesh::setToolStartPos(const float* p) +{ + m_sposSet = true; + vcopy(m_spos, p); + + if (m_toolMode == TOOLMODE_CREATE_TILES) + removeTile(m_spos); + else + toolRecalc(); +} + +void Sample_TileMesh::setToolEndPos(const float* p) +{ + if (!m_navMesh) + return; + + m_eposSet = true; + vcopy(m_epos, p); + + if (m_toolMode == TOOLMODE_CREATE_TILES) + buildTile(m_epos); + else + toolRecalc(); +} + +bool Sample_TileMesh::handleBuild() +{ + if (!m_verts || !m_tris) + { + printf("No verts or tris\n"); + return false; + } + + delete m_navMesh; + m_navMesh = new dtTiledNavMesh; + if (!m_navMesh) + { + printf("Could not allocate navmehs\n"); + return false; + } + if (!m_navMesh->init(m_bmin, m_tileSize*m_cellSize, m_agentMaxClimb*m_cellHeight)) + { + printf("Could not init navmesh\n"); + return false; + } + + // Build chunky mesh. + delete m_chunkyMesh; + m_chunkyMesh = new rcChunkyTriMesh; + if (!m_chunkyMesh) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: Out of memory 'm_chunkyMesh'."); + return false; + } + if (!rcCreateChunkyTriMesh(m_verts, m_tris, m_ntris, 256, m_chunkyMesh)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildTiledNavigation: Could not build chunky mesh."); + return false; + } + + return true; +} + +void Sample_TileMesh::buildTile(const float* pos) +{ + if (!m_navMesh) + return; + + const float ts = m_tileSize*m_cellSize; + const int tx = (int)floorf((pos[0]-m_bmin[0]) / ts); + const int ty = (int)floorf((pos[2]-m_bmin[2]) / ts); + if (tx < 0 || ty < 0) + return; + + m_tileBmin[0] = m_bmin[0] + tx*ts; + m_tileBmin[1] = m_bmin[1]; + m_tileBmin[2] = m_bmin[2] + ty*ts; + + m_tileBmax[0] = m_bmin[0] + (tx+1)*ts; + m_tileBmax[1] = m_bmax[1]; + m_tileBmax[2] = m_bmin[2] + (ty+1)*ts; + + m_tileCol[0] = 0.3f; m_tileCol[1] = 0.8f; m_tileCol[2] = 0; m_tileCol[3] = 1; + + int dataSize = 0; + unsigned char* data = buildTileMesh(m_tileBmin, m_tileBmax, dataSize); + + if (data) + { + // Remove any previous data (navmesh owns and deletes the data). + m_navMesh->removeTileAt(tx,ty,0,0); + + // Let the navmesh own the data. + if (!m_navMesh->addTileAt(tx,ty,data,dataSize,true)) + delete [] data; + } +} + +void Sample_TileMesh::removeTile(const float* pos) +{ + if (!m_navMesh) + return; + + const float ts = m_tileSize*m_cellSize; + const int tx = (int)floorf((pos[0]-m_bmin[0]) / ts); + const int ty = (int)floorf((pos[2]-m_bmin[2]) / ts); + + m_tileBmin[0] = m_bmin[0] + tx*ts; + m_tileBmin[1] = m_bmin[1]; + m_tileBmin[2] = m_bmin[2] + ty*ts; + + m_tileBmax[0] = m_bmin[0] + (tx+1)*ts; + m_tileBmax[1] = m_bmax[1]; + m_tileBmax[2] = m_bmin[2] + (ty+1)*ts; + + m_tileCol[0] = 0.8f; m_tileCol[1] = 0.1f; m_tileCol[2] = 0; m_tileCol[3] = 1; + + unsigned char* rdata = 0; + int rdataSize = 0; + if (m_navMesh->removeTileAt(tx,ty,&rdata,&rdataSize)) + delete [] rdata; +} + +unsigned char* Sample_TileMesh::buildTileMesh(const float* bmin, const float* bmax, int& dataSize) +{ + if (!m_verts || ! m_tris) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Input mesh is not specified."); + return 0; + } + + cleanup(); + + // Init build configuration from GUI + memset(&m_cfg, 0, sizeof(m_cfg)); + m_cfg.cs = m_cellSize; + m_cfg.ch = m_cellHeight; + m_cfg.walkableSlopeAngle = m_agentMaxSlope; + m_cfg.walkableHeight = (int)ceilf(m_agentHeight / m_cfg.ch); + m_cfg.walkableClimb = (int)ceilf(m_agentMaxClimb / m_cfg.ch); + m_cfg.walkableRadius = (int)ceilf(m_agentRadius / m_cfg.cs); + m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize); + m_cfg.maxSimplificationError = m_edgeMaxError; + m_cfg.minRegionSize = (int)rcSqr(m_regionMinSize); + m_cfg.mergeRegionSize = (int)rcSqr(m_regionMergeSize); + m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly; + m_cfg.tileSize = (int)m_tileSize; + m_cfg.borderSize = m_cfg.walkableRadius*2 + 2; // Reserve enough padding. + m_cfg.width = m_cfg.tileSize + m_cfg.borderSize*2; + m_cfg.height = m_cfg.tileSize + m_cfg.borderSize*2; + +/* if (m_cfg.maxVertsPerPoly == DT_VERTS_PER_POLYGON) + m_drawMode = DRAWMODE_NAVMESH; + else + m_drawMode = DRAWMODE_POLYMESH;*/ + + vcopy(m_cfg.bmin, bmin); + vcopy(m_cfg.bmax, bmax); + m_cfg.bmin[0] -= m_cfg.borderSize*m_cfg.cs; + m_cfg.bmin[2] -= m_cfg.borderSize*m_cfg.cs; + m_cfg.bmax[0] += m_cfg.borderSize*m_cfg.cs; + m_cfg.bmax[2] += m_cfg.borderSize*m_cfg.cs; + + // Reset build times gathering. + memset(&m_buildTimes, 0, sizeof(m_buildTimes)); + rcSetBuildTimes(&m_buildTimes); + + // Start the build process. + rcTimeVal totStartTime = rcGetPerformanceTimer(); + + if (rcGetLog()) + { + rcGetLog()->log(RC_LOG_PROGRESS, "Building navigation:"); + rcGetLog()->log(RC_LOG_PROGRESS, " - %d x %d cells", m_cfg.width, m_cfg.height); + rcGetLog()->log(RC_LOG_PROGRESS, " - %.1fK verts, %.1fK tris", m_nverts/1000.0f, m_ntris/1000.0f); + } + + // Allocate voxel heighfield where we rasterize our input data to. + m_solid = new rcHeightfield; + if (!m_solid) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'."); + return 0; + } + if (!rcCreateHeightfield(*m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not create solid heightfield."); + return 0; + } + + // Allocate array that can hold triangle flags. + // If you have multiple meshes you need to process, allocate + // and array which can hold the max number of triangles you need to process. + m_triflags = new unsigned char[m_chunkyMesh->maxTrisPerChunk]; + if (!m_triflags) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'triangleFlags' (%d).", m_chunkyMesh->maxTrisPerChunk); + return 0; + } + + + float tbmin[2], tbmax[2]; + tbmin[0] = m_cfg.bmin[0]; + tbmin[1] = m_cfg.bmin[2]; + tbmax[0] = m_cfg.bmax[0]; + tbmax[1] = m_cfg.bmax[2]; + int cid[256];// TODO: Make grow when returning too many items. + const int ncid = rcGetChunksInRect(m_chunkyMesh, tbmin, tbmax, cid, 256); + if (!ncid) + return 0; + + m_tileTriCount = 0; + + for (int i = 0; i < ncid; ++i) + { + const rcChunkyTriMeshNode& node = m_chunkyMesh->nodes[cid[i]]; + const int* tris = &m_chunkyMesh->tris[node.i*3]; + const int ntris = node.n; + + m_tileTriCount += ntris; + + memset(m_triflags, 0, ntris*sizeof(unsigned char)); + rcMarkWalkableTriangles(m_cfg.walkableSlopeAngle, + m_verts, m_nverts, tris, ntris, m_triflags); + + rcRasterizeTriangles(m_verts, m_nverts, tris, m_triflags, ntris, *m_solid); + } + + if (!m_keepInterResults) + { + delete [] m_triflags; + m_triflags = 0; + } + + // Once all geoemtry is rasterized, we do initial pass of filtering to + // remove unwanted overhangs caused by the conservative rasterization + // as well as filter spans where the character cannot possibly stand. + rcFilterLedgeSpans(m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid); + rcFilterWalkableLowHeightSpans(m_cfg.walkableHeight, *m_solid); + + // Compact the heightfield so that it is faster to handle from now on. + // This will result more cache coherent data as well as the neighbours + // between walkable cells will be calculated. + m_chf = new rcCompactHeightfield; + if (!m_chf) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'."); + return 0; + } + if (!rcBuildCompactHeightfield(m_cfg.walkableHeight, m_cfg.walkableClimb, RC_WALKABLE, *m_solid, *m_chf)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not build compact data."); + return 0; + } + + if (!m_keepInterResults) + { + delete m_solid; + m_solid = 0; + } + + // Prepare for region partitioning, by calculating distance field along the walkable surface. + if (!rcBuildDistanceField(*m_chf)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not build distance field."); + return 0; + } + + // Partition the walkable surface into simple regions without holes. + if (!rcBuildRegions(*m_chf, m_cfg.walkableRadius, m_cfg.borderSize, m_cfg.minRegionSize, m_cfg.mergeRegionSize)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not build regions."); + return 0; + } + + // Create contours. + m_cset = new rcContourSet; + if (!m_cset) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'."); + return 0; + } + if (!rcBuildContours(*m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not create contours."); + return 0; + } + + if (!m_keepInterResults) + { + delete m_chf; + m_chf = 0; + } + + // Build polygon navmesh from the contours. + m_polyMesh = new rcPolyMesh; + if (!m_polyMesh) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'polyMesh'."); + return 0; + } + if (!rcBuildPolyMesh(*m_cset, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch, m_cfg.maxVertsPerPoly, *m_polyMesh)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "buildNavigation: Could not triangulate contours."); + return 0; + } + + if (!m_keepInterResults) + { + delete m_cset; + m_cset = 0; + } + + unsigned char* navData = 0; + int navDataSize = 0; + if (m_cfg.maxVertsPerPoly == DT_TILE_VERTS_PER_POLYGON) + { + // Remove padding from the polymesh data. + for (int i = 0; i < m_polyMesh->nverts; ++i) + { + unsigned short* v = &m_polyMesh->verts[i*3]; + v[0] -= (unsigned short)m_cfg.borderSize; + v[2] -= (unsigned short)m_cfg.borderSize; + } + + if (!dtCreateNavMeshTileData(m_polyMesh->verts, m_polyMesh->nverts, + m_polyMesh->polys, m_polyMesh->npolys, m_polyMesh->nvp, + bmin, bmax, m_cfg.cs, m_cfg.ch, m_cfg.tileSize, m_cfg.walkableClimb, &navData, &navDataSize)) + { + if (rcGetLog()) + rcGetLog()->log(RC_LOG_ERROR, "Could not build Detour navmesh."); + return 0; + } + } + m_tileMemUsage = navDataSize/1024.0f; + + rcTimeVal totEndTime = rcGetPerformanceTimer(); + + // Show performance stats. + if (rcGetLog()) + { + const float pc = 100.0f / rcGetDeltaTimeUsec(totStartTime, totEndTime); + + rcGetLog()->log(RC_LOG_PROGRESS, "Rasterize: %.1fms (%.1f%%)", m_buildTimes.rasterizeTriangles/1000.0f, m_buildTimes.rasterizeTriangles*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Compact: %.1fms (%.1f%%)", m_buildTimes.buildCompact/1000.0f, m_buildTimes.buildCompact*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Filter Border: %.1fms (%.1f%%)", m_buildTimes.filterBorder/1000.0f, m_buildTimes.filterBorder*pc); + rcGetLog()->log(RC_LOG_PROGRESS, "Filter Walkable: %.1fms (%.1f%%)", m_buildTimes.filterWalkable/1000.0f, m_buildTimes.filterWalkable*pc); + rcGetLog()->log(RC_LOG_PROGRESS, "Filter Reachable: %.1fms (%.1f%%)", m_buildTimes.filterMarkReachable/1000.0f, m_buildTimes.filterMarkReachable*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Distancefield: %.1fms (%.1f%%)", m_buildTimes.buildDistanceField/1000.0f, m_buildTimes.buildDistanceField*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - distance: %.1fms (%.1f%%)", m_buildTimes.buildDistanceFieldDist/1000.0f, m_buildTimes.buildDistanceFieldDist*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - blur: %.1fms (%.1f%%)", m_buildTimes.buildDistanceFieldBlur/1000.0f, m_buildTimes.buildDistanceFieldBlur*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Regions: %.1fms (%.1f%%)", m_buildTimes.buildRegions/1000.0f, m_buildTimes.buildRegions*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - watershed: %.1fms (%.1f%%)", m_buildTimes.buildRegionsReg/1000.0f, m_buildTimes.buildRegionsReg*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - expand: %.1fms (%.1f%%)", m_buildTimes.buildRegionsExp/1000.0f, m_buildTimes.buildRegionsExp*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - find catchment basins: %.1fms (%.1f%%)", m_buildTimes.buildRegionsFlood/1000.0f, m_buildTimes.buildRegionsFlood*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - filter: %.1fms (%.1f%%)", m_buildTimes.buildRegionsFilter/1000.0f, m_buildTimes.buildRegionsFilter*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Contours: %.1fms (%.1f%%)", m_buildTimes.buildContours/1000.0f, m_buildTimes.buildContours*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - trace: %.1fms (%.1f%%)", m_buildTimes.buildContoursTrace/1000.0f, m_buildTimes.buildContoursTrace*pc); + rcGetLog()->log(RC_LOG_PROGRESS, " - simplify: %.1fms (%.1f%%)", m_buildTimes.buildContoursSimplify/1000.0f, m_buildTimes.buildContoursSimplify*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Fixup contours: %.1fms (%.1f%%)", m_buildTimes.fixupContours/1000.0f, m_buildTimes.fixupContours*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Build Polymesh: %.1fms (%.1f%%)", m_buildTimes.buildPolymesh/1000.0f, m_buildTimes.buildPolymesh*pc); + + rcGetLog()->log(RC_LOG_PROGRESS, "Polymesh: Verts:%d Polys:%d", m_polyMesh->nverts, m_polyMesh->npolys); + + rcGetLog()->log(RC_LOG_PROGRESS, "TOTAL: %.1fms", rcGetDeltaTimeUsec(totStartTime, totEndTime)/1000.0f); + } + + m_tileBuildTime = rcGetDeltaTimeUsec(totStartTime, totEndTime)/1000.0f; + + dataSize = navDataSize; + return navData; +}