From f462db6bfa83d27d3a6a08cb7602015c8b8a62e4 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 11 Mar 2026 01:29:56 -0700 Subject: [PATCH] fix: terrain descriptor pool leak, minimap quest markers, and item comparison UI - terrain_renderer: add FREE_DESCRIPTOR_SET_BIT flag and vkFreeDescriptorSets in destroyChunkGPU so material descriptor sets are returned to the pool; prevents GPU device lost from pool exhaustion near populated areas - game_screen: fix projectToMinimap to use the exact inverse of the minimap shader transform so quest objective markers appear at the correct position and orientation regardless of camera bearing - inventory_screen: fix item comparison tooltip to not compare equipped items against themselves (character screen); add item level diff line; show (=) indicator when stats are equal rather than bare value which looked identical to the item's own tooltip --- src/rendering/terrain_renderer.cpp | 5 +++++ src/ui/game_screen.cpp | 11 +++++++---- src/ui/inventory_screen.cpp | 22 ++++++++++++++++++++-- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/rendering/terrain_renderer.cpp b/src/rendering/terrain_renderer.cpp index 4e8593f5..3af644cf 100644 --- a/src/rendering/terrain_renderer.cpp +++ b/src/rendering/terrain_renderer.cpp @@ -89,6 +89,7 @@ bool TerrainRenderer::initialize(VkContext* ctx, VkDescriptorSetLayout perFrameL VkDescriptorPoolCreateInfo poolInfo{}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; poolInfo.maxSets = MAX_MATERIAL_SETS; poolInfo.poolSizeCount = 2; poolInfo.pPoolSizes = poolSizes; @@ -1034,6 +1035,10 @@ void TerrainRenderer::destroyChunkGPU(TerrainChunkGPU& chunk) { destroyBuffer(allocator, ab); chunk.paramsUBO = VK_NULL_HANDLE; } + // Return material descriptor set to the pool so it can be reused by new chunks + if (chunk.materialSet && materialDescPool) { + vkFreeDescriptorSets(vkCtx->getDevice(), materialDescPool, 1, &chunk.materialSet); + } chunk.materialSet = VK_NULL_HANDLE; // Destroy owned alpha textures (VkTexture::~VkTexture is a no-op, must call destroy() explicitly) diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index e1e064fc..71681c84 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -9406,10 +9406,13 @@ void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) { float dx = worldRenderPos.x - playerRender.x; float dy = worldRenderPos.y - playerRender.y; - // Match minimap shader transform exactly. - // Render axes: +X=west, +Y=north. Minimap screen axes: +X=right(east), +Y=down(south). - float rx = -dx * cosB + dy * sinB; - float ry = -dx * sinB - dy * cosB; + // Exact inverse of minimap display shader: + // shader: mapUV = playerUV + vec2(-rotated.x, rotated.y) * zoom * 2 + // where rotated = R(bearing) * center, center in [-0.5, 0.5] + // Inverse: center = R^-1(bearing) * (-deltaUV.x, deltaUV.y) / (zoom*2) + // With deltaUV.x ∝ +dx (render +X=west=larger U) and deltaUV.y ∝ -dy (V increases south): + float rx = -(dx * cosB + dy * sinB); + float ry = dx * sinB - dy * cosB; // Scale to minimap pixels float px = rx / viewRadius * mapRadius; diff --git a/src/ui/inventory_screen.cpp b/src/ui/inventory_screen.cpp index 8ceb64a5..0bb2c8c3 100644 --- a/src/ui/inventory_screen.cpp +++ b/src/ui/inventory_screen.cpp @@ -1722,7 +1722,9 @@ void InventoryScreen::renderItemSlot(game::Inventory& inventory, const game::Ite } if (ImGui::IsItemHovered() && !holdingItem) { - renderItemTooltip(item, &inventory); + // Pass inventory for backpack/bag items only; equipped items compare against themselves otherwise + const game::Inventory* tooltipInv = (kind == SlotKind::EQUIPMENT) ? nullptr : &inventory; + renderItemTooltip(item, tooltipInv); } } } @@ -1968,6 +1970,22 @@ void InventoryScreen::renderItemTooltip(const game::ItemDef& item, const game::I } ImGui::TextColored(getQualityColor(eq->item.quality), "%s", eq->item.name.c_str()); + // Item level comparison (always shown when different) + if (eq->item.itemLevel > 0 || item.itemLevel > 0) { + char ilvlBuf[64]; + float diff = static_cast(item.itemLevel) - static_cast(eq->item.itemLevel); + if (diff > 0.0f) + std::snprintf(ilvlBuf, sizeof(ilvlBuf), "Item Level: %u (▲%.0f)", item.itemLevel, diff); + else if (diff < 0.0f) + std::snprintf(ilvlBuf, sizeof(ilvlBuf), "Item Level: %u (▼%.0f)", item.itemLevel, -diff); + else + std::snprintf(ilvlBuf, sizeof(ilvlBuf), "Item Level: %u (=)", item.itemLevel); + ImVec4 ilvlColor = (diff > 0.0f) ? ImVec4(0.0f, 1.0f, 0.0f, 1.0f) + : (diff < 0.0f) ? ImVec4(1.0f, 0.3f, 0.3f, 1.0f) + : ImVec4(0.7f, 0.7f, 0.7f, 1.0f); + ImGui::TextColored(ilvlColor, "%s", ilvlBuf); + } + // Helper: render a numeric stat diff line auto showDiff = [](const char* label, float newVal, float eqVal) { if (newVal == 0.0f && eqVal == 0.0f) return; @@ -1980,7 +1998,7 @@ void InventoryScreen::renderItemTooltip(const game::ItemDef& item, const game::I std::snprintf(buf, sizeof(buf), "%s: %.0f (▼%.0f)", label, newVal, -diff); ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "%s", buf); } else { - std::snprintf(buf, sizeof(buf), "%s: %.0f", label, newVal); + std::snprintf(buf, sizeof(buf), "%s: %.0f (=)", label, newVal); ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "%s", buf); } };