From f95eb13ab30c78c03c38aa20492389d0fdf39a7f Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 12 Jul 2024 13:01:47 +0200 Subject: [PATCH] Recast: tilemesh editor refactor Move common code to Editor_Common and fix solomesh. Solomesh is useful for debugging recast as it allows for generating everything in 1 tile. Also did numerous fixes for the tilecache code, though this is still broken and won't be really used for the r5sdk project, but its nice to have for a potential project outside r5sdk that uses the xyz coordination system, which avoids having to run the navmesh through a conversion pass in runtime. --- src/naveditor/CMakeLists.txt | 4 + src/naveditor/Editor.cpp | 118 +++- src/naveditor/Editor_Common.cpp | 593 +++++++++++++++++++ src/naveditor/Editor_SoloMesh.cpp | 285 ++------- src/naveditor/Editor_TempObstacles.cpp | 514 ++++++---------- src/naveditor/Editor_TileMesh.cpp | 463 +-------------- src/naveditor/include/Editor.h | 6 + src/naveditor/include/Editor_Common.h | 113 ++++ src/naveditor/include/Editor_SoloMesh.h | 46 +- src/naveditor/include/Editor_TempObstacles.h | 41 +- src/naveditor/include/Editor_TileMesh.h | 49 +- src/naveditor/main.cpp | 2 + 12 files changed, 1083 insertions(+), 1151 deletions(-) create mode 100644 src/naveditor/Editor_Common.cpp create mode 100644 src/naveditor/include/Editor_Common.h diff --git a/src/naveditor/CMakeLists.txt b/src/naveditor/CMakeLists.txt index 1a78e158..b31b165f 100644 --- a/src/naveditor/CMakeLists.txt +++ b/src/naveditor/CMakeLists.txt @@ -4,11 +4,15 @@ add_module( "exe" "recast" "" ${FOLDER_CONTEXT} TRUE TRUE ) start_sources() add_sources( SOURCE_GROUP "Builder" + "Editor_Common.cpp" + "Editor_SoloMesh.cpp" "Editor_TileMesh.cpp" "InputGeom.cpp" ) add_sources( SOURCE_GROUP "Builder/Include" + "Include/Editor_Common.h" + "Include/Editor_SoloMesh.h" "include/Editor_TileMesh.h" "include/InputGeom.h" ) diff --git a/src/naveditor/Editor.cpp b/src/naveditor/Editor.cpp index 60a754d8..aac6cc33 100644 --- a/src/naveditor/Editor.cpp +++ b/src/naveditor/Editor.cpp @@ -29,6 +29,9 @@ #include "NavEditor/Include/InputGeom.h" #include "NavEditor/Include/Editor.h" +#include "game/server/ai_navmesh.h" +#include "game/server/ai_hull.h" + unsigned int EditorDebugDraw::areaToCol(unsigned int area) { switch(area) @@ -170,12 +173,11 @@ void Editor::collectSettings(BuildSettings& settings) void Editor::resetCommonSettings() { + selectNavMeshType(NAVMESH_SMALL); + m_cellSize = 16.0f; m_cellHeight = 5.85f; - m_agentHeight = 2.0f; - m_agentRadius = 0.6f; - m_agentMaxClimb = 0.9f; - m_agentMaxSlope = 45.0f; + m_agentMaxSlope = 45.0f; // todo(amos) put into hull def! m_regionMinSize = 8; m_regionMergeSize = 20; m_edgeMaxLen = 12; @@ -187,6 +189,19 @@ void Editor::resetCommonSettings() } void Editor::handleCommonSettings() { + ImGui::Text("NavMesh Type"); + for (int i = 0; i < NAVMESH_COUNT; i++) + { + const NavMeshType_e navMeshType = NavMeshType_e(i); + + if (ImGui::Button(NavMesh_GetNameForType(navMeshType), ImVec2(120, 0))) + { + selectNavMeshType(navMeshType); + } + } + + ImGui::Separator(); + ImGui::PushItemWidth(180.f); ImGui::Text("Rasterization"); @@ -339,6 +354,97 @@ void Editor::renderOverlayToolStates(double* proj, double* model, int* view) } } +void Editor::renderNavMeshDebugMenu() +{ + ImGui::Text("NavMesh Render Options"); + + bool isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_OFFMESHCONS); + + if (ImGui::Checkbox("Off-Mesh Connections", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_OFFMESHCONS); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_NODES); + + if (ImGui::Checkbox("Query Nodes", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_NODES); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_BVTREE); + + if (ImGui::Checkbox("BVTree", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_BVTREE); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_PORTALS); + + if (ImGui::Checkbox("Portals", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_PORTALS); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_CLOSEDLIST); + + if (ImGui::Checkbox("Closed List", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_CLOSEDLIST); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_COLOR_TILES); + + if (ImGui::Checkbox("Tile ID Colors", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_COLOR_TILES); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_VERTS); + + if (ImGui::Checkbox("Vertex Points", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_VERTS); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_INNERBOUND); + + if (ImGui::Checkbox("Inner Poly Boundaries", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_INNERBOUND); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_OUTERBOUND); + + if (ImGui::Checkbox("Outer Poly Boundaries", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_OUTERBOUND); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_POLYCENTERS); + + if (ImGui::Checkbox("Poly Centers", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_POLYCENTERS); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_POLYGROUPS); + + if (ImGui::Checkbox("Poly Group Colors", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_POLYGROUPS); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_DEPTH_MASK); + + if (ImGui::Checkbox("Depth Mask", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_DEPTH_MASK); + + isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_ALPHA); + + if (ImGui::Checkbox("Transparency", &isEnabled)) + toggleNavMeshDrawFlag(DU_DRAWNAVMESH_ALPHA); +} + +const hulldef hulls[NAVMESH_COUNT] = { + { g_navMeshNames[NAVMESH_SMALL] , NAI_Hull::Width(HULL_HUMAN) , NAI_Hull::Height(HULL_HUMAN) * NAI_Hull::Scale(HULL_HUMAN) , 45, 32 }, + { g_navMeshNames[NAVMESH_MED_SHORT] , NAI_Hull::Width(HULL_PROWLER), NAI_Hull::Height(HULL_PROWLER) * NAI_Hull::Scale(HULL_PROWLER), 50, 32 }, + { g_navMeshNames[NAVMESH_MEDIUM] , NAI_Hull::Width(HULL_MEDIUM) , NAI_Hull::Height(HULL_MEDIUM) * NAI_Hull::Scale(HULL_MEDIUM) , 55, 32 }, + { g_navMeshNames[NAVMESH_LARGE] , NAI_Hull::Width(HULL_TITAN) , NAI_Hull::Height(HULL_TITAN) * NAI_Hull::Scale(HULL_TITAN) , 60, 64 }, + { g_navMeshNames[NAVMESH_EXTRA_LARGE], NAI_Hull::Width(HULL_GOLIATH), NAI_Hull::Height(HULL_GOLIATH) * NAI_Hull::Scale(HULL_GOLIATH), 65, 64 }, +}; + +void Editor::selectNavMeshType(const NavMeshType_e navMeshType) +{ + const hulldef& h = hulls[navMeshType]; + + m_agentRadius = h.radius; + m_agentMaxClimb = h.climbHeight; + m_agentHeight = h.height; + m_navmeshName = h.name; + m_tileSize = h.tileSize; + + m_selectedNavMeshType = navMeshType; +} + dtNavMesh* Editor::loadAll(std::string path) { fs::path p = "..\\maps\\navmesh\\"; @@ -362,12 +468,12 @@ dtNavMesh* Editor::loadAll(std::string path) fclose(fp); return 0; } - if (header.magic != NAVMESHSET_MAGIC) + if (header.magic != NAVMESHSET_MAGIC) // todo(amos) check for tool mode since tilecache uses different constants! { fclose(fp); return 0; } - if (header.version != NAVMESHSET_VERSION) + if (header.version != NAVMESHSET_VERSION) // todo(amos) check for tool mode since tilecache uses different constants! { fclose(fp); return 0; diff --git a/src/naveditor/Editor_Common.cpp b/src/naveditor/Editor_Common.cpp new file mode 100644 index 00000000..0120a012 --- /dev/null +++ b/src/naveditor/Editor_Common.cpp @@ -0,0 +1,593 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#include "Shared/Include/SharedAssert.h" +#include "Include/Editor.h" +#include "Include/Editor_Common.h" +#include "DebugUtils/Include/RecastDebugDraw.h" +#include "DebugUtils/Include/DetourDebugDraw.h" +#include "Include/InputGeom.h" +#include + +// todo(amos): move these to common math. +inline unsigned int nextPow2(unsigned int v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +// todo(amos): move these to common math. +inline unsigned int ilog2(unsigned int v) +{ + unsigned int r; + unsigned int shift; + r = (v > 0xffff) << 4; v >>= r; + shift = (v > 0xff) << 3; v >>= shift; r |= shift; + shift = (v > 0xf) << 2; v >>= shift; r |= shift; + shift = (v > 0x3) << 1; v >>= shift; r |= shift; + r |= (v >> 1); + return r; +} + +static void EditorCommon_DrawInputGeometry(duDebugDraw* const dd, const InputGeom* const geom, + const float maxSlope, const float textureScale) +{ + duDebugDrawTriMeshSlope(dd, geom->getMesh()->getVerts(), geom->getMesh()->getVertCount(), + geom->getMesh()->getTris(), geom->getMesh()->getNormals(), geom->getMesh()->getTriCount(), + maxSlope, textureScale); +} + +static void EditorCommon_DrawBoundingBox(duDebugDraw* const dd, const InputGeom* const geom) +{ + // Draw bounds + const float* const bmin = geom->getNavMeshBoundsMin(); + const float* const bmax = geom->getNavMeshBoundsMax(); + duDebugDrawBoxWire(dd, bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2], duRGBA(255, 255, 255, 128), 1.0f); +} + +static void EditorCommon_DrawTilingGrid(duDebugDraw* const dd, const InputGeom* const geom, const int tileSize, const float cellSize) +{ + const float* const bmin = geom->getNavMeshBoundsMin(); + const float* const bmax = geom->getNavMeshBoundsMax(); + + int gw = 0, gh = 0; + rcCalcGridSize(bmin, bmax, cellSize, &gw, &gh); + + const int tw = (gw + tileSize - 1) / tileSize; + const int th = (gh + tileSize - 1) / tileSize; + const float s = tileSize * cellSize; + + duDebugDrawGridXY(dd, bmax[0], bmin[1], bmin[2], tw, th, s, duRGBA(0, 0, 0, 64), 1.0f); +} + +int EditorCommon_SetAndRenderTileProperties(const InputGeom* const geom, const int tileSize, + const float cellSize, int& maxTiles, int& maxPolysPerTile) +{ + int gridSize = 1; + + if (geom) + { + int gw = 0, gh = 0; + const float* bmin = geom->getNavMeshBoundsMin(); + const float* bmax = geom->getNavMeshBoundsMax(); + rcCalcGridSize(bmin, bmax, cellSize, &gw, &gh); + const int ts = tileSize; + const int tw = (gw + ts-1) / ts; + const int th = (gh + ts-1) / ts; + + ImGui::Text("Tiles: %d x %d", tw, th); + ImGui::Text("Tile Sizes: %g x %g (%g)", tw* cellSize, th*cellSize, tileSize*cellSize); + + // Max tiles and max polys affect how the tile IDs are calculated. + // There are 28 bits available for identifying a tile and a polygon. + int tileBits = rcMin((int)ilog2(nextPow2(tw*th)), 16); + int polyBits = 28 - tileBits; + + maxTiles = 1 << tileBits; + maxPolysPerTile = 1 << polyBits; + + gridSize = tw*th; + + ImGui::Text("Max Tiles: %d", maxTiles); + ImGui::Text("Max Polys: %d", maxPolysPerTile); + } + else + { + maxTiles = 0; + maxPolysPerTile = 0; + gridSize = 1; + } + + return gridSize; +} + +Editor_StaticTileMeshCommon::Editor_StaticTileMeshCommon() + : m_triareas(nullptr) + , m_solid(nullptr) + , m_chf(nullptr) + , m_cset(nullptr) + , m_pmesh(nullptr) + , m_dmesh(nullptr) + , m_tileMeshDrawFlags(TM_DRAWFLAGS_INPUT_MESH|TM_DRAWFLAGS_NAVMESH) + , m_tileCol(duRGBA(0, 0, 0, 32)) + , m_totalBuildTimeMs(0.0f) + , m_drawActiveTile(false) + , m_keepInterResults(false) +{ + m_lastBuiltTileBmin[0] = 0.0f; + m_lastBuiltTileBmin[1] = 0.0f; + m_lastBuiltTileBmin[2] = 0.0f; + + m_lastBuiltTileBmax[0] = 0.0f; + m_lastBuiltTileBmax[1] = 0.0f; + m_lastBuiltTileBmax[2] = 0.0f; + + memset(&m_cfg, 0, sizeof(rcConfig)); +} + +void Editor_StaticTileMeshCommon::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; +} + +void Editor_StaticTileMeshCommon::renderTileMeshRenderOptions() +{ + ImGui::Text("TileMesh Render Options"); + + bool isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_INPUT_MESH; + + // This should always be available, since if we load a large mesh we want to + // be able to toggle this off to save on performance. The renderer has to be + // moved to its own thread to solve this issue. + if (ImGui::Checkbox("Input Mesh", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_INPUT_MESH); + + // Check which modes are valid. + //const bool hasNavMesh =m_navMesh != 0; + const bool hasChf = m_chf != 0; + const bool hasCset = m_cset != 0; + const bool hasSolid = m_solid != 0; + const bool hasDMesh = m_dmesh != 0; + + const bool intermediateDataUnavailable = !hasChf || !hasCset || !hasSolid || !hasDMesh; + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_NAVMESH; + //ImGui::BeginDisabled(!hasNavMesh); + + if (ImGui::Checkbox("NavMesh", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_NAVMESH); + + //ImGui::EndDisabled(); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_VOXELS; + ImGui::BeginDisabled(!hasSolid); + + if (ImGui::Checkbox("Voxels", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_VOXELS); + + ImGui::EndDisabled(); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_VOXELS_WALKABLE; + ImGui::BeginDisabled(!hasSolid); + + if (ImGui::Checkbox("Walkable Voxels", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_VOXELS_WALKABLE); + + ImGui::EndDisabled(); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_COMPACT; + ImGui::BeginDisabled(!hasChf); + + if (ImGui::Checkbox("Compact", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_COMPACT); + + ImGui::EndDisabled(); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_COMPACT_DISTANCE; + ImGui::BeginDisabled(!hasChf); + + if (ImGui::Checkbox("Compact Distance", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_COMPACT_DISTANCE); + + ImGui::EndDisabled(); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_COMPACT_REGIONS; + ImGui::BeginDisabled(!hasChf); + + if (ImGui::Checkbox("Compact Regions", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_COMPACT_REGIONS); + + ImGui::EndDisabled(); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_REGION_CONNECTIONS; + ImGui::BeginDisabled(!hasCset); + + if (ImGui::Checkbox("Region Connections", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_REGION_CONNECTIONS); + + ImGui::EndDisabled(); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_RAW_CONTOURS; + ImGui::BeginDisabled(!hasCset); + + if (ImGui::Checkbox("Raw Contours", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_RAW_CONTOURS); + + ImGui::EndDisabled(); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_CONTOURS; + ImGui::BeginDisabled(!hasCset); + + if (ImGui::Checkbox("Contours", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_CONTOURS); + + ImGui::EndDisabled(); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_POLYMESH; + ImGui::BeginDisabled(!hasDMesh); + + if (ImGui::Checkbox("Poly Mesh", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_POLYMESH); + + ImGui::EndDisabled(); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_POLYMESH_DETAIL; + ImGui::BeginDisabled(!hasDMesh); + + if (ImGui::Checkbox("Poly Mesh Detail", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_POLYMESH_DETAIL); + + ImGui::EndDisabled(); + + if (intermediateDataUnavailable) + { + ImGui::Separator(); + + ImGui::Text("Tick 'Keep Intermediate Results'"); + ImGui::Text("rebuild some tiles to see"); + ImGui::Text("more debug mode options."); + } +} + +void Editor_StaticTileMeshCommon::renderTileMeshData() +{ + if (!m_geom || !m_geom->getMesh()) + return; + + const float texScale = 1.0f / (m_cellSize * 10.0f); + + // Draw input mesh + if (getTileMeshDrawFlags() & TM_DRAWFLAGS_INPUT_MESH) + EditorCommon_DrawInputGeometry(&m_dd, m_geom, m_agentMaxSlope, texScale); + + glDepthMask(GL_FALSE); + + // Draw bounds + EditorCommon_DrawBoundingBox(&m_dd, m_geom); + + // Tiling grid. + EditorCommon_DrawTilingGrid(&m_dd, m_geom, m_tileSize, m_cellSize); + + if (m_drawActiveTile) + { + // Draw active tile + duDebugDrawBoxWire(&m_dd, m_lastBuiltTileBmin[0], m_lastBuiltTileBmin[1], m_lastBuiltTileBmin[2], + m_lastBuiltTileBmax[0], m_lastBuiltTileBmax[1], m_lastBuiltTileBmax[2], m_tileCol, 1.0f); + } + + if (m_navMesh && m_navQuery) + { + if (m_tileMeshDrawFlags & TM_DRAWFLAGS_NAVMESH) + { + duDebugDrawNavMeshWithClosedList(&m_dd, *m_navMesh, *m_navQuery, m_navMeshDrawFlags); + duDebugDrawNavMeshPolysWithFlags(&m_dd, *m_navMesh, EDITOR_POLYFLAGS_DISABLED, duRGBA(0, 0, 0, 128)); + } + } + + glDepthMask(GL_TRUE); + + if (m_chf) + { + if (getTileMeshDrawFlags() & TM_DRAWFLAGS_COMPACT) + duDebugDrawCompactHeightfieldSolid(&m_dd, *m_chf); + + if (getTileMeshDrawFlags() & TM_DRAWFLAGS_COMPACT_DISTANCE) + duDebugDrawCompactHeightfieldDistance(&m_dd, *m_chf); + if (getTileMeshDrawFlags() & TM_DRAWFLAGS_COMPACT_REGIONS) + duDebugDrawCompactHeightfieldRegions(&m_dd, *m_chf); + } + + if (m_solid) + { + if (getTileMeshDrawFlags() & TM_DRAWFLAGS_VOXELS) + { + glEnable(GL_FOG); + duDebugDrawHeightfieldSolid(&m_dd, *m_solid); + glDisable(GL_FOG); + } + if (getTileMeshDrawFlags() & TM_DRAWFLAGS_VOXELS_WALKABLE) + { + glEnable(GL_FOG); + duDebugDrawHeightfieldWalkable(&m_dd, *m_solid); + glDisable(GL_FOG); + } + } + + if (m_cset) + { + if (getTileMeshDrawFlags() & TM_DRAWFLAGS_RAW_CONTOURS) + { + glDepthMask(GL_FALSE); + duDebugDrawRawContours(&m_dd, *m_cset); + glDepthMask(GL_TRUE); + } + if (getTileMeshDrawFlags() & TM_DRAWFLAGS_CONTOURS) + { + glDepthMask(GL_FALSE); + duDebugDrawContours(&m_dd, *m_cset); + glDepthMask(GL_TRUE); + } + } + + if ((m_chf &&m_cset) && + (getTileMeshDrawFlags() & TM_DRAWFLAGS_REGION_CONNECTIONS)) + { + duDebugDrawCompactHeightfieldRegions(&m_dd, *m_chf); + + glDepthMask(GL_FALSE); + duDebugDrawRegionConnections(&m_dd, *m_cset); + glDepthMask(GL_TRUE); + } + + if (m_pmesh && (getTileMeshDrawFlags() & TM_DRAWFLAGS_POLYMESH)) + { + glDepthMask(GL_FALSE); + duDebugDrawPolyMesh(&m_dd, *m_pmesh); + glDepthMask(GL_TRUE); + } + + if (m_dmesh && (getTileMeshDrawFlags() & TM_DRAWFLAGS_POLYMESH_DETAIL)) + { + glDepthMask(GL_FALSE); + duDebugDrawPolyMeshDetail(&m_dd, *m_dmesh); + glDepthMask(GL_TRUE); + } + + // TODO: also add flags for this + m_geom->drawConvexVolumes(&m_dd); + m_geom->drawOffMeshConnections(&m_dd); + + if (m_tool) + m_tool->handleRender(); + + renderToolStates(); + + glDepthMask(GL_TRUE); +} + +void Editor_StaticTileMeshCommon::renderIntermediateTileMeshOptions() +{ + ImGui::Indent(); + ImGui::Indent(); + + if (ImGui::Button("Load", ImVec2(123, 0))) + { + dtFreeNavMesh(m_navMesh); + m_navMesh = Editor::loadAll(m_modelName.c_str()); + m_navQuery->init(m_navMesh, 2048); + + m_loadedNavMeshType = m_selectedNavMeshType; + initToolStates(this); + } + + if (ImGui::Button("Save", ImVec2(123, 0))) + { + Editor::saveAll(m_modelName.c_str(), m_navMesh); + } + + ImGui::Unindent(); + ImGui::Unindent(); + + ImGui::Text("Build Time: %.1fms", m_totalBuildTimeMs); + + if (m_navMesh) + { + const dtNavMeshParams& params = m_navMesh->m_params; + const float* origin = m_navMesh->m_orig; + + ImGui::Text("Mesh Origin: \n\tX: %g \n\tY: %g \n\tZ: %g", origin[0], origin[1], origin[2]); + ImGui::Text("Tile Dimensions: %g x %g", params.tileWidth, params.tileHeight); + ImGui::Text("Poly Group Count: %d", params.polyGroupCount); + ImGui::Text("Traversal Table Size: %d", params.traversalTableSize); + ImGui::Text("Traversal Table Count: %d", params.traversalTableCount); + ImGui::Text("Max Tiles: %d", params.maxTiles); + ImGui::Text("Max Polys: %d", params.maxPolys); + + ImGui::Separator(); + } + else + ImGui::Separator(); +} + +void drawTiles(duDebugDraw* dd, dtTileCache* tc) +{ + unsigned int fcol[6]; + float bmin[3], bmax[3]; + + for (int i = 0; i < tc->getTileCount(); ++i) + { + const dtCompressedTile* tile = tc->getTile(i); + if (!tile->header) continue; + + tc->calcTightTileBounds(tile->header, bmin, bmax); + + const unsigned int col = duIntToCol(i, 64); + duCalcBoxColors(fcol, col, col); + duDebugDrawBox(dd, bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2], fcol); + } + + for (int i = 0; i < tc->getTileCount(); ++i) + { + const dtCompressedTile* tile = tc->getTile(i); + if (!tile->header) continue; + + tc->calcTightTileBounds(tile->header, bmin, bmax); + + const unsigned int col = duIntToCol(i, 255); + const float pad = tc->getParams()->cs * 0.1f; + duDebugDrawBoxWire(dd, bmin[0] - pad, bmin[1] - pad, bmin[2] - pad, + bmax[0] + pad, bmax[1] + pad, bmax[2] + pad, col, 2.0f); + } +} + +void drawObstacles(duDebugDraw* dd, const dtTileCache* tc) +{ + // Draw obstacles + for (int i = 0; i < tc->getObstacleCount(); ++i) + { + const dtTileCacheObstacle* ob = tc->getObstacle(i); + if (ob->state == DT_OBSTACLE_EMPTY) continue; + float bmin[3], bmax[3]; + tc->getObstacleBounds(ob, bmin, bmax); + + unsigned int col = 0; + if (ob->state == DT_OBSTACLE_PROCESSING) + col = duRGBA(255, 255, 0, 128); + else if (ob->state == DT_OBSTACLE_PROCESSED) + col = duRGBA(255, 192, 0, 192); + else if (ob->state == DT_OBSTACLE_REMOVING) + col = duRGBA(220, 0, 0, 128); + + duDebugDrawCylinder(dd, bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2], col); + duDebugDrawCylinderWire(dd, bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2], duDarkenCol(col), 2); + } +} + +Editor_DynamicTileMeshCommon::Editor_DynamicTileMeshCommon() + : m_tileCache(nullptr) + , m_talloc(nullptr) + , m_tcomp(nullptr) + , m_tmproc(nullptr) + , m_cacheBuildTimeMs(0.0f) + , m_cacheCompressedSize(0) + , m_cacheRawSize(0) + , m_cacheLayerCount(0) + , m_cacheBuildMemUsage(0) + , m_tileMeshDrawFlags(TM_DRAWFLAGS_INPUT_MESH|TM_DRAWFLAGS_NAVMESH) + , m_keepInterResults(false) +{ +} + +void Editor_DynamicTileMeshCommon::renderTileMeshRenderOptions() +{ + ImGui::Text("TileMesh Render Options"); + + bool isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_INPUT_MESH; + + // This should always be available, since if we load a large mesh we want to + // be able to toggle this off to save on performance. The renderer has to be + // moved to its own thread to solve this issue. + if (ImGui::Checkbox("Input Mesh", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_INPUT_MESH); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_NAVMESH; + //ImGui::BeginDisabled(!hasNavMesh); + + if (ImGui::Checkbox("NavMesh", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_NAVMESH); + + //ImGui::EndDisabled(); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_TILE_CACHE_BOUNDS; + + ImGui::BeginDisabled(!m_tileCache); + + if (ImGui::Checkbox("Cache Bounds", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_TILE_CACHE_BOUNDS); + + isEnabled = getTileMeshDrawFlags() & TM_DRAWFLAGS_TILE_CACHE_OBSTACLES; + + if (ImGui::Checkbox("Temp Obstacles", &isEnabled)) + toggleTileMeshDrawFlag(TM_DRAWFLAGS_TILE_CACHE_OBSTACLES); + + ImGui::EndDisabled(); +} + +void Editor_DynamicTileMeshCommon::renderTileMeshData() +{ + if (!m_geom || !m_geom->getMesh()) + return; + + const float texScale = 1.0f / (m_cellSize * 10.0f); + const unsigned int drawFlags = getTileMeshDrawFlags(); + + // Draw input mesh + if (getTileMeshDrawFlags() & TM_DRAWFLAGS_INPUT_MESH) + EditorCommon_DrawInputGeometry(&m_dd, m_geom, m_agentMaxSlope, texScale); + + // Draw bounds + EditorCommon_DrawBoundingBox(&m_dd, m_geom); + + // Tiling grid. + EditorCommon_DrawTilingGrid(&m_dd, m_geom, m_tileSize, m_cellSize); + + if (m_tileCache && drawFlags & TM_DRAWFLAGS_TILE_CACHE_BOUNDS) + drawTiles(&m_dd, m_tileCache); + + if (m_tileCache && drawFlags & TM_DRAWFLAGS_TILE_CACHE_OBSTACLES) + drawObstacles(&m_dd, m_tileCache); + + const bool navMeshRenderingEnabled = (drawFlags & TM_DRAWFLAGS_NAVMESH) != 0; + + if (m_navMesh && m_navQuery) + { + if (drawFlags & TM_DRAWFLAGS_NAVMESH) + { + duDebugDrawNavMeshWithClosedList(&m_dd, *m_navMesh, *m_navQuery, m_navMeshDrawFlags); + duDebugDrawNavMeshPolysWithFlags(&m_dd, *m_navMesh, EDITOR_POLYFLAGS_DISABLED, duRGBA(0, 0, 0, 128)); + } + } + + // TODO: also add flags for this + m_geom->drawConvexVolumes(&m_dd); + m_geom->drawOffMeshConnections(&m_dd); + + if (m_tool) + m_tool->handleRender(); + + renderToolStates(); + + glDepthMask(GL_TRUE); +} diff --git a/src/naveditor/Editor_SoloMesh.cpp b/src/naveditor/Editor_SoloMesh.cpp index 19804ef3..b0c2af48 100644 --- a/src/naveditor/Editor_SoloMesh.cpp +++ b/src/naveditor/Editor_SoloMesh.cpp @@ -33,16 +33,7 @@ #include "NavEditor/Include/Editor_SoloMesh.h" -Editor_SoloMesh::Editor_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) +Editor_SoloMesh::Editor_SoloMesh() { setTool(new NavMeshTesterTool); } @@ -74,264 +65,67 @@ void Editor_SoloMesh::handleSettings() { Editor::handleCommonSettings(); - if (imguiCheck("Keep Itermediate Results", m_keepInterResults)) - m_keepInterResults = !m_keepInterResults; + ImGui::Checkbox("Keep Intermediate Results", &m_keepInterResults); + ImGui::Separator(); - imguiSeparator(); - - imguiIndent(); - imguiIndent(); - - if (imguiButton("Save")) - { - Editor::saveAll("solo_navmesh.bin", m_navMesh); - } - - if (imguiButton("Load")) - { - dtFreeNavMesh(m_navMesh); - m_navMesh = Editor::loadAll("solo_navmesh.bin"); - m_navQuery->init(m_navMesh, 2048); - } - - imguiUnindent(); - imguiUnindent(); - - char msg[64]; - snprintf(msg, 64, "Build Time: %.1fms", m_totalBuildTimeMs); - imguiLabel(msg); - - imguiSeparator(); + Editor_StaticTileMeshCommon::renderIntermediateTileMeshOptions(); } void Editor_SoloMesh::handleTools() { int type = !m_tool ? TOOL_NONE : m_tool->type(); + bool enabled = type == TOOL_NAVMESH_TESTER; - if (imguiCheck("Test Navmesh", type == TOOL_NAVMESH_TESTER)) + if (ImGui::Checkbox("Test NavMesh", &enabled)) { setTool(new NavMeshTesterTool); } - if (imguiCheck("Prune Navmesh", type == TOOL_NAVMESH_PRUNE)) + + enabled = type == TOOL_NAVMESH_PRUNE; + if (ImGui::Checkbox("Prune NavMesh", &enabled)) { setTool(new NavMeshPruneTool); } - if (imguiCheck("Create Off-Mesh Connections", type == TOOL_OFFMESH_CONNECTION)) + + enabled = type == TOOL_OFFMESH_CONNECTION; + if (ImGui::Checkbox("Create Off-Mesh Connections", &enabled)) { setTool(new OffMeshConnectionTool); } - if (imguiCheck("Create Convex Volumes", type == TOOL_CONVEX_VOLUME)) + + enabled = type == TOOL_CONVEX_VOLUME; + if (ImGui::Checkbox("Create Convex Volumes", &enabled)) { setTool(new ConvexVolumeTool); } - if (imguiCheck("Create Crowds", type == TOOL_CROWD)) + + enabled = type == TOOL_CROWD; + if (ImGui::Checkbox("Create Crowds", &enabled)) { setTool(new CrowdTool); } - imguiSeparatorLine(); + ImGui::Separator(); - imguiIndent(); + ImGui::Indent(); if (m_tool) m_tool->handleMenu(); - imguiUnindent(); + ImGui::Unindent(); } void Editor_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."); - } + Editor::renderNavMeshDebugMenu(); + ImGui::Separator(); + Editor_StaticTileMeshCommon::renderTileMeshRenderOptions(); } void Editor_SoloMesh::handleRender() { - if (!m_geom || !m_geom->getMesh()) - return; - - glEnable(GL_FOG); - glDepthMask(GL_TRUE); - - const float texScale = 1.0f / (m_cellSize * 10.0f); - - if (m_drawMode != DRAWMODE_NAVMESH_TRANS) - { - // Draw mesh - duDebugDrawTriMeshSlope(&m_dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(), - m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), - m_agentMaxSlope, texScale); - m_geom->drawOffMeshConnections(&m_dd); - } - - glDisable(GL_FOG); - glDepthMask(GL_FALSE); - - // Draw bounds - const float* bmin = m_geom->getNavMeshBoundsMin(); - const float* bmax = m_geom->getNavMeshBoundsMax(); - duDebugDrawBoxWire(&m_dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duRGBA(255,255,255,128), 1.0f); - m_dd.begin(DU_DRAW_POINTS, 5.0f); - m_dd.vertex(bmin[0],bmin[1],bmin[2],duRGBA(255,255,255,128)); - m_dd.end(); - - if (m_navMesh && m_navQuery && - (m_drawMode == DRAWMODE_NAVMESH || - m_drawMode == DRAWMODE_NAVMESH_TRANS || - m_drawMode == DRAWMODE_NAVMESH_BVTREE || - m_drawMode == DRAWMODE_NAVMESH_NODES || - 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, EDITOR_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); - duDebugDrawHeightfieldSolid(&m_dd, *m_solid); - glDisable(GL_FOG); - } - if (m_solid && m_drawMode == DRAWMODE_VOXELS_WALKABLE) - { - glEnable(GL_FOG); - duDebugDrawHeightfieldWalkable(&m_dd, *m_solid); - glDisable(GL_FOG); - } - if (m_cset && m_drawMode == DRAWMODE_RAW_CONTOURS) - { - glDepthMask(GL_FALSE); - duDebugDrawRawContours(&m_dd, *m_cset); - glDepthMask(GL_TRUE); - } - if (m_cset && m_drawMode == DRAWMODE_BOTH_CONTOURS) - { - glDepthMask(GL_FALSE); - duDebugDrawRawContours(&m_dd, *m_cset, 0.5f); - duDebugDrawContours(&m_dd, *m_cset); - glDepthMask(GL_TRUE); - } - if (m_cset && m_drawMode == DRAWMODE_CONTOURS) - { - glDepthMask(GL_FALSE); - duDebugDrawContours(&m_dd, *m_cset); - glDepthMask(GL_TRUE); - } - if (m_chf && m_cset && m_drawMode == DRAWMODE_REGION_CONNECTIONS) - { - duDebugDrawCompactHeightfieldRegions(&m_dd, *m_chf); - - glDepthMask(GL_FALSE); - duDebugDrawRegionConnections(&m_dd, *m_cset); - glDepthMask(GL_TRUE); - } - if (m_pmesh && m_drawMode == DRAWMODE_POLYMESH) - { - glDepthMask(GL_FALSE); - duDebugDrawPolyMesh(&m_dd, *m_pmesh); - glDepthMask(GL_TRUE); - } - if (m_dmesh && m_drawMode == DRAWMODE_POLYMESH_DETAIL) - { - glDepthMask(GL_FALSE); - duDebugDrawPolyMeshDetail(&m_dd, *m_dmesh); - glDepthMask(GL_TRUE); - } - - m_geom->drawConvexVolumes(&m_dd); - - if (m_tool) - m_tool->handleRender(); - renderToolStates(); - - glDepthMask(GL_TRUE); + Editor_StaticTileMeshCommon::renderTileMeshData(); } void Editor_SoloMesh::handleRenderOverlay(double* proj, double* model, int* view) @@ -360,7 +154,7 @@ void Editor_SoloMesh::handleMeshChanged(class InputGeom* geom) bool Editor_SoloMesh::handleBuild() { - if (!m_geom || !m_geom->getMesh()) + if (!m_geom || !m_geom->getMesh() || !m_geom->getChunkyMesh()) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Input mesh is not specified."); return false; @@ -389,8 +183,8 @@ bool Editor_SoloMesh::handleBuild() m_cfg.walkableRadius = (int)ceilf(m_agentRadius / m_cfg.cs); m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize); m_cfg.maxSimplificationError = m_edgeMaxError; - m_cfg.minRegionArea = (int)rcSqr(m_regionMinSize); // Note: area = size*size - m_cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize); // Note: area = size*size + m_cfg.minRegionArea = rcSqr(m_regionMinSize); // Note: area = size*size + m_cfg.mergeRegionArea = rcSqr(m_regionMergeSize); // Note: area = size*size m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly; m_cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist; m_cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError; @@ -460,7 +254,7 @@ bool Editor_SoloMesh::handleBuild() // Step 3. Filter walkables surfaces. // - // Once all geoemtry is rasterized, we do initial pass of filtering to + // Once all geometry is rasterized, we do initial pass of filtering to // remove unwanted overhangs caused by the conservative rasterization // as well as filter spans where the character cannot possibly stand. if (m_filterLowHangingObstacles) @@ -639,6 +433,9 @@ bool Editor_SoloMesh::handleBuild() // The GUI may allow more max points per polygon than Detour can handle. // Only build the detour navmesh if we do not exceed the limit. + + const int traversalTableCount = NavMesh_GetTraversalTableCountForNavMeshType(m_selectedNavMeshType); + if (m_cfg.maxVertsPerPoly <= DT_VERTS_PER_POLYGON) { unsigned char* navData = 0; @@ -706,17 +503,17 @@ bool Editor_SoloMesh::handleBuild() m_navMesh = dtAllocNavMesh(); if (!m_navMesh) { - dtFree(navData); + rdFree(navData); 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); + status = m_navMesh->init(navData, navDataSize, traversalTableCount, DT_TILE_FREE_DATA); if (dtStatusFailed(status)) { - dtFree(navData); + rdFree(navData); m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh"); return false; } @@ -728,6 +525,18 @@ bool Editor_SoloMesh::handleBuild() return false; } } + + dtDisjointSet data; + + if (!dtCreateDisjointPolyGroups(m_navMesh, data)) + { + m_ctx->log(RC_LOG_ERROR, "buildNavigation: Failed to build disjoint poly groups."); + } + + if (!dtCreateTraversalTableData(m_navMesh, data, traversalTableCount)) + { + m_ctx->log(RC_LOG_ERROR, "buildNavigation: Failed to build traversal table data."); + } m_ctx->stopTimer(RC_TIMER_TOTAL); diff --git a/src/naveditor/Editor_TempObstacles.cpp b/src/naveditor/Editor_TempObstacles.cpp index 4496b22b..f5aaec65 100644 --- a/src/naveditor/Editor_TempObstacles.cpp +++ b/src/naveditor/Editor_TempObstacles.cpp @@ -17,10 +17,9 @@ // #include "Pch.h" +#include "Shared/Include/SharedAlloc.h" +#include "Shared/Include/SharedAssert.h" #include "Recast/Include/Recast.h" -#include "Recast/Include/RecastAlloc.h" -#include "Recast/Include/RecastAssert.h" -#include "Detour/Include/DetourAssert.h" #include "Detour/Include/DetourNavMesh.h" #include "Detour/Include/DetourNavMeshBuilder.h" #include "Detour/Include/DetourCommon.h" @@ -125,13 +124,13 @@ struct LinearAllocator : public dtTileCacheAlloc ~LinearAllocator() { - dtFree(buffer); + rdFree(buffer); } void resize(const size_t cap) { - if (buffer) dtFree(buffer); - buffer = (unsigned char*)dtAlloc(cap, DT_ALLOC_PERM); + if (buffer) rdFree(buffer); + buffer = (unsigned char*)rdAlloc(cap, RD_ALLOC_PERM); capacity = cap; } @@ -241,7 +240,7 @@ struct RasterizationContext rcFreeCompactHeightfield(chf); for (int i = 0; i < MAX_LAYERS; ++i) { - dtFree(tiles[i].data); + rdFree(tiles[i].data); tiles[i].data = 0; } } @@ -279,16 +278,18 @@ int Editor_TempObstacles::rasterizeTileLayers( rcConfig tcfg; memcpy(&tcfg, &cfg, sizeof(tcfg)); - tcfg.bmin[0] = cfg.bmin[0] + tx*tcs; - tcfg.bmin[1] = cfg.bmin[1]; - tcfg.bmin[2] = cfg.bmin[2] + ty*tcs; - tcfg.bmax[0] = cfg.bmin[0] + (tx+1)*tcs; - tcfg.bmax[1] = cfg.bmax[1]; - tcfg.bmax[2] = cfg.bmin[2] + (ty+1)*tcs; + tcfg.bmin[0] = cfg.bmax[0] - (tx+1)*tcs; + tcfg.bmin[1] = cfg.bmin[1] + (ty)*tcs; + tcfg.bmin[2] = cfg.bmin[2]; + + tcfg.bmax[0] = cfg.bmax[0] - (tx)*tcs; + tcfg.bmax[1] = cfg.bmin[1] + (ty+1)*tcs; + tcfg.bmax[2] = cfg.bmax[2]; + tcfg.bmin[0] -= tcfg.borderSize*tcfg.cs; - tcfg.bmin[2] -= tcfg.borderSize*tcfg.cs; + tcfg.bmin[1] -= tcfg.borderSize*tcfg.cs; tcfg.bmax[0] += tcfg.borderSize*tcfg.cs; - tcfg.bmax[2] += tcfg.borderSize*tcfg.cs; + tcfg.bmax[1] += tcfg.borderSize*tcfg.cs; // Allocate voxel heightfield where we rasterize our input data to. rc.solid = rcAllocHeightfield(); @@ -315,11 +316,12 @@ int Editor_TempObstacles::rasterizeTileLayers( float tbmin[2], tbmax[2]; tbmin[0] = tcfg.bmin[0]; - tbmin[1] = tcfg.bmin[2]; + tbmin[1] = tcfg.bmin[1]; tbmax[0] = tcfg.bmax[0]; - tbmax[1] = tcfg.bmax[2]; - int cid[512];// TODO: Make grow when returning too many items. - const int ncid = rcGetChunksOverlappingRect(chunkyMesh, tbmin, tbmax, cid, 512); + tbmax[1] = tcfg.bmax[1]; +#if 0 + int cid[1024];// TODO: Make grow when returning too many items. + const int ncid = rcGetChunksOverlappingRect(chunkyMesh, tbmin, tbmax, cid, 1024); if (!ncid) { return 0; // empty @@ -338,6 +340,29 @@ int Editor_TempObstacles::rasterizeTileLayers( if (!rcRasterizeTriangles(m_ctx, verts, nverts, tris, rc.triareas, ntris, *rc.solid, tcfg.walkableClimb)) return 0; } +#else + int cid[1024];//NOTE: we don't grow it but we reuse it (e.g. like a yieldable function or iterator or sth) + int currentNode = 0; + + bool done = false; + do{ + int currentCount = 0; + done=rcGetChunksOverlappingRect(chunkyMesh, tbmin, tbmax, cid, 1024,currentCount,currentNode); + for (int i = 0; i < currentCount; ++i) + { + const rcChunkyTriMeshNode& node = chunkyMesh->nodes[cid[i]]; + const int* tris = &chunkyMesh->tris[node.i*3]; + const int ntris = node.n; + + memset(rc.triareas, 0, ntris * sizeof(unsigned char)); + rcMarkWalkableTriangles(m_ctx, tcfg.walkableSlopeAngle, + verts, nverts, tris, ntris, rc.triareas); + + if (!rcRasterizeTriangles(m_ctx, verts, nverts, tris, rc.triareas, ntris, *rc.solid, tcfg.walkableClimb)) + return 0; + } + } while (!done); +#endif // Once all geometry is rasterized, we do initial pass of filtering to // remove unwanted overhangs caused by the conservative rasterization @@ -349,7 +374,9 @@ int Editor_TempObstacles::rasterizeTileLayers( if (m_filterWalkableLowHeightSpans) rcFilterWalkableLowHeightSpans(m_ctx, tcfg.walkableHeight, *rc.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. rc.chf = rcAllocCompactHeightfield(); if (!rc.chf) { @@ -386,7 +413,7 @@ int Editor_TempObstacles::rasterizeTileLayers( } if (!rcBuildHeightfieldLayers(m_ctx, *rc.chf, tcfg.borderSize, tcfg.walkableHeight, *rc.lset)) { - m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build heighfield layers."); + m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build heightfield layers."); return 0; } @@ -426,7 +453,7 @@ int Editor_TempObstacles::rasterizeTileLayers( } } - // Transfer ownsership of tile data from build context to the caller. + // Transfer ownership of tile data from build context to the caller. int n = 0; for (int i = 0; i < rcMin(rc.ntiles, maxTiles); ++i) { @@ -438,39 +465,6 @@ int Editor_TempObstacles::rasterizeTileLayers( return n; } - -void drawTiles(duDebugDraw* dd, dtTileCache* tc) -{ - unsigned int fcol[6]; - float bmin[3], bmax[3]; - - for (int i = 0; i < tc->getTileCount(); ++i) - { - const dtCompressedTile* tile = tc->getTile(i); - if (!tile->header) continue; - - tc->calcTightTileBounds(tile->header, bmin, bmax); - - const unsigned int col = duIntToCol(i,64); - duCalcBoxColors(fcol, col, col); - duDebugDrawBox(dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], fcol); - } - - for (int i = 0; i < tc->getTileCount(); ++i) - { - const dtCompressedTile* tile = tc->getTile(i); - if (!tile->header) continue; - - tc->calcTightTileBounds(tile->header, bmin, bmax); - - const unsigned int col = duIntToCol(i,255); - const float pad = tc->getParams()->cs * 0.1f; - duDebugDrawBoxWire(dd, bmin[0]-pad,bmin[1]-pad,bmin[2]-pad, - bmax[0]+pad,bmax[1]+pad,bmax[2]+pad, col, 2.0f); - } - -} - enum DrawDetailType { DRAWDETAIL_AREAS, @@ -575,8 +569,7 @@ void drawDetailOverlay(const dtTileCache* tc, const int tx, const int ty, double return; const int rawSize = calcLayerBufferSize(tc->getParams()->width, tc->getParams()->height); - - char text[128]; + const int h = view[3]; for (int i = 0; i < ntiles; ++i) { @@ -584,19 +577,21 @@ void drawDetailOverlay(const dtTileCache* tc, const int tx, const int ty, double float pos[3]; pos[0] = (tile->header->bmin[0]+tile->header->bmax[0])/2.0f; - pos[1] = tile->header->bmin[1]; - pos[2] = (tile->header->bmin[2]+tile->header->bmax[2])/2.0f; + pos[1] = (tile->header->bmin[1]+tile->header->bmax[1])/2.0f; + pos[2] = (tile->header->bmin[2]); GLdouble x, y, z; if (gluProject((GLdouble)pos[0], (GLdouble)pos[1], (GLdouble)pos[2], model, proj, view, &x, &y, &z)) { - snprintf(text,128,"(%d,%d)/%d", tile->header->tx,tile->header->ty,tile->header->tlayer); - imguiDrawText((int)x, (int)y-25, IMGUI_ALIGN_CENTER, text, imguiRGBA(0,0,0,220)); - snprintf(text,128,"Compressed: %.1f kB", tile->dataSize/1024.0f); - imguiDrawText((int)x, (int)y-45, IMGUI_ALIGN_CENTER, text, imguiRGBA(0,0,0,128)); - snprintf(text,128,"Raw:%.1fkB", rawSize/1024.0f); - imguiDrawText((int)x, (int)y-65, IMGUI_ALIGN_CENTER, text, imguiRGBA(0,0,0,128)); + ImGui_RenderText(ImGuiTextAlign_e::kAlignCenter, ImVec2((float)x, h-((float)y-25.f)), ImVec4(0.0f, 0.0f, 0.0f, 0.8f), + "(%d,%d)/%d", tile->header->tx, tile->header->ty, tile->header->tlayer); + + ImGui_RenderText(ImGuiTextAlign_e::kAlignCenter, ImVec2((float)x, h-((float)y-45.f)), ImVec4(0.0f, 0.0f, 0.0f, 0.8f), + "Compressed: %.1f kB", tile->dataSize/1024.0f); + + ImGui_RenderText(ImGuiTextAlign_e::kAlignCenter, ImVec2((float)x, h-((float)y-65.f)), ImVec4(0.0f, 0.0f, 0.0f, 0.8f), + "Raw: %.1fkB", rawSize/1024.0f); } } } @@ -625,36 +620,13 @@ dtObstacleRef hitTestObstacle(const dtTileCache* tc, const float* sp, const floa } return tc->getObstacleRef(obmin); } - -void drawObstacles(duDebugDraw* dd, const dtTileCache* tc) -{ - // Draw obstacles - for (int i = 0; i < tc->getObstacleCount(); ++i) - { - const dtTileCacheObstacle* ob = tc->getObstacle(i); - if (ob->state == DT_OBSTACLE_EMPTY) continue; - float bmin[3], bmax[3]; - tc->getObstacleBounds(ob, bmin,bmax); - - unsigned int col = 0; - if (ob->state == DT_OBSTACLE_PROCESSING) - col = duRGBA(255,255,0,128); - else if (ob->state == DT_OBSTACLE_PROCESSED) - col = duRGBA(255,192,0,192); - else if (ob->state == DT_OBSTACLE_REMOVING) - col = duRGBA(220,0,0,128); - - duDebugDrawCylinder(dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], col); - duDebugDrawCylinderWire(dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duDarkenCol(col), 2); - } -} class TempObstacleHilightTool : public EditorTool { - Editor_TempObstacles* ; + Editor_TempObstacles* m_editor; float m_hitPos[3]; bool m_hitPosSet; int m_drawType; @@ -662,7 +634,7 @@ class TempObstacleHilightTool : public EditorTool public: TempObstacleHilightTool() : - (0), + m_editor(0), m_hitPosSet(false), m_drawType(DRAWDETAIL_AREAS) { @@ -677,23 +649,31 @@ public: virtual void init(Editor* editor) { - = (Editor_TempObstacles*)editor; + m_editor = (Editor_TempObstacles*)editor; } virtual void reset() {} virtual void handleMenu() { - imguiLabel("Highlight Tile Cache"); - imguiValue("Click LMB to highlight a tile."); - imguiSeparator(); - if (imguiCheck("Draw Areas", m_drawType == DRAWDETAIL_AREAS)) + ImGui::Text("Highlight Tile Cache"); + ImGui::Text("Click LMB to highlight a tile."); + ImGui::Separator(); + + bool enabled = m_drawType == DRAWDETAIL_AREAS; // todo(amos): use flags instead? + if (ImGui::Checkbox("Draw Areas", &enabled)) m_drawType = DRAWDETAIL_AREAS; - if (imguiCheck("Draw Regions", m_drawType == DRAWDETAIL_REGIONS)) + + enabled = m_drawType == DRAWDETAIL_REGIONS; + if (ImGui::Checkbox("Draw Regions", &enabled)) m_drawType = DRAWDETAIL_REGIONS; - if (imguiCheck("Draw Contours", m_drawType == DRAWDETAIL_CONTOURS)) + + enabled = m_drawType == DRAWDETAIL_CONTOURS; + if (ImGui::Checkbox("Draw Contours", &enabled)) m_drawType = DRAWDETAIL_CONTOURS; - if (imguiCheck("Draw Mesh", m_drawType == DRAWDETAIL_MESH)) + + enabled = m_drawType == DRAWDETAIL_MESH; + if (ImGui::Checkbox("Draw Mesh", &enabled)) m_drawType = DRAWDETAIL_MESH; } @@ -711,9 +691,9 @@ public: virtual void handleRender() { - if (m_hitPosSet && ) + if (m_hitPosSet && m_editor) { - const float s = ->getAgentRadius(); + const float s = m_editor->getAgentRadius(); glColor4ub(0,0,0,128); glLineWidth(2.0f); glBegin(GL_LINES); @@ -727,8 +707,8 @@ public: glLineWidth(1.0f); int tx=0, ty=0; - ->getTilePos(m_hitPos, tx, ty); - ->renderCachedTile(tx,ty,m_drawType); + m_editor->getTilePos(m_hitPos, tx, ty); + m_editor->renderCachedTile(tx,ty,m_drawType); } } @@ -736,11 +716,11 @@ public: { if (m_hitPosSet) { - if () + if (m_editor) { int tx=0, ty=0; - ->getTilePos(m_hitPos, tx, ty); - ->renderCachedTileOverlay(tx,ty,proj,model,view); + m_editor->getTilePos(m_hitPos, tx, ty); + m_editor->renderCachedTileOverlay(tx,ty,proj,model,view); } } } @@ -749,11 +729,11 @@ public: class TempObstacleCreateTool : public EditorTool { - Editor_TempObstacles* ; + Editor_TempObstacles* m_editor; public: - TempObstacleCreateTool() : (0) + TempObstacleCreateTool() : m_editor(0) { } @@ -765,32 +745,32 @@ public: virtual void init(Editor* editor) { - = (Editor_TempObstacles*)editor; + m_editor = (Editor_TempObstacles*)editor; } virtual void reset() {} virtual void handleMenu() { - imguiLabel("Create Temp Obstacles"); + ImGui::Text("Create Temp Obstacles"); - if (imguiButton("Remove All")) - ->clearAllTempObstacles(); + if (ImGui::Button("Remove All")) + m_editor->clearAllTempObstacles(); - imguiSeparator(); + ImGui::Separator(); - imguiValue("Click LMB to create an obstacle."); - imguiValue("Shift+LMB to remove an obstacle."); + ImGui::Text("Click LMB to create an obstacle."); + ImGui::Text("Shift+LMB to remove an obstacle."); } virtual void handleClick(const float* s, const float* p, bool shift) { - if () + if (m_editor) { if (shift) - ->removeTempObstacle(s,p); + m_editor->removeTempObstacle(s,p); else - ->addTempObstacle(p); + m_editor->addTempObstacle(p); } } @@ -805,18 +785,9 @@ public: -Editor_TempObstacles::Editor_TempObstacles() : - m_keepInterResults(false), - m_tileCache(0), - m_cacheBuildTimeMs(0), - m_cacheCompressedSize(0), - m_cacheRawSize(0), - m_cacheLayerCount(0), - m_cacheBuildMemUsage(0), - m_drawMode(DRAWMODE_NAVMESH), - m_maxTiles(0), - m_maxPolysPerTile(0), - m_tileSize(48) +Editor_TempObstacles::Editor_TempObstacles() + : m_maxTiles(0) + , m_maxPolysPerTile(0) { resetCommonSettings(); @@ -838,246 +809,125 @@ void Editor_TempObstacles::handleSettings() { Editor::handleCommonSettings(); - if (imguiCheck("Keep Itermediate Results", m_keepInterResults)) - m_keepInterResults = !m_keepInterResults; + ImGui::Text("Tiling"); + ImGui::SliderInt("Tile Size", &m_tileSize, 8, 1024); - imguiLabel("Tiling"); - imguiSlider("TileSize", &m_tileSize, 16.0f, 128.0f, 8.0f); - - int gridSize = 1; - if (m_geom) - { - const float* bmin = m_geom->getNavMeshBoundsMin(); - const float* bmax = m_geom->getNavMeshBoundsMax(); - char text[64]; - int gw = 0, gh = 0; - rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); - const int ts = (int)m_tileSize; - const int tw = (gw + ts-1) / ts; - const int th = (gh + ts-1) / ts; - snprintf(text, 64, "Tiles %d x %d", tw, th); - imguiValue(text); - // Max tiles and max polys affect how the tile IDs are caculated. - // There are 22 bits available for identifying a tile and a polygon. - int tileBits = rcMin((int)dtIlog2(dtNextPow2(tw*th*EXPECTED_LAYERS_PER_TILE)), 14); - if (tileBits > 14) tileBits = 14; - int polyBits = 22 - tileBits; - m_maxTiles = 1 << tileBits; - m_maxPolysPerTile = 1 << polyBits; - snprintf(text, 64, "Max Tiles %d", m_maxTiles); - imguiValue(text); - snprintf(text, 64, "Max Polys %d", m_maxPolysPerTile); - imguiValue(text); - gridSize = tw*th; - } - else - { - m_maxTiles = 0; - m_maxPolysPerTile = 0; - } - - imguiSeparator(); - - imguiLabel("Tile Cache"); - char msg[64]; + ImGui::Checkbox("Keep Intermediate Results", &m_keepInterResults); + const int gridSize = EditorCommon_SetAndRenderTileProperties(m_geom, m_tileSize, m_cellSize, m_maxTiles, m_maxPolysPerTile); + ImGui::Separator(); + + ImGui::Text("Tile Cache"); const float compressionRatio = (float)m_cacheCompressedSize / (float)(m_cacheRawSize+1); - snprintf(msg, 64, "Layers %d", m_cacheLayerCount); - imguiValue(msg); - snprintf(msg, 64, "Layers (per tile) %.1f", (float)m_cacheLayerCount/(float)gridSize); - imguiValue(msg); - - snprintf(msg, 64, "Memory %.1f kB / %.1f kB (%.1f%%)", m_cacheCompressedSize/1024.0f, m_cacheRawSize/1024.0f, compressionRatio*100.0f); - imguiValue(msg); - snprintf(msg, 64, "Navmesh Build Time %.1f ms", m_cacheBuildTimeMs); - imguiValue(msg); - snprintf(msg, 64, "Build Peak Mem Usage %.1f kB", m_cacheBuildMemUsage/1024.0f); - imguiValue(msg); + ImGui::Text("Layers: %d", m_cacheLayerCount); + ImGui::Text("Layers (per tile): %.1f", (float)m_cacheLayerCount/(float)gridSize); + ImGui::Text("Memory: %.1f kB / %.1f kB (%.1f%%)", m_cacheCompressedSize/1024.0f, m_cacheRawSize/1024.0f, compressionRatio*100.0f); + ImGui::Text("Build Peak Mem Usage: %.1f kB", m_cacheBuildMemUsage/1024.0f); + ImGui::Text("Build Time: %.1fms", m_cacheBuildTimeMs); - imguiSeparator(); + ImGui::Separator(); - imguiIndent(); - imguiIndent(); + ImGui::Indent(); + ImGui::Indent(); - if (imguiButton("Save")) - { - saveAll("all_tiles_tilecache.bin"); - } - - if (imguiButton("Load")) + if (ImGui::Button("Load", ImVec2(123, 0))) { dtFreeNavMesh(m_navMesh); - dtFreeTileCache(m_tileCache); - loadAll("all_tiles_tilecache.bin"); + m_navMesh = Editor::loadAll(m_modelName.c_str()); m_navQuery->init(m_navMesh, 2048); + + m_loadedNavMeshType = m_selectedNavMeshType; + initToolStates(this); } - imguiUnindent(); - imguiUnindent(); - - imguiSeparator(); + if (ImGui::Button("Save", ImVec2(123, 0))) + { + Editor::saveAll(m_modelName.c_str(), m_navMesh); + } + + ImGui::Unindent(); + ImGui::Unindent(); + + if (m_navMesh) + { + const dtNavMeshParams& params = m_navMesh->m_params; + const float* origin = m_navMesh->m_orig; + + ImGui::Text("Mesh Origin: \n\tX: %g \n\tY: %g \n\tZ: %g", origin[0], origin[1], origin[2]); + ImGui::Text("Tile Dimensions: %g x %g", params.tileWidth, params.tileHeight); + ImGui::Text("Poly Group Count: %d", params.polyGroupCount); + ImGui::Text("Traversal Table Size: %d", params.traversalTableSize); + ImGui::Text("Traversal Table Count: %d", params.traversalTableCount); + ImGui::Text("Max Tiles: %d", params.maxTiles); + ImGui::Text("Max Polys: %d", params.maxPolys); + + ImGui::Separator(); + } + else + ImGui::Separator(); } void Editor_TempObstacles::handleTools() { int type = !m_tool ? TOOL_NONE : m_tool->type(); + bool enabled = type == TOOL_NAVMESH_TESTER; - if (imguiCheck("Test Navmesh", type == TOOL_NAVMESH_TESTER)) + if (ImGui::Checkbox("Test NavMesh", &enabled)) { setTool(new NavMeshTesterTool); } - if (imguiCheck("Highlight Tile Cache", type == TOOL_TILE_HIGHLIGHT)) + + enabled = type == TOOL_TILE_HIGHLIGHT; + if (ImGui::Checkbox("Highlight Tile Cache", &enabled)) { setTool(new TempObstacleHilightTool); } - if (imguiCheck("Create Temp Obstacles", type == TOOL_TEMP_OBSTACLE)) + + enabled = type == TOOL_TEMP_OBSTACLE; + if (ImGui::Checkbox("Create Temp Obstacles", &enabled)) { setTool(new TempObstacleCreateTool); } - if (imguiCheck("Create Off-Mesh Links", type == TOOL_OFFMESH_CONNECTION)) + + enabled = type == TOOL_OFFMESH_CONNECTION; + if (ImGui::Checkbox("Create Off-Mesh Links", &enabled)) { setTool(new OffMeshConnectionTool); } - if (imguiCheck("Create Convex Volumes", type == TOOL_CONVEX_VOLUME)) + + enabled = type == TOOL_CONVEX_VOLUME; + if (ImGui::Checkbox("Create Convex Volumes", &enabled)) { setTool(new ConvexVolumeTool); } - if (imguiCheck("Create Crowds", type == TOOL_CROWD)) + + enabled = type == TOOL_CROWD; + if (ImGui::Checkbox("Create Crowds", &enabled)) { setTool(new CrowdTool); } - imguiSeparatorLine(); + ImGui::Separator(); - imguiIndent(); + ImGui::Indent(); if (m_tool) m_tool->handleMenu(); - imguiUnindent(); + ImGui::Unindent(); } void Editor_TempObstacles::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_PORTALS] = m_navMesh != 0; - valid[DRAWMODE_NAVMESH_INVIS] = m_navMesh != 0; - valid[DRAWMODE_MESH] = true; - valid[DRAWMODE_CACHE_BOUNDS] = true; - } - - 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("Navmesh Portals", m_drawMode == DRAWMODE_NAVMESH_PORTALS, valid[DRAWMODE_NAVMESH_PORTALS])) - m_drawMode = DRAWMODE_NAVMESH_PORTALS; - if (imguiCheck("Cache Bounds", m_drawMode == DRAWMODE_CACHE_BOUNDS, valid[DRAWMODE_CACHE_BOUNDS])) - m_drawMode = DRAWMODE_CACHE_BOUNDS; - - if (unavail) - { - imguiValue("Tick 'Keep Itermediate Results'"); - imguiValue("rebuild some tiles to see"); - imguiValue("more debug mode options."); - } + Editor::renderNavMeshDebugMenu(); + ImGui::Separator(); + Editor_DynamicTileMeshCommon::renderTileMeshRenderOptions(); } void Editor_TempObstacles::handleRender() { - if (!m_geom || !m_geom->getMesh()) - return; - - const float texScale = 1.0f / (m_cellSize * 10.0f); - - // Draw mesh - if (m_drawMode != DRAWMODE_NAVMESH_TRANS) - { - // Draw mesh - duDebugDrawTriMeshSlope(&m_dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(), - m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), - m_agentMaxSlope, texScale); - m_geom->drawOffMeshConnections(&m_dd); - } - - if (m_tileCache && m_drawMode == DRAWMODE_CACHE_BOUNDS) - drawTiles(&m_dd, m_tileCache); - - if (m_tileCache) - drawObstacles(&m_dd, m_tileCache); - - - glDepthMask(GL_FALSE); - - // Draw bounds - const float* bmin = m_geom->getNavMeshBoundsMin(); - const float* bmax = m_geom->getNavMeshBoundsMax(); - duDebugDrawBoxWire(&m_dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duRGBA(255,255,255,128), 1.0f); - - // Tiling grid. - int gw = 0, gh = 0; - rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); - const int tw = (gw + (int)m_tileSize-1) / (int)m_tileSize; - const int th = (gh + (int)m_tileSize-1) / (int)m_tileSize; - const float s = m_tileSize*m_cellSize; - duDebugDrawGridXZ(&m_dd, bmin[0],bmin[1],bmin[2], tw,th, s, duRGBA(0,0,0,64), 1.0f); - - if (m_navMesh && m_navQuery && - (m_drawMode == DRAWMODE_NAVMESH || - m_drawMode == DRAWMODE_NAVMESH_TRANS || - m_drawMode == DRAWMODE_NAVMESH_BVTREE || - m_drawMode == DRAWMODE_NAVMESH_NODES || - m_drawMode == DRAWMODE_NAVMESH_PORTALS || - m_drawMode == DRAWMODE_NAVMESH_INVIS)) - { - if (m_drawMode != DRAWMODE_NAVMESH_INVIS) - duDebugDrawNavMeshWithClosedList(&m_dd, *m_navMesh, *m_navQuery, m_navMeshDrawFlags/*|DU_DRAWNAVMESH_COLOR_TILES*/); - if (m_drawMode == DRAWMODE_NAVMESH_BVTREE) - duDebugDrawNavMeshBVTree(&m_dd, *m_navMesh); - if (m_drawMode == DRAWMODE_NAVMESH_PORTALS) - duDebugDrawNavMeshPortals(&m_dd, *m_navMesh); - if (m_drawMode == DRAWMODE_NAVMESH_NODES) - duDebugDrawNavMeshNodes(&m_dd, *m_navQuery); - duDebugDrawNavMeshPolysWithFlags(&m_dd, *m_navMesh, EDITOR_POLYFLAGS_DISABLED, duRGBA(0,0,0,128)); - } - - - glDepthMask(GL_TRUE); - - m_geom->drawConvexVolumes(&m_dd); - - if (m_tool) - m_tool->handleRender(); - renderToolStates(); - - glDepthMask(GL_TRUE); + Editor_DynamicTileMeshCommon::renderTileMeshData(); } void Editor_TempObstacles::renderCachedTile(const int tx, const int ty, const int type) @@ -1148,7 +998,7 @@ void Editor_TempObstacles::addTempObstacle(const float* pos) return; float p[3]; dtVcopy(p, pos); - p[1] -= 0.5f; + p[2] -= 0.5f; m_tileCache->addObstacle(p, 1.0f, 2.0f, 0); } @@ -1204,10 +1054,10 @@ bool Editor_TempObstacles::handleBuild() cfg.walkableRadius = (int)ceilf(m_agentRadius / cfg.cs); cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize); cfg.maxSimplificationError = m_edgeMaxError; - cfg.minRegionArea = (int)rcSqr(m_regionMinSize); // Note: area = size*size - cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize); // Note: area = size*size - cfg.maxVertsPerPoly = (int)m_vertsPerPoly; - cfg.tileSize = (int)m_tileSize; + cfg.minRegionArea = rcSqr(m_regionMinSize); // Note: area = size*size + cfg.mergeRegionArea = rcSqr(m_regionMergeSize); // Note: area = size*size + cfg.maxVertsPerPoly = m_vertsPerPoly; + cfg.tileSize = m_tileSize; cfg.borderSize = cfg.walkableRadius + 3; // Reserve enough padding. cfg.width = cfg.tileSize + cfg.borderSize*2; cfg.height = cfg.tileSize + cfg.borderSize*2; @@ -1222,8 +1072,8 @@ bool Editor_TempObstacles::handleBuild() rcVcopy(tcparams.orig, bmin); tcparams.cs = m_cellSize; tcparams.ch = m_cellHeight; - tcparams.width = (int)m_tileSize; - tcparams.height = (int)m_tileSize; + tcparams.width = m_tileSize; + tcparams.height = m_tileSize; tcparams.walkableHeight = m_agentHeight; tcparams.walkableRadius = m_agentRadius; tcparams.walkableClimb = m_agentMaxClimb; @@ -1266,7 +1116,7 @@ bool Editor_TempObstacles::handleBuild() status = m_navMesh->init(¶ms); if (dtStatusFailed(status)) { - m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init navmesh."); + m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init Detour navmesh."); return false; } @@ -1300,7 +1150,7 @@ bool Editor_TempObstacles::handleBuild() status = m_tileCache->addTile(tile->data, tile->dataSize, DT_COMPRESSEDTILE_FREE_DATA, 0); if (dtStatusFailed(status)) { - dtFree(tile->data); + rdFree(tile->data); tile->data = 0; continue; } @@ -1361,7 +1211,7 @@ void Editor_TempObstacles::getTilePos(const float* pos, int& tx, int& ty) const float ts = m_tileSize*m_cellSize; tx = (int)((pos[0] - bmin[0]) / ts); - ty = (int)((pos[2] - bmin[2]) / ts); + ty = (int)((pos[1] - bmin[1]) / ts); } static const int TILECACHESET_MAGIC = 'T'<<24 | 'S'<<16 | 'E'<<8 | 'T'; //'TSET'; @@ -1487,14 +1337,14 @@ void Editor_TempObstacles::loadAll(const char* path) if (!tileHeader.tileRef || !tileHeader.dataSize) break; - unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM); + unsigned char* data = (unsigned char*)rdAlloc(tileHeader.dataSize, RD_ALLOC_PERM); if (!data) break; memset(data, 0, tileHeader.dataSize); size_t tileDataReadReturnCode = fread(data, tileHeader.dataSize, 1, fp); if( tileDataReadReturnCode != 1) { // Error or early EOF - dtFree(data); + rdFree(data); fclose(fp); return; } @@ -1503,7 +1353,7 @@ void Editor_TempObstacles::loadAll(const char* path) dtStatus addTileStatus = m_tileCache->addTile(data, tileHeader.dataSize, DT_COMPRESSEDTILE_FREE_DATA, &tile); if (dtStatusFailed(addTileStatus)) { - dtFree(data); + rdFree(data); } if (tile) diff --git a/src/naveditor/Editor_TileMesh.cpp b/src/naveditor/Editor_TileMesh.cpp index 05d80db4..e9a4cafd 100644 --- a/src/naveditor/Editor_TileMesh.cpp +++ b/src/naveditor/Editor_TileMesh.cpp @@ -37,30 +37,6 @@ #include "game/server/ai_hull.h" -inline unsigned int nextPow2(unsigned int v) -{ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; -} - -inline unsigned int ilog2(unsigned int v) -{ - unsigned int r; - unsigned int shift; - r = (v > 0xffff) << 4; v >>= r; - shift = (v > 0xff) << 3; v >>= shift; r |= shift; - shift = (v > 0xf) << 2; v >>= shift; r |= shift; - shift = (v > 0x3) << 1; v >>= shift; r |= shift; - r |= (v >> 1); - return r; -} - class NavMeshTileTool : public EditorTool { Editor_TileMesh* m_editor; @@ -165,20 +141,10 @@ public: Editor_TileMesh::Editor_TileMesh() : - m_keepInterResults(false), m_buildAll(true), - m_totalBuildTimeMs(0), - m_triareas(0), - m_solid(0), - m_chf(0), - m_cset(0), - m_pmesh(0), - m_dmesh(0), - m_tileMeshDrawFlags(TM_DRAWFLAGS_INPUT_MESH|TM_DRAWFLAGS_NAVMESH), m_maxTiles(0), m_maxPolysPerTile(0), m_tileSize(32), - m_tileCol(duRGBA(0,0,0,32)), m_tileBuildTime(0), m_tileMemUsage(0), m_tileTriCount(0) @@ -190,6 +156,8 @@ Editor_TileMesh::Editor_TileMesh() : memset(m_lastBuiltTileBmax, 0, sizeof(m_lastBuiltTileBmax)); setTool(new NavMeshTileTool); + + m_drawActiveTile = true; } Editor_TileMesh::~Editor_TileMesh() @@ -199,56 +167,8 @@ Editor_TileMesh::~Editor_TileMesh() m_navMesh = 0; } -void Editor_TileMesh::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; -} -const hulldef hulls[NAVMESH_COUNT] = { - { g_navMeshNames[NAVMESH_SMALL] , NAI_Hull::Width(HULL_HUMAN) , NAI_Hull::Height(HULL_HUMAN) * NAI_Hull::Scale(HULL_HUMAN) , 45, 32 }, - { g_navMeshNames[NAVMESH_MED_SHORT] , NAI_Hull::Width(HULL_PROWLER), NAI_Hull::Height(HULL_PROWLER) * NAI_Hull::Scale(HULL_PROWLER), 50, 32 }, - { g_navMeshNames[NAVMESH_MEDIUM] , NAI_Hull::Width(HULL_MEDIUM) , NAI_Hull::Height(HULL_MEDIUM) * NAI_Hull::Scale(HULL_MEDIUM) , 55, 32 }, - { g_navMeshNames[NAVMESH_LARGE] , NAI_Hull::Width(HULL_TITAN) , NAI_Hull::Height(HULL_TITAN) * NAI_Hull::Scale(HULL_TITAN) , 60, 64 }, - { g_navMeshNames[NAVMESH_EXTRA_LARGE], NAI_Hull::Width(HULL_GOLIATH), NAI_Hull::Height(HULL_GOLIATH) * NAI_Hull::Scale(HULL_GOLIATH), 65, 64 }, -}; - -void Editor_TileMesh::selectNavMeshType(const NavMeshType_e navMeshType) -{ - const hulldef& h = hulls[navMeshType]; - - m_agentRadius = h.radius; - m_agentMaxClimb = h.climbHeight; - m_agentHeight = h.height; - m_navmeshName = h.name; - m_tileSize = h.tileSize; - - m_selectedNavMeshType = navMeshType; -} - void Editor_TileMesh::handleSettings() { - ImGui::Text("NavMesh Type"); - for (int i = 0; i < NAVMESH_COUNT; i++) - { - const NavMeshType_e navMeshType = NavMeshType_e(i); - - if (ImGui::Button(NavMesh_GetNameForType(navMeshType), ImVec2(120, 0))) - { - selectNavMeshType(navMeshType); - } - } - - ImGui::Separator(); Editor::handleCommonSettings(); ImGui::Text("Tiling"); @@ -257,80 +177,10 @@ void Editor_TileMesh::handleSettings() ImGui::Checkbox("Build All Tiles", &m_buildAll); ImGui::Checkbox("Keep Intermediate Results", &m_keepInterResults); - if (m_geom) - { - char text[128]; - int gw = 0, gh = 0; - const float* bmin = m_geom->getNavMeshBoundsMin(); - const float* bmax = m_geom->getNavMeshBoundsMax(); - rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); - const int ts = m_tileSize; - const int tw = (gw + ts-1) / ts; - const int th = (gh + ts-1) / ts; - snprintf(text, sizeof(text), "Tiles: %d x %d", tw, th); - ImGui::Text(text); - snprintf(text, sizeof(text), "Tile Sizes: %g x %g (%g)", tw*m_cellSize, th*m_cellSize, m_tileSize*m_cellSize); - ImGui::Text(text); - // Max tiles and max polys affect how the tile IDs are calculated. - // There are 28 bits available for identifying a tile and a polygon. - int tileBits = rcMin((int)ilog2(nextPow2(tw*th)), 16); - int polyBits = 28 - tileBits; - m_maxTiles = 1 << tileBits; - m_maxPolysPerTile = 1 << polyBits; - snprintf(text, sizeof(text), "Max Tiles: %d", m_maxTiles); - ImGui::Text(text); - snprintf(text, sizeof(text), "Max Polys: %d", m_maxPolysPerTile); - ImGui::Text(text); - } - else - { - m_maxTiles = 0; - m_maxPolysPerTile = 0; - } + EditorCommon_SetAndRenderTileProperties(m_geom, m_tileSize, m_cellSize, m_maxTiles, m_maxPolysPerTile); ImGui::Separator(); - - ImGui::Indent(); - ImGui::Indent(); - - - if (ImGui::Button("Load", ImVec2(123, 0))) - { - dtFreeNavMesh(m_navMesh); - m_navMesh = Editor::loadAll(m_modelName.c_str()); - m_navQuery->init(m_navMesh, 2048); - - m_loadedNavMeshType = m_selectedNavMeshType; - initToolStates(this); - } - - if (ImGui::Button("Save", ImVec2(123, 0))) - { - Editor::saveAll(m_modelName.c_str(), m_navMesh); - } - - ImGui::Unindent(); - ImGui::Unindent(); - - ImGui::Text("Build Time: %.1fms", m_totalBuildTimeMs); - - if (m_navMesh) - { - const dtNavMeshParams& params = m_navMesh->m_params; - const float* origin = m_navMesh->m_orig; - - ImGui::Text("Mesh Origin: \n\tX: %g \n\tY: %g \n\tZ: %g", origin[0], origin[1], origin[2]); - ImGui::Text("Tile Dimensions: %g x %g", params.tileWidth, params.tileHeight); - ImGui::Text("Poly Group Count: %d", params.polyGroupCount); - ImGui::Text("Traversal Table Size: %d", params.traversalTableSize); - ImGui::Text("Traversal Table Count: %d", params.traversalTableCount); - ImGui::Text("Max Tiles: %d", params.maxTiles); - ImGui::Text("Max Polys: %d", params.maxPolys); - - ImGui::Separator(); - } - else - ImGui::Separator(); + Editor_StaticTileMeshCommon::renderIntermediateTileMeshOptions(); } void Editor_TileMesh::handleTools() @@ -385,313 +235,14 @@ void Editor_TileMesh::handleTools() void Editor_TileMesh::handleDebugMode() { - ImGui::Text("NavMesh Render Options"); - - bool isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_OFFMESHCONS); - - if (ImGui::Checkbox("Off-Mesh Connections", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_OFFMESHCONS); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_NODES); - - if (ImGui::Checkbox("Query Nodes", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_NODES); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_BVTREE); - - if (ImGui::Checkbox("BVTree", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_BVTREE); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_PORTALS); - - if (ImGui::Checkbox("Portals", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_PORTALS); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_CLOSEDLIST); - - if (ImGui::Checkbox("Closed List", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_CLOSEDLIST); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_COLOR_TILES); - - if (ImGui::Checkbox("Tile ID Colors", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_COLOR_TILES); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_VERTS); - - if (ImGui::Checkbox("Vertex Points", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_VERTS); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_INNERBOUND); - - if (ImGui::Checkbox("Inner Poly Boundaries", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_INNERBOUND); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_OUTERBOUND); - - if (ImGui::Checkbox("Outer Poly Boundaries", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_OUTERBOUND); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_POLYCENTERS); - - if (ImGui::Checkbox("Poly Centers", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_POLYCENTERS); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_POLYGROUPS); - - if (ImGui::Checkbox("Poly Group Colors", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_POLYGROUPS); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_DEPTH_MASK); - - if (ImGui::Checkbox("Depth Mask", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_DEPTH_MASK); - - isEnabled = (getNavMeshDrawFlags() & DU_DRAWNAVMESH_ALPHA); - - if (ImGui::Checkbox("Transparency", &isEnabled)) - toggleNavMeshDrawFlag(DU_DRAWNAVMESH_ALPHA); - + Editor::renderNavMeshDebugMenu(); ImGui::Separator(); - ImGui::Text("TileMesh Render Options"); - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_INPUT_MESH; - - // This should always be available, since if we load a large mesh we want to - // be able to toggle this off to save on performance. The renderer has to be - // moved to its own thread to solve this issue. - if (ImGui::Checkbox("Input Mesh", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_INPUT_MESH); - - // Check which modes are valid. - const bool hasNavMesh = m_navMesh != 0; - const bool hasChf = m_chf != 0; - const bool hasCset = m_cset != 0; - const bool hasSolid = m_solid != 0; - const bool hasDMesh = m_dmesh != 0; - - const bool intermediateDataUnavailable = !hasChf||!hasCset||!hasSolid||!hasDMesh; - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_NAVMESH; - ImGui::BeginDisabled(!hasNavMesh); - - if (ImGui::Checkbox("NavMesh", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_NAVMESH); - - ImGui::EndDisabled(); - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_VOXELS; - ImGui::BeginDisabled(!hasSolid); - - if (ImGui::Checkbox("Voxels", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_VOXELS); - - ImGui::EndDisabled(); - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_VOXELS_WALKABLE; - ImGui::BeginDisabled(!hasSolid); - - if (ImGui::Checkbox("Walkable Voxels", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_VOXELS_WALKABLE); - - ImGui::EndDisabled(); - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_COMPACT; - ImGui::BeginDisabled(!hasChf); - - if (ImGui::Checkbox("Compact", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_COMPACT); - - ImGui::EndDisabled(); - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_COMPACT_DISTANCE; - ImGui::BeginDisabled(!hasChf); - - if (ImGui::Checkbox("Compact Distance", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_COMPACT_DISTANCE); - - ImGui::EndDisabled(); - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_COMPACT_REGIONS; - ImGui::BeginDisabled(!hasChf); - - if (ImGui::Checkbox("Compact Regions", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_COMPACT_REGIONS); - - ImGui::EndDisabled(); - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_REGION_CONNECTIONS; - ImGui::BeginDisabled(!hasCset); - - if (ImGui::Checkbox("Region Connections", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_REGION_CONNECTIONS); - - ImGui::EndDisabled(); - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_RAW_CONTOURS; - ImGui::BeginDisabled(!hasCset); - - if (ImGui::Checkbox("Raw Contours", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_RAW_CONTOURS); - - ImGui::EndDisabled(); - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_CONTOURS; - ImGui::BeginDisabled(!hasCset); - - if (ImGui::Checkbox("Contours", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_CONTOURS); - - ImGui::EndDisabled(); - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_POLYMESH; - ImGui::BeginDisabled(!hasDMesh); - - if (ImGui::Checkbox("Poly Mesh", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_POLYMESH); - - ImGui::EndDisabled(); - - isEnabled = m_tileMeshDrawFlags & TM_DRAWFLAGS_POLYMESH_DETAIL; - ImGui::BeginDisabled(!hasDMesh); - - if (ImGui::Checkbox("Poly Mesh Detail", &isEnabled)) - toggleTileMeshDrawFlag(TM_DRAWFLAGS_POLYMESH_DETAIL); - - ImGui::EndDisabled(); - - if (intermediateDataUnavailable) - { - ImGui::Separator(); - - ImGui::Text("Tick 'Keep Intermediate Results'"); - ImGui::Text("rebuild some tiles to see"); - ImGui::Text("more debug mode options."); - } + Editor_StaticTileMeshCommon::renderTileMeshRenderOptions(); } void Editor_TileMesh::handleRender() { - if (!m_geom || !m_geom->getMesh()) - return; - - const float texScale = 1.0f / (m_cellSize * 10.0f); - - // Draw input mesh - if (m_tileMeshDrawFlags & TM_DRAWFLAGS_INPUT_MESH) - { - // Draw mesh - duDebugDrawTriMeshSlope(&m_dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(), - m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), - m_agentMaxSlope, texScale); - } - - glDepthMask(GL_FALSE); - - // Draw bounds - const float* bmin = m_geom->getNavMeshBoundsMin(); - const float* bmax = m_geom->getNavMeshBoundsMax(); - duDebugDrawBoxWire(&m_dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duRGBA(255,255,255,128), 1.0f); - - // Tiling grid. - int gw = 0, gh = 0; - rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); - const int tw = (gw + m_tileSize-1) / m_tileSize; - const int th = (gh + m_tileSize-1) / m_tileSize; - const float s = m_tileSize*m_cellSize; - duDebugDrawGridXY(&m_dd, bmax[0],bmin[1],bmin[2], tw,th, s, duRGBA(0,0,0,64), 1.0f); - - // Draw active tile - duDebugDrawBoxWire(&m_dd, m_lastBuiltTileBmin[0],m_lastBuiltTileBmin[1],m_lastBuiltTileBmin[2], - m_lastBuiltTileBmax[0],m_lastBuiltTileBmax[1],m_lastBuiltTileBmax[2], m_tileCol, 1.0f); - - if (m_navMesh && m_navQuery) - { - if (m_tileMeshDrawFlags & TM_DRAWFLAGS_NAVMESH) - { - duDebugDrawNavMeshWithClosedList(&m_dd, *m_navMesh, *m_navQuery, m_navMeshDrawFlags); - duDebugDrawNavMeshPolysWithFlags(&m_dd, *m_navMesh, EDITOR_POLYFLAGS_DISABLED, duRGBA(0, 0, 0, 128)); - } - } - - glDepthMask(GL_TRUE); - - if (m_chf) - { - if (m_tileMeshDrawFlags & TM_DRAWFLAGS_COMPACT) - duDebugDrawCompactHeightfieldSolid(&m_dd, *m_chf); - - if (m_tileMeshDrawFlags & TM_DRAWFLAGS_COMPACT_DISTANCE) - duDebugDrawCompactHeightfieldDistance(&m_dd, *m_chf); - if (m_tileMeshDrawFlags & TM_DRAWFLAGS_COMPACT_REGIONS) - duDebugDrawCompactHeightfieldRegions(&m_dd, *m_chf); - } - - if (m_solid) - { - if (m_tileMeshDrawFlags & TM_DRAWFLAGS_VOXELS) - { - glEnable(GL_FOG); - duDebugDrawHeightfieldSolid(&m_dd, *m_solid); - glDisable(GL_FOG); - } - if (m_tileMeshDrawFlags & TM_DRAWFLAGS_VOXELS_WALKABLE) - { - glEnable(GL_FOG); - duDebugDrawHeightfieldWalkable(&m_dd, *m_solid); - glDisable(GL_FOG); - } - } - - if (m_cset) - { - if (m_tileMeshDrawFlags & TM_DRAWFLAGS_RAW_CONTOURS) - { - glDepthMask(GL_FALSE); - duDebugDrawRawContours(&m_dd, *m_cset); - glDepthMask(GL_TRUE); - } - if (m_tileMeshDrawFlags & TM_DRAWFLAGS_CONTOURS) - { - glDepthMask(GL_FALSE); - duDebugDrawContours(&m_dd, *m_cset); - glDepthMask(GL_TRUE); - } - } - - if ((m_chf && m_cset) && (m_tileMeshDrawFlags & TM_DRAWFLAGS_REGION_CONNECTIONS)) - { - duDebugDrawCompactHeightfieldRegions(&m_dd, *m_chf); - - glDepthMask(GL_FALSE); - duDebugDrawRegionConnections(&m_dd, *m_cset); - glDepthMask(GL_TRUE); - } - - if (m_pmesh && (m_tileMeshDrawFlags & TM_DRAWFLAGS_POLYMESH)) - { - glDepthMask(GL_FALSE); - duDebugDrawPolyMesh(&m_dd, *m_pmesh); - glDepthMask(GL_TRUE); - } - - if (m_dmesh && (m_tileMeshDrawFlags & TM_DRAWFLAGS_POLYMESH_DETAIL)) - { - glDepthMask(GL_FALSE); - duDebugDrawPolyMeshDetail(&m_dd, *m_dmesh); - glDepthMask(GL_TRUE); - } - - // TODO: also add flags for this - m_geom->drawConvexVolumes(&m_dd); - m_geom->drawOffMeshConnections(&m_dd); - - if (m_tool) - m_tool->handleRender(); - - renderToolStates(); - - glDepthMask(GL_TRUE); + Editor_StaticTileMeshCommon::renderTileMeshData(); } void Editor_TileMesh::handleRenderOverlay(double* proj, double* model, int* view) diff --git a/src/naveditor/include/Editor.h b/src/naveditor/include/Editor.h index 8fa00ce5..edfba843 100644 --- a/src/naveditor/include/Editor.h +++ b/src/naveditor/include/Editor.h @@ -120,6 +120,7 @@ protected: bool m_filterLedgeSpans; bool m_filterWalkableLowHeightSpans; + int m_tileSize; float m_cellSize; float m_cellHeight; float m_agentHeight; @@ -198,6 +199,11 @@ public: void renderToolStates(); void renderOverlayToolStates(double* proj, double* model, int* view); + void renderNavMeshDebugMenu(); + void renderIntermediateTileMeshOptions(); + + void selectNavMeshType(const NavMeshType_e navMeshType); + void resetCommonSettings(); void handleCommonSettings(); diff --git a/src/naveditor/include/Editor_Common.h b/src/naveditor/include/Editor_Common.h new file mode 100644 index 00000000..9e73ad61 --- /dev/null +++ b/src/naveditor/include/Editor_Common.h @@ -0,0 +1,113 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#ifndef RECASTEDITORCOMMON_H +#define RECASTEDITORCOMMON_H +#include "Recast/Include/Recast.h" +#include "NavEditor/Include/ChunkyTriMesh.h" + +enum DrawTileMeshFlags +{ + TM_DRAWFLAGS_INPUT_MESH = (1<<0), + TM_DRAWFLAGS_NAVMESH = (1<<1), + TM_DRAWFLAGS_VOXELS = (1<<2), + TM_DRAWFLAGS_VOXELS_WALKABLE = (1<<3), + TM_DRAWFLAGS_COMPACT = (1<<4), + TM_DRAWFLAGS_COMPACT_DISTANCE = (1<<5), + TM_DRAWFLAGS_COMPACT_REGIONS = (1<<6), + TM_DRAWFLAGS_REGION_CONNECTIONS = (1<<7), + TM_DRAWFLAGS_RAW_CONTOURS = (1<<8), + TM_DRAWFLAGS_CONTOURS = (1<<9), + TM_DRAWFLAGS_POLYMESH = (1<<10), + TM_DRAWFLAGS_POLYMESH_DETAIL = (1<<11), + TM_DRAWFLAGS_TILE_CACHE_BOUNDS = (1<<12), + TM_DRAWFLAGS_TILE_CACHE_OBSTACLES = (1<<13), +}; + +class Editor_StaticTileMeshCommon : public Editor +{ +public: + Editor_StaticTileMeshCommon(); + void cleanup(); + + void renderTileMeshRenderOptions(); + void renderTileMeshData(); + + void renderIntermediateTileMeshOptions(); + + inline unsigned int getTileMeshDrawFlags() const { return m_tileMeshDrawFlags; } + inline void setTileMeshDrawFlags(unsigned int flags) { m_tileMeshDrawFlags = flags; } + + inline void toggleTileMeshDrawFlag(unsigned int flag) { m_tileMeshDrawFlags ^= flag; } + +protected: + unsigned char* m_triareas; + + rcHeightfield* m_solid; + rcCompactHeightfield* m_chf; + rcContourSet* m_cset; + rcPolyMesh* m_pmesh; + rcPolyMeshDetail* m_dmesh; + rcConfig m_cfg; + + unsigned int m_tileMeshDrawFlags; + unsigned int m_tileCol; + + float m_lastBuiltTileBmin[3]; + float m_lastBuiltTileBmax[3]; + + float m_totalBuildTimeMs; + + bool m_drawActiveTile; + bool m_keepInterResults; +}; + +class Editor_DynamicTileMeshCommon : public Editor +{ +public: + Editor_DynamicTileMeshCommon(); + + void renderTileMeshRenderOptions(); + void renderTileMeshData(); + + inline unsigned int getTileMeshDrawFlags() const { return m_tileMeshDrawFlags; } + inline void setTileMeshDrawFlags(unsigned int flags) { m_tileMeshDrawFlags = flags; } + + inline void toggleTileMeshDrawFlag(unsigned int flag) { m_tileMeshDrawFlags ^= flag; } + +protected: + class dtTileCache* m_tileCache; + struct LinearAllocator* m_talloc; + struct FastLZCompressor* m_tcomp; + struct MeshProcess* m_tmproc; + + float m_cacheBuildTimeMs; + int m_cacheCompressedSize; + int m_cacheRawSize; + int m_cacheLayerCount; + + unsigned int m_cacheBuildMemUsage; + unsigned int m_tileMeshDrawFlags; + + bool m_keepInterResults; +}; + +int EditorCommon_SetAndRenderTileProperties(const InputGeom* const geom, const int tileSize, + const float cellSize, int& maxTiles, int& maxPolysPerTile); + +#endif // RECASTEDITORCOMMON_H diff --git a/src/naveditor/include/Editor_SoloMesh.h b/src/naveditor/include/Editor_SoloMesh.h index 1784bfa4..950ad0e8 100644 --- a/src/naveditor/include/Editor_SoloMesh.h +++ b/src/naveditor/include/Editor_SoloMesh.h @@ -16,51 +16,17 @@ // 3. This notice may not be removed or altered from any source distribution. // -#ifndef RECASTSAMPLESOLOMESH_H -#define RECASTSAMPLESOLOMESH_H +#ifndef RECASTEDITORSOLOMESH_H +#define RECASTEDITORSOLOMESH_H #include "Recast/Include/Recast.h" #include "Detour/Include/DetourNavMesh.h" -#include "NavEditor/Include/Sample.h" +#include "NavEditor/Include/Editor.h" +#include "NavEditor/Include/Editor_Common.h" -class Editor_SoloMesh : public Sample +class Editor_SoloMesh : public Editor_StaticTileMeshCommon { protected: - bool m_keepInterResults; - float m_totalBuildTimeMs; - - unsigned char* m_triareas; - rcHeightfield* m_solid; - rcCompactHeightfield* m_chf; - rcContourSet* m_cset; - rcPolyMesh* m_pmesh; - rcConfig m_cfg; - rcPolyMeshDetail* m_dmesh; - - enum DrawMode - { - DRAWMODE_NAVMESH, - DRAWMODE_NAVMESH_TRANS, - DRAWMODE_NAVMESH_BVTREE, - DRAWMODE_NAVMESH_NODES, - 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, - DRAWMODE_POLYMESH_DETAIL, - MAX_DRAWMODE - }; - - DrawMode m_drawMode; - void cleanup(); public: @@ -83,4 +49,4 @@ private: }; -#endif // RECASTSAMPLESOLOMESHSIMPLE_H +#endif // RECASTEDITORSOLOMESH_H diff --git a/src/naveditor/include/Editor_TempObstacles.h b/src/naveditor/include/Editor_TempObstacles.h index cfc059b6..c1ba434b 100644 --- a/src/naveditor/include/Editor_TempObstacles.h +++ b/src/naveditor/include/Editor_TempObstacles.h @@ -16,50 +16,21 @@ // 3. This notice may not be removed or altered from any source distribution. // -#ifndef RECASTSAMPLETEMPOBSTACLE_H -#define RECASTSAMPLETEMPOBSTACLE_H +#ifndef RECASTEDITORTEMPOBSTACLE_H +#define RECASTEDITORTEMPOBSTACLE_H #include "Recast/Include/Recast.h" #include "Detour/Include/DetourNavMesh.h" #include "NavEditor/Include/ChunkyTriMesh.h" -#include "NavEditor/Include/Sample.h" +#include "NavEditor/Include/Editor.h" +#include "NavEditor/Include/Editor_Common.h" -class Editor_TempObstacles : public Sample +class Editor_TempObstacles : public Editor_DynamicTileMeshCommon { protected: - bool m_keepInterResults; - - struct LinearAllocator* m_talloc; - struct FastLZCompressor* m_tcomp; - struct MeshProcess* m_tmproc; - - class dtTileCache* m_tileCache; - - float m_cacheBuildTimeMs; - int m_cacheCompressedSize; - int m_cacheRawSize; - int m_cacheLayerCount; - unsigned int m_cacheBuildMemUsage; - - enum DrawMode - { - DRAWMODE_NAVMESH, - DRAWMODE_NAVMESH_TRANS, - DRAWMODE_NAVMESH_BVTREE, - DRAWMODE_NAVMESH_NODES, - DRAWMODE_NAVMESH_PORTALS, - DRAWMODE_NAVMESH_INVIS, - DRAWMODE_MESH, - DRAWMODE_CACHE_BOUNDS, - MAX_DRAWMODE - }; - - DrawMode m_drawMode; - int m_maxTiles; int m_maxPolysPerTile; - float m_tileSize; public: Editor_TempObstacles(); @@ -95,4 +66,4 @@ private: }; -#endif // RECASTSAMPLETEMPOBSTACLE_H +#endif // RECASTEDITORTEMPOBSTACLE_H diff --git a/src/naveditor/include/Editor_TileMesh.h b/src/naveditor/include/Editor_TileMesh.h index d41fde6b..d9a5987d 100644 --- a/src/naveditor/include/Editor_TileMesh.h +++ b/src/naveditor/include/Editor_TileMesh.h @@ -16,62 +16,30 @@ // 3. This notice may not be removed or altered from any source distribution. // -#ifndef RECASTSAMPLETILEMESH_H -#define RECASTSAMPLETILEMESH_H +#ifndef RECASTEDITORTILEMESH_H +#define RECASTEDITORTILEMESH_H #include "Recast/Include/Recast.h" #include "Detour/Include/DetourNavMesh.h" #include "NavEditor/Include/ChunkyTriMesh.h" #include "NavEditor/Include/Editor.h" +#include "NavEditor/Include/Editor_Common.h" -class Editor_TileMesh : public Editor +class Editor_TileMesh : public Editor_StaticTileMeshCommon { protected: - bool m_keepInterResults; bool m_buildAll; - float m_totalBuildTimeMs; - - unsigned char* m_triareas; - rcHeightfield* m_solid; - rcCompactHeightfield* m_chf; - rcContourSet* m_cset; - rcPolyMesh* m_pmesh; - rcPolyMeshDetail* m_dmesh; - rcConfig m_cfg; - - enum DrawTileMeshFlags - { - TM_DRAWFLAGS_INPUT_MESH = (1<<0), - TM_DRAWFLAGS_NAVMESH = (1<<1), - TM_DRAWFLAGS_VOXELS = (1<<2), - TM_DRAWFLAGS_VOXELS_WALKABLE = (1<<3), - TM_DRAWFLAGS_COMPACT = (1<<4), - TM_DRAWFLAGS_COMPACT_DISTANCE = (1<<5), - TM_DRAWFLAGS_COMPACT_REGIONS = (1<<6), - TM_DRAWFLAGS_REGION_CONNECTIONS = (1<<7), - TM_DRAWFLAGS_RAW_CONTOURS = (1<<8), - TM_DRAWFLAGS_CONTOURS = (1<<9), - TM_DRAWFLAGS_POLYMESH = (1<<10), - TM_DRAWFLAGS_POLYMESH_DETAIL = (1<<11), - }; - - unsigned int m_tileMeshDrawFlags; int m_maxTiles; int m_maxPolysPerTile; int m_tileSize; - unsigned int m_tileCol; - float m_lastBuiltTileBmin[3]; - float m_lastBuiltTileBmax[3]; float m_tileBuildTime; float m_tileMemUsage; int m_tileTriCount; unsigned char* buildTileMesh(const int tx, const int ty, const float* bmin, const float* bmax, int& dataSize); - void cleanup(); - void saveAll(const char* path, const dtNavMesh* mesh); dtNavMesh* loadAll(const char* path); @@ -87,13 +55,6 @@ public: virtual void handleMeshChanged(class InputGeom* geom); virtual bool handleBuild(); virtual void collectSettings(struct BuildSettings& settings); - - void selectNavMeshType(const NavMeshType_e navMeshType); - - inline unsigned int getTileMeshDrawFlags() const { return m_tileMeshDrawFlags; } - inline void setTileMeshDrawFlags(unsigned int flags) { m_tileMeshDrawFlags = flags; } - - inline void toggleTileMeshDrawFlag(unsigned int flag) { m_tileMeshDrawFlags ^= flag; } void getTilePos(const float* pos, int& tx, int& ty); void getTileExtents(int tx, int ty, float* bmin, float* bmax); @@ -111,4 +72,4 @@ private: }; -#endif // RECASTSAMPLETILEMESH_H +#endif // RECASTEDITORTILEMESH_H diff --git a/src/naveditor/main.cpp b/src/naveditor/main.cpp index 308eaebf..f56098f4 100644 --- a/src/naveditor/main.cpp +++ b/src/naveditor/main.cpp @@ -23,6 +23,7 @@ #include "NavEditor/Include/InputGeom.h" #include "NavEditor/Include/TestCase.h" #include "NavEditor/Include/Filelist.h" +#include "NavEditor/Include/Editor_SoloMesh.h" #include "NavEditor/Include/Editor_TileMesh.h" #include "NavEditor/Include/Editor_Debug.h" #include "NavEditor/include/DroidSans.h" @@ -36,6 +37,7 @@ struct SampleItem Editor* (*create)(); const string name; }; +Editor* createSolo() { return new Editor_SoloMesh(); } Editor* createTile() { return new Editor_TileMesh(); } Editor* createDebug() { return new Editor_Debug(); }