diff --git a/src/bsp/Bsp.cpp b/src/bsp/Bsp.cpp index 47f9f8fc..5a62b0a2 100644 --- a/src/bsp/Bsp.cpp +++ b/src/bsp/Bsp.cpp @@ -91,6 +91,10 @@ Bsp::~Bsp() for (int i = 0; i < ents.size(); i++) delete ents[i]; + + if (pvsFaces) { + delete[] pvsFaces; + } } void Bsp::get_bounding_box(vec3& mins, vec3& maxs) { @@ -4103,6 +4107,63 @@ bool Bsp::is_leaf_visible(int ileaf, vec3 pos) { return isVisible; } +bool Bsp::is_face_visible(int faceIdx, vec3 pos, vec3 angles) { + BSPFACE& face = faces[faceIdx]; + BSPPLANE& plane = planes[face.iPlane]; + vec3 normal = plane.vNormal; + + // TODO: is it in the frustrum? Is it part of an entity model? If so is the entity linked in the PVS? + // is it facing the camera? Is it a special face? + + return true; +} + +int Bsp::count_visible_polys(vec3 pos, vec3 angles) { + int ipvsLeaf = get_leaf(pos); + BSPLEAF& pvsLeaf = leaves[ipvsLeaf]; + + int p = pvsLeaf.nVisOffset; // pvs offset + byte* pvs = lumps[LUMP_VISIBILITY]; + + bool isVisible = false; + int numVisible = 0; + + if (ipvsLeaf == 0) { + return faceCount; + } + + memset(pvsFaces, 0, pvsFaceCount*sizeof(bool)); + int renderFaceCount = 0; + + for (int lf = 1; lf < leafCount; p++) + { + if (pvs[p] == 0) // prepare to skip leafs + lf += 8 * pvs[++p]; // next byte holds number of leafs to skip + else + { + for (byte bit = 1; bit != 0; bit *= 2, lf++) + { + if ((pvs[p] & bit) && lf < leafCount) // leaf is flagged as visible + { + numVisible++; + BSPLEAF& leaf = leaves[lf]; + + for (int i = 0; i < leaf.nMarkSurfaces; i++) { + int faceIdx = marksurfs[leaf.iFirstMarkSurface + i]; + if (!pvsFaces[faceIdx]) { + pvsFaces[faceIdx] = true; + if (is_face_visible(faceIdx, pos, angles)) + renderFaceCount++; + } + } + } + } + } + } + + return renderFaceCount; +} + void Bsp::mark_face_structures(int iFace, STRUCTUSAGE* usage) { BSPFACE& face = faces[iFace]; usage->faces[iFace] = true; @@ -5621,6 +5682,15 @@ void Bsp::update_lump_pointers() { if (textureCount > g_limits.max_textures) logf("Overflowed textures !!!\n"); if (lightDataLength > g_limits.max_lightdata) logf("Overflowed lightdata !!!\n"); if (visDataLength > g_limits.max_visdata) logf("Overflowed visdata !!!\n"); + + if (pvsFaceCount != faceCount) { + pvsFaceCount = faceCount; + + if (pvsFaces) { + delete[] pvsFaces; + } + pvsFaces = new bool[pvsFaceCount]; + } } void Bsp::replace_lump(int lumpIdx, void* newData, int newLength) { diff --git a/src/bsp/Bsp.h b/src/bsp/Bsp.h index e677c9a1..23412aab 100644 --- a/src/bsp/Bsp.h +++ b/src/bsp/Bsp.h @@ -97,6 +97,10 @@ class Bsp // returns true if leaf is in the PVS from the given position bool is_leaf_visible(int ileaf, vec3 pos); + bool is_face_visible(int faceIdx, vec3 pos, vec3 angles); + + int count_visible_polys(vec3 pos, vec3 angles); + // get leaf index from world position int get_leaf(vec3 pos); @@ -296,6 +300,9 @@ class Bsp void update_lump_pointers(); private: + bool* pvsFaces = NULL; // flags which faces are marked for rendering in the PVS + int pvsFaceCount = 0; + int remove_unused_lightmaps(bool* usedFaces); int remove_unused_visdata(STRUCTREMAP* remap, BSPLEAF* oldLeaves, int oldLeafCount, int oldWorldspawnLeafCount); // called after removing unused leaves int remove_unused_textures(bool* usedTextures, int* remappedIndexes); diff --git a/src/editor/Gui.cpp b/src/editor/Gui.cpp index 8f242fb6..b9a607cb 100644 --- a/src/editor/Gui.cpp +++ b/src/editor/Gui.cpp @@ -1510,16 +1510,36 @@ void Gui::drawToolbar() { } void Gui::drawFpsOverlay() { + ImGuiContext& g = *GImGui; ImGuiIO& io = ImGui::GetIO(); ImVec2 window_pos = ImVec2(io.DisplaySize.x - 10.0f, 35.0f); ImVec2 window_pos_pivot = ImVec2(1.0f, 0.0f); ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background + if (ImGui::Begin("Overlay", 0, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) { - ImGui::Text("%.0f FPS", ImGui::GetIO().Framerate); + int faceCount = 0; + + if (polycount && g_app->mapRenderers.size()) { + Bsp* map = g_app->mapRenderers[0]->map; + faceCount = map->count_visible_polys(g_app->cameraOrigin, g_app->cameraAngles); + + ImGui::Text("%d Polys %.0f FPS", faceCount, ImGui::GetIO().Framerate); + } + else { + ImGui::Text("%.0f FPS", ImGui::GetIO().Framerate); + } + if (ImGui::BeginPopupContextWindow()) { + /* + if (ImGui::MenuItem("Poly Counter", NULL, polycount)) { + polycount = !polycount; + } + tooltip(g, "Count rendered polygons in the PVS."); + */ + if (ImGui::MenuItem("VSync", NULL, vsync)) { vsync = !vsync; glfwSwapInterval(vsync ? 1 : 0); diff --git a/src/editor/Gui.h b/src/editor/Gui.h index 51d6d5f5..1ce3c978 100644 --- a/src/editor/Gui.h +++ b/src/editor/Gui.h @@ -52,6 +52,7 @@ class Gui { private: bool vsync = true; + bool polycount = false; bool showDebugWidget = false; bool showKeyvalueWidget = false; bool showTransformWidget = false;