123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- //
- // 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.
- //
- #define _USE_MATH_DEFINES
- #include <math.h>
- #include <stdio.h>
- #include <string.h>
- #include <float.h>
- #include <vector>
- #include "SDL.h"
- #include "SDL_opengl.h"
- #include "imgui.h"
- #include "NavMeshPruneTool.h"
- #include "InputGeom.h"
- #include "Sample.h"
- #include "DetourNavMesh.h"
- #include "DetourCommon.h"
- #include "DetourAssert.h"
- #include "DetourDebugDraw.h"
- #ifdef WIN32
- # define snprintf _snprintf
- #endif
- class NavmeshFlags
- {
- struct TileFlags
- {
- inline void purge() { dtFree(flags); }
- unsigned char* flags;
- int nflags;
- dtPolyRef base;
- };
-
- const dtNavMesh* m_nav;
- TileFlags* m_tiles;
- int m_ntiles;
- public:
- NavmeshFlags() :
- m_nav(0), m_tiles(0), m_ntiles(0)
- {
- }
-
- ~NavmeshFlags()
- {
- for (int i = 0; i < m_ntiles; ++i)
- m_tiles[i].purge();
- dtFree(m_tiles);
- }
-
- bool init(const dtNavMesh* nav)
- {
- m_ntiles = nav->getMaxTiles();
- if (!m_ntiles)
- return true;
- m_tiles = (TileFlags*)dtAlloc(sizeof(TileFlags)*m_ntiles, DT_ALLOC_TEMP);
- if (!m_tiles)
- {
- return false;
- }
- memset(m_tiles, 0, sizeof(TileFlags)*m_ntiles);
-
- // Alloc flags for each tile.
- for (int i = 0; i < nav->getMaxTiles(); ++i)
- {
- const dtMeshTile* tile = nav->getTile(i);
- if (!tile->header) continue;
- TileFlags* tf = &m_tiles[i];
- tf->nflags = tile->header->polyCount;
- tf->base = nav->getPolyRefBase(tile);
- if (tf->nflags)
- {
- tf->flags = (unsigned char*)dtAlloc(tf->nflags, DT_ALLOC_TEMP);
- if (!tf->flags)
- return false;
- memset(tf->flags, 0, tf->nflags);
- }
- }
-
- m_nav = nav;
-
- return false;
- }
-
- inline void clearAllFlags()
- {
- for (int i = 0; i < m_ntiles; ++i)
- {
- TileFlags* tf = &m_tiles[i];
- if (tf->nflags)
- memset(tf->flags, 0, tf->nflags);
- }
- }
-
- inline unsigned char getFlags(dtPolyRef ref)
- {
- dtAssert(m_nav);
- dtAssert(m_ntiles);
- // Assume the ref is valid, no bounds checks.
- unsigned int salt, it, ip;
- m_nav->decodePolyId(ref, salt, it, ip);
- return m_tiles[it].flags[ip];
- }
- inline void setFlags(dtPolyRef ref, unsigned char flags)
- {
- dtAssert(m_nav);
- dtAssert(m_ntiles);
- // Assume the ref is valid, no bounds checks.
- unsigned int salt, it, ip;
- m_nav->decodePolyId(ref, salt, it, ip);
- m_tiles[it].flags[ip] = flags;
- }
-
- };
- static void floodNavmesh(dtNavMesh* nav, NavmeshFlags* flags, dtPolyRef start, unsigned char flag)
- {
- // If already visited, skip.
- if (flags->getFlags(start))
- return;
- flags->setFlags(start, flag);
-
- std::vector<dtPolyRef> openList;
- openList.push_back(start);
- while (openList.size())
- {
- const dtPolyRef ref = openList.back();
- openList.pop_back();
- // Get current poly and tile.
- // The API input has been cheked already, skip checking internal data.
- const dtMeshTile* tile = 0;
- const dtPoly* poly = 0;
- nav->getTileAndPolyByRefUnsafe(ref, &tile, &poly);
- // Visit linked polygons.
- for (unsigned int i = poly->firstLink; i != DT_NULL_LINK; i = tile->links[i].next)
- {
- const dtPolyRef neiRef = tile->links[i].ref;
- // Skip invalid and already visited.
- if (!neiRef || flags->getFlags(neiRef))
- continue;
- // Mark as visited
- flags->setFlags(neiRef, flag);
- // Visit neighbours
- openList.push_back(neiRef);
- }
- }
- }
- static void disableUnvisitedPolys(dtNavMesh* nav, NavmeshFlags* flags)
- {
- for (int i = 0; i < nav->getMaxTiles(); ++i)
- {
- const dtMeshTile* tile = ((const dtNavMesh*)nav)->getTile(i);
- if (!tile->header) continue;
- const dtPolyRef base = nav->getPolyRefBase(tile);
- for (int j = 0; j < tile->header->polyCount; ++j)
- {
- const dtPolyRef ref = base | (unsigned int)j;
- if (!flags->getFlags(ref))
- {
- unsigned short f = 0;
- nav->getPolyFlags(ref, &f);
- nav->setPolyFlags(ref, f | SAMPLE_POLYFLAGS_DISABLED);
- }
- }
- }
- }
- NavMeshPruneTool::NavMeshPruneTool() :
- m_sample(0),
- m_flags(0),
- m_hitPosSet(false)
- {
- }
- NavMeshPruneTool::~NavMeshPruneTool()
- {
- delete m_flags;
- }
- void NavMeshPruneTool::init(Sample* sample)
- {
- m_sample = sample;
- }
- void NavMeshPruneTool::reset()
- {
- m_hitPosSet = false;
- delete m_flags;
- m_flags = 0;
- }
- void NavMeshPruneTool::handleMenu()
- {
- dtNavMesh* nav = m_sample->getNavMesh();
- if (!nav) return;
- if (!m_flags) return;
- if (imguiButton("Clear Selection"))
- {
- m_flags->clearAllFlags();
- }
-
- if (imguiButton("Prune Unselected"))
- {
- disableUnvisitedPolys(nav, m_flags);
- delete m_flags;
- m_flags = 0;
- }
- }
- void NavMeshPruneTool::handleClick(const float* s, const float* p, bool shift)
- {
- rcIgnoreUnused(s);
- rcIgnoreUnused(shift);
- if (!m_sample) return;
- InputGeom* geom = m_sample->getInputGeom();
- if (!geom) return;
- dtNavMesh* nav = m_sample->getNavMesh();
- if (!nav) return;
- dtNavMeshQuery* query = m_sample->getNavMeshQuery();
- if (!query) return;
-
- dtVcopy(m_hitPos, p);
- m_hitPosSet = true;
-
- if (!m_flags)
- {
- m_flags = new NavmeshFlags;
- m_flags->init(nav);
- }
-
- const float halfExtents[3] = { 2, 4, 2 };
- dtQueryFilter filter;
- dtPolyRef ref = 0;
- query->findNearestPoly(p, halfExtents, &filter, &ref, 0);
- floodNavmesh(nav, m_flags, ref, 1);
- }
- void NavMeshPruneTool::handleToggle()
- {
- }
- void NavMeshPruneTool::handleStep()
- {
- }
- void NavMeshPruneTool::handleUpdate(const float /*dt*/)
- {
- }
- void NavMeshPruneTool::handleRender()
- {
- duDebugDraw& dd = m_sample->getDebugDraw();
- if (m_hitPosSet)
- {
- const float s = m_sample->getAgentRadius();
- const unsigned int col = duRGBA(255,255,255,255);
- dd.begin(DU_DRAW_LINES);
- dd.vertex(m_hitPos[0]-s,m_hitPos[1],m_hitPos[2], col);
- dd.vertex(m_hitPos[0]+s,m_hitPos[1],m_hitPos[2], col);
- dd.vertex(m_hitPos[0],m_hitPos[1]-s,m_hitPos[2], col);
- dd.vertex(m_hitPos[0],m_hitPos[1]+s,m_hitPos[2], col);
- dd.vertex(m_hitPos[0],m_hitPos[1],m_hitPos[2]-s, col);
- dd.vertex(m_hitPos[0],m_hitPos[1],m_hitPos[2]+s, col);
- dd.end();
- }
- const dtNavMesh* nav = m_sample->getNavMesh();
- if (m_flags && nav)
- {
- for (int i = 0; i < nav->getMaxTiles(); ++i)
- {
- const dtMeshTile* tile = nav->getTile(i);
- if (!tile->header) continue;
- const dtPolyRef base = nav->getPolyRefBase(tile);
- for (int j = 0; j < tile->header->polyCount; ++j)
- {
- const dtPolyRef ref = base | (unsigned int)j;
- if (m_flags->getFlags(ref))
- {
- duDebugDrawNavMeshPoly(&dd, *nav, ref, duRGBA(255,255,255,128));
- }
- }
- }
- }
- }
- void NavMeshPruneTool::handleRenderOverlay(double* proj, double* model, int* view)
- {
- rcIgnoreUnused(model);
- rcIgnoreUnused(proj);
- // Tool help
- const int h = view[3];
- imguiDrawText(280, h-40, IMGUI_ALIGN_LEFT, "LMB: Click fill area.", imguiRGBA(255,255,255,192));
- }
|