diff --git a/RecastDemo/Include/Sample_SoloMesh.h b/RecastDemo/Include/Sample_SoloMesh.h index a278529e..0a8d315e 100644 --- a/RecastDemo/Include/Sample_SoloMesh.h +++ b/RecastDemo/Include/Sample_SoloMesh.h @@ -16,26 +16,24 @@ // 3. This notice may not be removed or altered from any source distribution. // -#ifndef RECASTSAMPLESOLOMESH_H -#define RECASTSAMPLESOLOMESH_H +#pragma once -#include "Sample.h" -#include "DetourNavMesh.h" #include "Recast.h" +#include "Sample.h" class Sample_SoloMesh : public Sample { protected: - bool m_keepInterResults; - float m_totalBuildTimeMs; + bool m_keepInterResults = true; + float m_totalBuildTimeMs = 0; - unsigned char* m_triareas; - rcHeightfield* m_solid; - rcCompactHeightfield* m_chf; - rcContourSet* m_cset; - rcPolyMesh* m_pmesh; - rcConfig m_cfg; - rcPolyMeshDetail* m_dmesh; + unsigned char* m_triareas = nullptr; + rcHeightfield* m_solid = nullptr; + rcCompactHeightfield* m_chf = nullptr; + rcContourSet* m_cset = nullptr; + rcPolyMesh* m_pmesh = nullptr; + rcConfig m_cfg {}; + rcPolyMeshDetail* m_dmesh = nullptr; enum DrawMode { @@ -59,28 +57,24 @@ protected: MAX_DRAWMODE }; - DrawMode m_drawMode; + DrawMode m_drawMode = DRAWMODE_NAVMESH; void cleanup(); public: Sample_SoloMesh(); - virtual ~Sample_SoloMesh(); - - virtual void handleSettings(); - virtual void handleTools(); - virtual void handleDebugMode(); - - virtual void handleRender(); - virtual void handleRenderOverlay(double* proj, double* model, int* view); - virtual void handleMeshChanged(class InputGeom* geom); - virtual bool handleBuild(); + ~Sample_SoloMesh() override; + Sample_SoloMesh(const Sample_SoloMesh&) = delete; + Sample_SoloMesh& operator=(const Sample_SoloMesh&) = delete; + Sample_SoloMesh(const Sample_SoloMesh&&) = delete; + Sample_SoloMesh& operator=(const Sample_SoloMesh&&) = delete; -private: - // Explicitly disabled copy constructor and copy assignment operator. - Sample_SoloMesh(const Sample_SoloMesh&); - Sample_SoloMesh& operator=(const Sample_SoloMesh&); + void handleSettings() override; + void handleTools() override; + void handleDebugMode() override; + + void handleRender() override; + void handleRenderOverlay(double* proj, double* model, int* view) override; + void handleMeshChanged(class InputGeom* geom) override; + bool handleBuild() override; }; - - -#endif // RECASTSAMPLESOLOMESHSIMPLE_H diff --git a/RecastDemo/Source/Sample_SoloMesh.cpp b/RecastDemo/Source/Sample_SoloMesh.cpp index 174a4e15..c1c77dbe 100644 --- a/RecastDemo/Source/Sample_SoloMesh.cpp +++ b/RecastDemo/Source/Sample_SoloMesh.cpp @@ -16,42 +16,34 @@ // 3. This notice may not be removed or altered from any source distribution. // -#include -#include -#include -#include "SDL.h" -#include "SDL_opengl.h" +#include "Sample_SoloMesh.h" + +#include +#include +#include + +#include "ConvexVolumeTool.h" +#include "CrowdTool.h" +#include "DetourDebugDraw.h" +#include "DetourNavMesh.h" +#include "DetourNavMeshBuilder.h" #include "imgui.h" #include "InputGeom.h" -#include "Sample.h" -#include "Sample_SoloMesh.h" +#include "NavMeshPruneTool.h" +#include "NavMeshTesterTool.h" +#include "OffMeshConnectionTool.h" #include "Recast.h" #include "RecastDebugDraw.h" #include "RecastDump.h" -#include "DetourNavMesh.h" -#include "DetourNavMeshBuilder.h" -#include "DetourDebugDraw.h" -#include "NavMeshTesterTool.h" -#include "NavMeshPruneTool.h" -#include "OffMeshConnectionTool.h" -#include "ConvexVolumeTool.h" -#include "CrowdTool.h" +#include "Sample.h" +#include "SDL.h" +#include "SDL_opengl.h" #ifdef WIN32 # define snprintf _snprintf #endif - -Sample_SoloMesh::Sample_SoloMesh() : - m_keepInterResults(true), - m_totalBuildTimeMs(0), - m_triareas(0), - m_solid(0), - m_chf(0), - m_cset(0), - m_pmesh(0), - m_dmesh(0), - m_drawMode(DRAWMODE_NAVMESH) +Sample_SoloMesh::Sample_SoloMesh() { setTool(new NavMeshTesterTool); } @@ -63,20 +55,13 @@ Sample_SoloMesh::~Sample_SoloMesh() void Sample_SoloMesh::cleanup() { - delete [] m_triareas; - m_triareas = 0; - rcFreeHeightField(m_solid); - m_solid = 0; - rcFreeCompactHeightfield(m_chf); - m_chf = 0; - rcFreeContourSet(m_cset); - m_cset = 0; - rcFreePolyMesh(m_pmesh); - m_pmesh = 0; - rcFreePolyMeshDetail(m_dmesh); - m_dmesh = 0; - dtFreeNavMesh(m_navMesh); - m_navMesh = 0; + delete [] m_triareas; m_triareas = 0; + rcFreeHeightField(m_solid); m_solid = 0; + rcFreeCompactHeightfield(m_chf); m_chf = 0; + rcFreeContourSet(m_cset); m_cset = 0; + rcFreePolyMesh(m_pmesh); m_pmesh = 0; + rcFreePolyMeshDetail(m_dmesh); m_dmesh = 0; + dtFreeNavMesh(m_navMesh); m_navMesh = 0; } void Sample_SoloMesh::handleSettings() @@ -84,7 +69,9 @@ void Sample_SoloMesh::handleSettings() Sample::handleCommonSettings(); if (imguiCheck("Keep Itermediate Results", m_keepInterResults)) + { m_keepInterResults = !m_keepInterResults; + } imguiSeparator(); @@ -105,7 +92,7 @@ void Sample_SoloMesh::handleSettings() imguiUnindent(); imguiUnindent(); - + char msg[64]; snprintf(msg, 64, "Build Time: %.1fms", m_totalBuildTimeMs); imguiLabel(msg); @@ -115,123 +102,57 @@ void Sample_SoloMesh::handleSettings() void Sample_SoloMesh::handleTools() { - int type = !m_tool ? TOOL_NONE : m_tool->type(); - - if (imguiCheck("Test Navmesh", type == TOOL_NAVMESH_TESTER)) - { - setTool(new NavMeshTesterTool); - } - if (imguiCheck("Prune Navmesh", type == TOOL_NAVMESH_PRUNE)) - { - setTool(new NavMeshPruneTool); - } - if (imguiCheck("Create Off-Mesh Connections", type == TOOL_OFFMESH_CONNECTION)) - { - setTool(new OffMeshConnectionTool); - } - if (imguiCheck("Create Convex Volumes", type == TOOL_CONVEX_VOLUME)) - { - setTool(new ConvexVolumeTool); - } - if (imguiCheck("Create Crowds", type == TOOL_CROWD)) - { - setTool(new CrowdTool); - } - + const int type = !m_tool ? TOOL_NONE : m_tool->type(); + + if (imguiCheck("Test Navmesh", type == TOOL_NAVMESH_TESTER)) { setTool(new NavMeshTesterTool); } + if (imguiCheck("Prune Navmesh", type == TOOL_NAVMESH_PRUNE)) { setTool(new NavMeshPruneTool); } + if (imguiCheck("Create Off-Mesh Connections", type == TOOL_OFFMESH_CONNECTION)) { setTool(new OffMeshConnectionTool); } + if (imguiCheck("Create Convex Volumes", type == TOOL_CONVEX_VOLUME)) { setTool(new ConvexVolumeTool); } + if (imguiCheck("Create Crowds", type == TOOL_CROWD)) { setTool(new CrowdTool); } + imguiSeparatorLine(); imguiIndent(); if (m_tool) + { m_tool->handleMenu(); + } imguiUnindent(); - } void Sample_SoloMesh::handleDebugMode() { - // Check which modes are valid. - bool valid[MAX_DRAWMODE]; - for (int i = 0; i < MAX_DRAWMODE; ++i) - valid[i] = false; - - if (m_geom) - { - valid[DRAWMODE_NAVMESH] = m_navMesh != 0; - valid[DRAWMODE_NAVMESH_TRANS] = m_navMesh != 0; - valid[DRAWMODE_NAVMESH_BVTREE] = m_navMesh != 0; - valid[DRAWMODE_NAVMESH_NODES] = m_navQuery != 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_pmesh != 0; - valid[DRAWMODE_POLYMESH_DETAIL] = m_dmesh != 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("Navmesh Nodes", m_drawMode == DRAWMODE_NAVMESH_NODES, valid[DRAWMODE_NAVMESH_NODES])) - m_drawMode = DRAWMODE_NAVMESH_NODES; - 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 (imguiCheck("Poly Mesh Detail", m_drawMode == DRAWMODE_POLYMESH_DETAIL, valid[DRAWMODE_POLYMESH_DETAIL])) - m_drawMode = DRAWMODE_POLYMESH_DETAIL; - - if (unavail) - { - imguiValue("Tick 'Keep Itermediate Results'"); - imguiValue("to see more debug mode options."); - } +#define DRAW_OPTION(name, value, condition) if (imguiCheck(name, m_drawMode == (value), (condition))) { m_drawMode = value; } + DRAW_OPTION("Input Mesh", DRAWMODE_MESH, true) + DRAW_OPTION("Navmesh", DRAWMODE_NAVMESH, m_navMesh != nullptr) + DRAW_OPTION("Navmesh Invis", DRAWMODE_NAVMESH_INVIS, m_navMesh != nullptr) + DRAW_OPTION("Navmesh Trans", DRAWMODE_NAVMESH_TRANS, m_navMesh != nullptr) + DRAW_OPTION("Navmesh BVTree", DRAWMODE_NAVMESH_BVTREE, m_navMesh != nullptr) + DRAW_OPTION("Navmesh Nodes", DRAWMODE_NAVMESH_NODES, m_navQuery != nullptr) + DRAW_OPTION("Voxels", DRAWMODE_VOXELS, m_solid != nullptr) + DRAW_OPTION("Walkable Voxels", DRAWMODE_VOXELS_WALKABLE, m_solid != nullptr) + DRAW_OPTION("Compact", DRAWMODE_COMPACT, m_chf != nullptr) + DRAW_OPTION("Compact Distance", DRAWMODE_COMPACT_DISTANCE, m_chf != nullptr) + DRAW_OPTION("Compact Regions", DRAWMODE_COMPACT_REGIONS, m_chf != nullptr) + DRAW_OPTION("Region Connections", DRAWMODE_REGION_CONNECTIONS, m_cset != nullptr) + DRAW_OPTION("Raw Contours", DRAWMODE_RAW_CONTOURS, m_cset != nullptr) + DRAW_OPTION("Both Contours", DRAWMODE_BOTH_CONTOURS, m_cset != nullptr) + DRAW_OPTION("Contours", DRAWMODE_CONTOURS, m_cset != nullptr) + DRAW_OPTION("Poly Mesh", DRAWMODE_POLYMESH, m_pmesh != nullptr) + DRAW_OPTION("Poly Mesh Detail", DRAWMODE_POLYMESH_DETAIL, m_dmesh != nullptr) +#undef DRAW_OPTION } void Sample_SoloMesh::handleRender() { if (!m_geom || !m_geom->getMesh()) + { return; - + } + glEnable(GL_FOG); glDepthMask(GL_TRUE); @@ -265,23 +186,35 @@ void Sample_SoloMesh::handleRender() m_drawMode == DRAWMODE_NAVMESH_INVIS)) { if (m_drawMode != DRAWMODE_NAVMESH_INVIS) + { duDebugDrawNavMeshWithClosedList(&m_dd, *m_navMesh, *m_navQuery, m_navMeshDrawFlags); + } if (m_drawMode == DRAWMODE_NAVMESH_BVTREE) + { duDebugDrawNavMeshBVTree(&m_dd, *m_navMesh); + } if (m_drawMode == DRAWMODE_NAVMESH_NODES) + { duDebugDrawNavMeshNodes(&m_dd, *m_navQuery); + } duDebugDrawNavMeshPolysWithFlags(&m_dd, *m_navMesh, SAMPLE_POLYFLAGS_DISABLED, duRGBA(0,0,0,128)); } glDepthMask(GL_TRUE); if (m_chf && m_drawMode == DRAWMODE_COMPACT) + { duDebugDrawCompactHeightfieldSolid(&m_dd, *m_chf); + } if (m_chf && m_drawMode == DRAWMODE_COMPACT_DISTANCE) + { duDebugDrawCompactHeightfieldDistance(&m_dd, *m_chf); + } if (m_chf && m_drawMode == DRAWMODE_COMPACT_REGIONS) + { duDebugDrawCompactHeightfieldRegions(&m_dd, *m_chf); + } if (m_solid && m_drawMode == DRAWMODE_VOXELS) { glEnable(GL_FOG); @@ -337,7 +270,9 @@ void Sample_SoloMesh::handleRender() m_geom->drawConvexVolumes(&m_dd); if (m_tool) + { m_tool->handleRender(); + } renderToolStates(); glDepthMask(GL_TRUE); @@ -346,7 +281,9 @@ void Sample_SoloMesh::handleRender() void Sample_SoloMesh::handleRenderOverlay(double* proj, double* model, int* view) { if (m_tool) + { m_tool->handleRenderOverlay(proj, model, view); + } renderOverlayToolStates(proj, model, view); } @@ -419,7 +356,7 @@ bool Sample_SoloMesh::handleBuild() m_ctx->log(RC_LOG_PROGRESS, "Building navigation:"); m_ctx->log(RC_LOG_PROGRESS, " - %d x %d cells", m_cfg.width, m_cfg.height); - m_ctx->log(RC_LOG_PROGRESS, " - %.1fK verts, %.1fK tris", nverts/1000.0f, ntris/1000.0f); + m_ctx->log(RC_LOG_PROGRESS, " - %.1fK verts, %.1fK tris", static_cast(nverts) / 1000.0f, static_cast(ntris) / 1000.0f); // // Step 2. Rasterize input polygon soup. @@ -473,12 +410,17 @@ bool Sample_SoloMesh::handleBuild() // remove unwanted overhangs caused by the conservative rasterization // as well as filter spans where the character cannot possibly stand. if (m_filterLowHangingObstacles) + { rcFilterLowHangingWalkableObstacles(m_ctx, m_cfg.walkableClimb, *m_solid); + } if (m_filterLedgeSpans) + { rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid); + } if (m_filterWalkableLowHeightSpans) + { rcFilterWalkableLowHeightSpans(m_ctx, m_cfg.walkableHeight, *m_solid); - + } // // Step 4. Partition walkable surface to simple regions. @@ -515,9 +457,10 @@ bool Sample_SoloMesh::handleBuild() // (Optional) Mark areas. const ConvexVolume* vols = m_geom->getConvexVolumes(); for (int i = 0; i < m_geom->getConvexVolumeCount(); ++i) + { rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned char)vols[i].area, *m_chf); + } - // Partition the heightfield so that we can use simple algorithm later to triangulate the walkable areas. // There are 3 partitioning methods, each with some pros and cons: // 1) Watershed partitioning @@ -657,11 +600,13 @@ bool Sample_SoloMesh::handleBuild() for (int i = 0; i < m_pmesh->npolys; ++i) { if (m_pmesh->areas[i] == RC_WALKABLE_AREA) + { m_pmesh->areas[i] = SAMPLE_POLYAREA_GROUND; - + } + if (m_pmesh->areas[i] == SAMPLE_POLYAREA_GROUND || - m_pmesh->areas[i] == SAMPLE_POLYAREA_GRASS || - m_pmesh->areas[i] == SAMPLE_POLYAREA_ROAD) + m_pmesh->areas[i] == SAMPLE_POLYAREA_GRASS || + m_pmesh->areas[i] == SAMPLE_POLYAREA_ROAD) { m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK; } @@ -675,7 +620,6 @@ bool Sample_SoloMesh::handleBuild() } } - dtNavMeshCreateParams params; memset(¶ms, 0, sizeof(params)); params.verts = m_pmesh->verts; @@ -719,10 +663,8 @@ bool Sample_SoloMesh::handleBuild() m_ctx->log(RC_LOG_ERROR, "Could not create Detour navmesh"); return false; } - - dtStatus status; - - status = m_navMesh->init(navData, navDataSize, DT_TILE_FREE_DATA); + + dtStatus status = m_navMesh->init(navData, navDataSize, DT_TILE_FREE_DATA); if (dtStatusFailed(status)) { dtFree(navData); @@ -744,10 +686,12 @@ bool Sample_SoloMesh::handleBuild() duLogBuildTimes(*m_ctx, m_ctx->getAccumulatedTime(RC_TIMER_TOTAL)); m_ctx->log(RC_LOG_PROGRESS, ">> Polymesh: %d vertices %d polygons", m_pmesh->nverts, m_pmesh->npolys); - m_totalBuildTimeMs = m_ctx->getAccumulatedTime(RC_TIMER_TOTAL)/1000.0f; + m_totalBuildTimeMs = static_cast(m_ctx->getAccumulatedTime(RC_TIMER_TOTAL)) / 1000.0f; if (m_tool) + { m_tool->init(this); + } initToolStates(this); return true;