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
This commit is contained in:
Kelsi 2026-03-11 01:29:56 -07:00
parent 568c566e1a
commit f462db6bfa
3 changed files with 32 additions and 6 deletions

View file

@ -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)

View file

@ -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;

View file

@ -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<float>(item.itemLevel) - static_cast<float>(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);
}
};