diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c4e756..e13d937 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ endif() project( NavKit - VERSION 0.8.0 + VERSION 0.9.0 DESCRIPTION "An app to create NAVP and AIRG files for use with Hitman" LANGUAGES CXX) diff --git a/include/NavKit/NavKitConfig.h b/include/NavKit/NavKitConfig.h index ab6ccfb..9573ff2 100644 --- a/include/NavKit/NavKitConfig.h +++ b/include/NavKit/NavKitConfig.h @@ -1,3 +1,3 @@ #define NavKit_VERSION_MAJOR "0" -#define NavKit_VERSION_MINOR "8" +#define NavKit_VERSION_MINOR "9" #define NavKit_VERSION_PATCH "0" diff --git a/include/NavKit/Navp.h b/include/NavKit/Navp.h index f838878..6763d6e 100644 --- a/include/NavKit/Navp.h +++ b/include/NavKit/Navp.h @@ -30,6 +30,13 @@ class Navp { float bBoxSizeY; float bBoxSizeZ; + float lastBBoxPosX; + float lastBBoxPosY; + float lastBBoxPosZ; + float lastBBoxSizeX; + float lastBBoxSizeY; + float lastBBoxSizeZ; + bool stairsCheckboxValue; void setLastLoadFileName(const char* fileName); diff --git a/include/NavKit/ReasoningGrid.h b/include/NavKit/ReasoningGrid.h index 335a865..36f938f 100644 --- a/include/NavKit/ReasoningGrid.h +++ b/include/NavKit/ReasoningGrid.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -9,7 +10,9 @@ #include "..\NavWeakness\NavPower.h" #include "..\RecastDemo\SampleInterfaces.h" #include "..\..\extern\simdjson\simdjson.h" +#include "NavKit.h" +class NavKit; class Vec4 { public: float x; @@ -65,5 +68,5 @@ class ReasoningGrid { const void writeJson(std::ostream& f); void readJson(const char* p_AirgPath); - void build(NavPower::NavMesh* navMesh, BuildContext* ctx); + static void build(ReasoningGrid* airg, NavPower::NavMesh* navMesh, NavKit* ctx); }; diff --git a/src/Airg.cpp b/src/Airg.cpp index 00791c4..e0ee8fd 100644 --- a/src/Airg.cpp +++ b/src/Airg.cpp @@ -89,12 +89,14 @@ void Airg::drawMenu() { navKit->log(RC_LOG_PROGRESS, msg.data()); if (extension == "JSON") { saveAirg(fileName); + navKit->log(RC_LOG_PROGRESS, ("Finished saving Airg to " + std::string{ fileName } + ".").c_str()); } else if (extension == "AIRG") { std::string tempJsonFile = fileName; tempJsonFile += ".temp.json"; saveAirg(tempJsonFile); airgResourceGenerator->FromJsonFileToResourceFile(tempJsonFile.data(), fileName, false); + navKit->log(RC_LOG_PROGRESS, ("Finished saving Airg to " + std::string{ fileName } + ".").c_str()); std::filesystem::remove(tempJsonFile); } } @@ -106,8 +108,8 @@ void Airg::drawMenu() { reasoningGrid = new ReasoningGrid(); std::string msg = "Building Airg from Navp"; navKit->log(RC_LOG_PROGRESS, msg.data()); - reasoningGrid->build(navKit->navp->navMesh, &navKit->ctx); - airgLoaded = true; + std::thread buildAirgThread(&ReasoningGrid::build, reasoningGrid, navKit->navp->navMesh, navKit); + buildAirgThread.detach(); } imguiEndScrollArea(); } @@ -164,7 +166,6 @@ void Airg::saveAirg(std::string fileName) { std::ofstream fileOutputStream(s_OutputFileName); reasoningGrid->writeJson(fileOutputStream); fileOutputStream.close(); - navKit->log(RC_LOG_PROGRESS, ("Finished saving Airg to " + std::string{fileName} + ".").c_str()); } void Airg::loadAirg(Airg* airg, char* fileName, bool isFromJson) { diff --git a/src/Navp.cpp b/src/Navp.cpp index 0748e74..6edebcb 100644 --- a/src/Navp.cpp +++ b/src/Navp.cpp @@ -17,6 +17,12 @@ Navp::Navp(NavKit* navKit): navKit(navKit) { bBoxSizeX = 100.0; bBoxSizeY = 100.0; bBoxSizeZ = 100.0; + lastBBoxPosX = 0.0; + lastBBoxPosY = 0.0; + lastBBoxPosZ = 0.0; + lastBBoxSizeX = 100.0; + lastBBoxSizeY = 100.0; + lastBBoxSizeZ = 100.0; stairsCheckboxValue = false; loading = false; @@ -267,12 +273,42 @@ void Navp::drawMenu() { navKit->sample->handleCommonSettings(); bool bboxChanged = false; - bboxChanged |= imguiSlider("Bounding Box Origin X", &bBoxPosX, -300.0f, 300.0f, 1.0f); - bboxChanged |= imguiSlider("Bounding Box Origin Y", &bBoxPosY, -300.0f, 300.0f, 1.0f); - bboxChanged |= imguiSlider("Bounding Box Origin Z", &bBoxPosZ, -300.0f, 300.0f, 1.0f); - bboxChanged |= imguiSlider("Bounding Box Size X", &bBoxSizeX, 1.0f, 600.0f, 1.0f); - bboxChanged |= imguiSlider("Bounding Box Size Y", &bBoxSizeY, 1.0f, 600.0f, 1.0f); - bboxChanged |= imguiSlider("Bounding Box Size Z", &bBoxSizeZ, 1.0f, 600.0f, 1.0f); + if (imguiSlider("Bounding Box Origin X", &bBoxPosX, -300.0f, 300.0f, 1.0f)) { + if (lastBBoxPosX != bBoxPosX) { + bboxChanged = true; + lastBBoxPosX = bBoxPosX; + } + } + if (imguiSlider("Bounding Box Origin Y", &bBoxPosY, -300.0f, 300.0f, 1.0f)) { + if (lastBBoxPosY != bBoxPosY) { + bboxChanged = true; + lastBBoxPosY = bBoxPosY; + } + } + if (imguiSlider("Bounding Box Origin Z", &bBoxPosZ, -300.0f, 300.0f, 1.0f)) { + if (lastBBoxPosZ != bBoxPosZ) { + bboxChanged = true; + lastBBoxPosZ = bBoxPosZ; + } + } + if (imguiSlider("Bounding Box Size X", &bBoxSizeX, 1.0f, 600.0f, 1.0f)) { + if (lastBBoxSizeX != bBoxSizeX) { + bboxChanged = true; + lastBBoxSizeX = bBoxSizeX; + } + } + if (imguiSlider("Bounding Box Size Y", &bBoxSizeY, 1.0f, 600.0f, 1.0f)) { + if (lastBBoxSizeY != bBoxSizeY) { + bboxChanged = true; + lastBBoxSizeY = bBoxSizeY; + } + } + if (imguiSlider("Bounding Box Size Z", &bBoxSizeZ, 1.0f, 600.0f, 1.0f)) { + if (lastBBoxSizeZ != bBoxSizeZ) { + bboxChanged = true; + lastBBoxSizeZ = bBoxSizeZ; + } + } if (bboxChanged) { diff --git a/src/ReasoningGrid.cpp b/src/ReasoningGrid.cpp index 7d89242..1009196 100644 --- a/src/ReasoningGrid.cpp +++ b/src/ReasoningGrid.cpp @@ -236,9 +236,20 @@ int pnpoly(int nvert, float* vertx, float* verty, float testx, float testy) return c; } -void ReasoningGrid::build(NavPower::NavMesh* navMesh, BuildContext* ctx) { - ctx->log(RC_LOG_PROGRESS, "Started building Airg."); +float calcZ(Vec3 p1, Vec3 p2, Vec3 p3, float x, float y) { + float dx1 = x - p1.X; + float dy1 = y - p1.Y; + float dx2 = p2.X - p1.X; + float dy2 = p2.Y - p1.Y; + float dx3 = p3.X - p1.X; + float dy3 = p3.Y - p1.Y; + return p1.Z + ((dy1 * dx3 - dx1 * dy3) * (p2.Z - p1.Z) + (dx1 * dy2 - dy1 * dx2) * (p3.Z - p1.Z)) / (dx3 * dy2 - dx2 * dy3); +} + +void ReasoningGrid::build(ReasoningGrid* airg, NavPower::NavMesh* navMesh, NavKit* navKit) { + navKit->log(RC_LOG_PROGRESS, "Started building Airg."); double spacing = 2; + double zSpacing = 1; // grid is set up in this order: Z[Y[X[]]] std::vector>> grid; Vec3 min = navMesh->m_graphHdr->m_bbox.m_min; @@ -247,39 +258,78 @@ void ReasoningGrid::build(NavPower::NavMesh* navMesh, BuildContext* ctx) { Vec3 max = navMesh->m_graphHdr->m_bbox.m_max; int gridXSize = std::ceil((max.X - min.X) / spacing); int gridYSize = std::ceil((max.Y - min.Y) / spacing); - int gridZSize = 1; - m_Properties.fGridSpacing = spacing; - m_Properties.nGridWidth = gridYSize; - m_Properties.vMin.x = min.X; - m_Properties.vMin.y = min.Y; - m_Properties.vMin.z = min.Z; - m_Properties.vMin.w = 1; - m_Properties.vMax.x = max.X; - m_Properties.vMax.y = max.Y; - m_Properties.vMax.z = max.Z; - m_Properties.vMax.w = 1; + int gridZSize = std::ceil((max.Z - min.Z) / zSpacing); + gridZSize = gridZSize > 0 ? gridZSize : 1; + airg->m_Properties.fGridSpacing = spacing; + airg->m_Properties.nGridWidth = gridYSize; + airg->m_Properties.vMin.x = min.X; + airg->m_Properties.vMin.y = min.Y; + airg->m_Properties.vMin.z = min.Z; + airg->m_Properties.vMin.w = 1; + airg->m_Properties.vMax.x = max.X; + airg->m_Properties.vMax.y = max.Y; + airg->m_Properties.vMax.z = max.Z; + airg->m_Properties.vMax.w = 1; + + std::vector areaZMins; + std::vector areaZMaxes; + + for (auto area : navMesh->m_areas) { + const int areaPointCount = area.m_edges.size(); + double areaMinZ = 1000; + double areaMaxZ = -1000; + double pointZ = 0; + for (int i = 0; i < areaPointCount; i++) { + pointZ = area.m_edges[i]->m_pos.Z; + areaMinZ = areaMinZ < pointZ ? areaMinZ : pointZ; + areaMaxZ = areaMaxZ > pointZ ? areaMaxZ : pointZ; + } + areaZMins.push_back(areaMinZ); + areaZMaxes.push_back(areaMaxZ); + } + std::vector> areasByZLevel; + for (int zi = 0; zi < gridZSize; zi++) { + std::vector areasForZLevel; + for (int areaIndex = 0; areaIndex < navMesh->m_areas.size(); areaIndex++) { + double minZ = min.Z + zi * zSpacing; + double maxZ = min.Z + (zi + 1) * zSpacing; + if ((areaZMins[areaIndex] >= minZ && areaZMins[areaIndex] <= maxZ) || + (areaZMaxes[areaIndex] >= minZ && areaZMaxes[areaIndex] <= maxZ) || + (areaZMins[areaIndex] <= minZ && areaZMaxes[areaIndex] >= maxZ)) { + areasForZLevel.push_back(areaIndex); + } + } + areasByZLevel.push_back(areasForZLevel); + } int wayPointIndex = 0; for (int zi = 0; zi < gridZSize; zi++) { std::vector> yRow; + navKit->log(rcLogCategory::RC_LOG_PROGRESS, ("Adding waypoints for Z level: " + std::to_string(zi) + " at Z: " + std::to_string(min.Z + zi * zSpacing)).c_str()); + double minZ = min.Z + zi * zSpacing; + double maxZ = min.Z + (zi + 1) * zSpacing; for (int yi = 0; yi < gridYSize; yi++) { std::vector xRow; for (int xi = 0; xi < gridXSize; xi++) { - bool pointInArea = false; double x = min.X + xi * spacing; double y = min.Y + yi * spacing; - double z = min.Z + zi * spacing; - for (auto area : navMesh->m_areas) { + double z = min.Z + zi * zSpacing; + bool pointInArea = false; + for (int areaIndex : areasByZLevel[zi]) { + auto area = navMesh->m_areas[areaIndex]; const int areaPointCount = area.m_edges.size(); - float areaXCoords[10]; - float areaYCoords[10]; - for (int i = 0; i < areaPointCount; i++) { - areaXCoords[i] = area.m_edges[i]->m_pos.X; - areaYCoords[i] = area.m_edges[i]->m_pos.Y; - } - pointInArea = pnpoly(areaPointCount, areaXCoords, areaYCoords, x, y); - if (pointInArea) { - break; + z = calcZ(area.m_edges[0]->m_pos, area.m_edges[1]->m_pos, area.m_edges[2]->m_pos, x, y) + 0.1; + if (z > (minZ - zSpacing * .8) && z < (maxZ + zSpacing * .8)) { + float areaXCoords[10]; + float areaYCoords[10]; + for (int i = 0; i < areaPointCount; i++) { + areaXCoords[i] = area.m_edges[i]->m_pos.X; + areaYCoords[i] = area.m_edges[i]->m_pos.Y; + } + pointInArea = pnpoly(areaPointCount, areaXCoords, areaYCoords, x, y); + if (pointInArea) { + break; + } } } xRow.push_back(pointInArea ? wayPointIndex++ : 65535); @@ -291,7 +341,7 @@ void ReasoningGrid::build(NavPower::NavMesh* navMesh, BuildContext* ctx) { waypoint.vPos.w = 1.0; waypoint.nVisionDataOffset = 0; waypoint.nLayerIndex = 0; - m_WaypointList.push_back(waypoint); + airg->m_WaypointList.push_back(waypoint); } } yRow.push_back(xRow); @@ -299,8 +349,8 @@ void ReasoningGrid::build(NavPower::NavMesh* navMesh, BuildContext* ctx) { grid.push_back(yRow); } - m_nNodeCount = m_WaypointList.size(); - m_deadEndData.m_nSize = m_nNodeCount; + airg->m_nNodeCount = airg->m_WaypointList.size(); + airg->m_deadEndData.m_nSize = airg->m_nNodeCount; // Neighbors: South is 0, increases CCW std::pair gridIndexDiff[8]{ std::pair(0, -1), @@ -326,12 +376,14 @@ void ReasoningGrid::build(NavPower::NavMesh* navMesh, BuildContext* ctx) { nyi >= 0 && nyi < gridYSize) { neighborWaypointIndex = grid[zi][nyi][nxi]; } - m_WaypointList[waypointIndex].nNeighbors.push_back(neighborWaypointIndex); + airg->m_WaypointList[waypointIndex].nNeighbors.push_back(neighborWaypointIndex); } } } } } - std::vector visibilityData(m_nNodeCount * 1001); - m_pVisibilityData = visibilityData; + std::vector visibilityData(airg->m_nNodeCount * 1001); + airg->m_pVisibilityData = visibilityData; + navKit->log(RC_LOG_PROGRESS, "Done building Airg."); + navKit->airg->airgLoaded = true; } \ No newline at end of file diff --git a/src/RecastDemo/Sample.cpp b/src/RecastDemo/Sample.cpp index df9912d..8e3f944 100644 --- a/src/RecastDemo/Sample.cpp +++ b/src/RecastDemo/Sample.cpp @@ -188,7 +188,7 @@ void Sample::resetCommonSettings() m_regionMergeSize = 30; m_edgeMaxLen = 500.0f; m_edgeMaxError = 1.4f; - m_vertsPerPoly = 6.0f; + m_vertsPerPoly = 3.0f; m_detailSampleDist = 1.5f; m_detailSampleMaxError = 1.4f; m_partitionType = SAMPLE_PARTITION_WATERSHED;