From 73262ca616f0623a9715ceac90c17b0da4b320d7 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Mon, 5 Feb 2024 17:01:22 +0000 Subject: Port navmesh debug renderer from primedev (#626) Adds support for rendering navmeshes in-game using debug overlay Cherry-picked from primedev, originally written by F1F7Y Co-authored-by: F1F7Y Co-authored-by: Maya <11448698+RoyalBlue1@users.noreply.github.com> --- primedev/server/ai_helper.cpp | 159 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 primedev/server/ai_helper.cpp (limited to 'primedev/server/ai_helper.cpp') diff --git a/primedev/server/ai_helper.cpp b/primedev/server/ai_helper.cpp new file mode 100644 index 00000000..ebb56af2 --- /dev/null +++ b/primedev/server/ai_helper.cpp @@ -0,0 +1,159 @@ +#include "ai_helper.h" + +#include "client/debugoverlay.h" +#include "client/cdll_client_int.h" +#include "engine/hoststate.h" + +#include "core/math/vplane.h" + +#include + +const int AINET_VERSION_NUMBER = 57; +const int AINET_SCRIPT_VERSION_NUMBER = 21; +const int PLACEHOLDER_CRC = 0; + +static ConVar* Cvar_navmesh_debug_hull; +static ConVar* Cvar_navmesh_debug_camera_radius; +static ConVar* Cvar_navmesh_debug_lossy_optimization; + +//----------------------------------------------------------------------------- +// Purpose: Get navmesh pointer for hull +// Output : navmesh*, nullptr if out of range +//----------------------------------------------------------------------------- +dtNavMesh* GetNavMeshForHull(int nHull) +{ + if (nHull < 1 || nHull > 4) + return nullptr; + + return g_pNavMesh[nHull - 1]; +} + +//----------------------------------------------------------------------------- +// Purpose: Packs two vectors into a __m128i +// Input : &v1 - +// &v2 - +// Output : +//----------------------------------------------------------------------------- +__m128i PackVerticesSIMD16(const Vector3& v1, const Vector3& v2) +{ + short x1, x2, y1, y2, z1, z2; + x1 = static_cast(v1.x); + x2 = static_cast(v2.x); + y1 = static_cast(v1.y); + y2 = static_cast(v2.y); + z1 = static_cast(v1.z); + z2 = static_cast(v2.z); + + __m128i xRes = _mm_set_epi16(x1, x2, y1, y2, z1, z2, 0, 0); + + if (x1 < x2) + xRes = _mm_shufflehi_epi16(xRes, _MM_SHUFFLE(2, 3, 1, 0)); + + if (y1 < y2) + xRes = _mm_shufflehi_epi16(xRes, _MM_SHUFFLE(3, 2, 0, 1)); + + if (z1 < z2) + xRes = _mm_shufflelo_epi16(xRes, _MM_SHUFFLE(2, 3, 1, 0)); + + return xRes; +} + +//----------------------------------------------------------------------------- +// Purpose: Draw navmesh polys using debug overlay +// Input : *pNavMesh +//----------------------------------------------------------------------------- +void CAI_Helper::DrawNavmeshPolys(dtNavMesh* pNavMesh) +{ + if (!pNavMesh) + pNavMesh = GetNavMeshForHull(Cvar_navmesh_debug_hull->GetInt()); + if (!pNavMesh) + return; + + Vector3 vCamera; + QAngle aCamera; + float fFov; + g_pClientTools->GetLocalPlayerEyePosition(vCamera, aCamera, fFov); + + const VPlane CullPlane(vCamera - aCamera.GetNormal() * 256.0f, aCamera); + + const float fCamRadius = Cvar_navmesh_debug_camera_radius->GetFloat(); + const bool bOptimize = Cvar_navmesh_debug_lossy_optimization->GetBool(); + + // Used for lossy optimization ( z is ignored when checking for duplicates ) + // [Fifty]: On a release build i gained around 12 fps on a 1050 ti + std::unordered_set sOutlines; + + for (int i = 0; i < pNavMesh->m_maxTiles; ++i) + { + const dtMeshTile* pTile = &pNavMesh->m_tiles[i]; + + if (!pTile->header) + continue; + + for (int j = 0; j < pTile->header->polyCount; j++) + { + const dtPoly* pPoly = &pTile->polys[j]; + + if (vCamera.DistTo(pPoly->org) > fCamRadius) + continue; + + if (CullPlane.GetPointSide(pPoly->org) != SIDE_FRONT) + continue; + + const unsigned int ip = (unsigned int)(pPoly - pTile->polys); + + if (pPoly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) + { + const dtOffMeshConnection* pCon = &pTile->offMeshConnections[ip - pTile->header->offMeshBase]; + RenderLine(pCon->origin, pCon->dest, Color(255, 250, 50, 255), true); + } + else + { + const dtPolyDetail* pDetail = &pTile->detailMeshes[ip]; + + Vector3 v[3]; + + for (int k = 0; k < pDetail->triCount; ++k) + { + const unsigned char* t = &pTile->detailTris[(pDetail->triBase + k) * 4]; + for (int l = 0; l < 3; ++l) + { + if (t[l] < pPoly->vertCount) + { + float* pfVerts = &pTile->verts[pPoly->verts[t[l]] * 3]; + v[l] = Vector3(pfVerts[0], pfVerts[1], pfVerts[2]); + } + else + { + float* pfVerts = &pTile->detailVerts[(pDetail->vertBase + t[l] - pPoly->vertCount) * 3]; + v[l] = Vector3(pfVerts[0], pfVerts[1], pfVerts[2]); + } + } + + RenderTriangle(v[0], v[1], v[2], Color(110, 200, 220, 160), true); + + auto r = sOutlines.insert(_mm_extract_epi64(PackVerticesSIMD16(v[0], v[1]), 1)); + if (r.second || !bOptimize) + RenderLine(v[0], v[1], Color(0, 0, 150), true); + + r = sOutlines.insert(_mm_extract_epi64(PackVerticesSIMD16(v[1], v[2]), 1)); + if (r.second || !bOptimize) + RenderLine(v[1], v[2], Color(0, 0, 150), true); + + r = sOutlines.insert(_mm_extract_epi64(PackVerticesSIMD16(v[2], v[0]), 1)); + if (r.second || !bOptimize) + RenderLine(v[2], v[0], Color(0, 0, 150), true); + } + } + } + } +} + +ON_DLL_LOAD("server.dll", ServerAIHelper, (CModule module)) +{ + Cvar_navmesh_debug_hull = new ConVar("navmesh_debug_hull", "0", FCVAR_RELEASE, "0 = NONE"); + Cvar_navmesh_debug_camera_radius = + new ConVar("navmesh_debug_camera_radius", "1000", FCVAR_RELEASE, "Radius in which to draw navmeshes"); + Cvar_navmesh_debug_lossy_optimization = + new ConVar("navmesh_debug_lossy_optimization", "1", FCVAR_RELEASE, "Whether to enable lossy navmesh debug draw optimizations"); +} -- cgit v1.2.3