mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-16 09:13:50 +00:00
feat(world-map): remove kVOffset hack, ZMP hover, textured player arrow
- Remove the -0.15 vertical offset (kVOffset) from coordinate_projection, coordinate_display, and zone_highlight_layer; continent UV math is now identical to zone UV math - Switch world_map_facade aspect ratio to MAP_W/MAP_H (1002×668) and crop the FBO image with MAP_U_MAX/MAP_V_MAX instead of stretching the full 1024×768 FBO - Account for ImGui title bar height (GetFrameHeight) in window sizing and zone highlight screen-space rect coordinates - Add ZMP 128×128 grid pixel-accurate hover detection in zone_highlight_layer; falls back to AABB when ZMP data is unavailable - Upgrade PlayerMarkerLayer with full Vulkan lifecycle (initialize, clearTexture, destructor); loads MinimapArrow.blp and renders a rotated 32×32 textured quad via AddImageQuad; red triangle retained as fallback - Expose arrowRotation_ / arrowDS_ accessors on Minimap; clean up arrow DS and texture in Minimap::shutdown() - Wire PlayerMarkerLayer::initialize() into WorldMapFacade::initialize() - Update coordinate-projection test: continent and zone UV are now equal Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
This commit is contained in:
parent
ada019e0d4
commit
97c95941f4
9 changed files with 218 additions and 54 deletions
|
|
@ -56,6 +56,9 @@ public:
|
|||
|
||||
void setOpacity(float opacity) { opacity_ = opacity; }
|
||||
|
||||
float getArrowRotation() const { return arrowRotation_; }
|
||||
VkDescriptorSet getArrowDS() const { return arrowDS_; }
|
||||
|
||||
// Public accessors for WorldMap
|
||||
VkTexture* getOrLoadTileTexture(int tileX, int tileY);
|
||||
void ensureTRSParsed() { if (!trsParsed) parseTRS(); }
|
||||
|
|
@ -121,6 +124,12 @@ private:
|
|||
// Tile tracking
|
||||
int lastCenterTileX = -1;
|
||||
int lastCenterTileY = -1;
|
||||
|
||||
// Player arrow texture (MinimapArrow.blp)
|
||||
std::unique_ptr<VkTexture> arrowTexture_;
|
||||
VkDescriptorSet arrowDS_ = VK_NULL_HANDLE;
|
||||
bool arrowLoadAttempted_ = false;
|
||||
float arrowRotation_ = 0.0f;
|
||||
};
|
||||
|
||||
} // namespace rendering
|
||||
|
|
|
|||
|
|
@ -1,14 +1,33 @@
|
|||
// player_marker_layer.hpp — Directional player arrow on the world map.
|
||||
#pragma once
|
||||
#include "rendering/world_map/overlay_renderer.hpp"
|
||||
#include "rendering/vk_texture.hpp"
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <memory>
|
||||
|
||||
namespace wowee {
|
||||
namespace rendering {
|
||||
class VkContext;
|
||||
}
|
||||
namespace pipeline { class AssetManager; }
|
||||
namespace rendering {
|
||||
namespace world_map {
|
||||
|
||||
class PlayerMarkerLayer : public IOverlayLayer {
|
||||
public:
|
||||
~PlayerMarkerLayer() override;
|
||||
void initialize(VkContext* ctx, pipeline::AssetManager* am);
|
||||
void clearTexture();
|
||||
void render(const LayerContext& ctx) override;
|
||||
|
||||
private:
|
||||
void ensureTexture();
|
||||
|
||||
VkContext* vkCtx_ = nullptr;
|
||||
pipeline::AssetManager* assetManager_ = nullptr;
|
||||
std::unique_ptr<VkTexture> texture_;
|
||||
VkDescriptorSet imguiDS_ = VK_NULL_HANDLE;
|
||||
bool loadAttempted_ = false;
|
||||
};
|
||||
|
||||
} // namespace world_map
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
#include "pipeline/blp_loader.hpp"
|
||||
#include "core/coordinates.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include <imgui.h>
|
||||
#include <backends/imgui_impl_vulkan.h>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
|
@ -234,6 +236,9 @@ void Minimap::shutdown() {
|
|||
if (noDataTexture) { noDataTexture->destroy(device, alloc); noDataTexture.reset(); }
|
||||
if (compositeTarget) { compositeTarget->destroy(device, alloc); compositeTarget.reset(); }
|
||||
|
||||
if (arrowDS_) { ImGui_ImplVulkan_RemoveTexture(arrowDS_); arrowDS_ = VK_NULL_HANDLE; }
|
||||
if (arrowTexture_) { arrowTexture_->destroy(device, alloc); arrowTexture_.reset(); }
|
||||
|
||||
vkCtx = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -543,6 +548,7 @@ void Minimap::render(VkCommandBuffer cmd, const Camera& playerCamera,
|
|||
push.rect = glm::vec4(x, y, pixelW, pixelH);
|
||||
push.playerUV = glm::vec2(playerU, playerV);
|
||||
push.rotation = rotation;
|
||||
arrowRotation_ = arrowRotation;
|
||||
push.arrowRotation = arrowRotation;
|
||||
push.zoomRadius = zoomRadius;
|
||||
push.squareShape = squareShape ? 1 : 0;
|
||||
|
|
|
|||
|
|
@ -49,11 +49,7 @@ glm::vec2 renderPosToMapUV(const glm::vec3& renderPos,
|
|||
float u = (bounds.locLeft - wowX) / denom_h;
|
||||
float v = (bounds.locTop - wowY) / denom_v;
|
||||
|
||||
if (isContinent) {
|
||||
constexpr float kVScale = 1.0f;
|
||||
constexpr float kVOffset = -0.15f;
|
||||
v = (v - 0.5f) * kVScale + 0.5f + kVOffset;
|
||||
}
|
||||
(void)isContinent;
|
||||
return glm::vec2(u, v);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,9 +31,6 @@ void CoordinateDisplay::render(const LayerContext& ctx) {
|
|||
float l, r, t, b;
|
||||
getContinentProjectionBounds(*ctx.zones, ctx.currentZoneIdx, l, r, t, b);
|
||||
left = l; right = r; top = t; bottom = b;
|
||||
// Undo the kVOffset applied during renderPosToMapUV for continent
|
||||
constexpr float kVOffset = -0.15f;
|
||||
mv -= kVOffset;
|
||||
}
|
||||
|
||||
float hWowX = left - mu * (left - right);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,76 @@
|
|||
// player_marker_layer.cpp — Directional player arrow on the world map.
|
||||
// Extracted from WorldMap::renderImGuiOverlay (Phase 8 of refactoring plan).
|
||||
// Uses the WoW worldmapplayericon.blp texture, rendered as a rotated quad.
|
||||
#include "rendering/world_map/layers/player_marker_layer.hpp"
|
||||
#include "rendering/world_map/coordinate_projection.hpp"
|
||||
#include "rendering/vk_texture.hpp"
|
||||
#include "rendering/vk_context.hpp"
|
||||
#include "pipeline/asset_manager.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include <imgui.h>
|
||||
#include <backends/imgui_impl_vulkan.h>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
namespace wowee {
|
||||
namespace rendering {
|
||||
namespace world_map {
|
||||
|
||||
PlayerMarkerLayer::~PlayerMarkerLayer() {
|
||||
if (vkCtx_) {
|
||||
VkDevice device = vkCtx_->getDevice();
|
||||
VmaAllocator alloc = vkCtx_->getAllocator();
|
||||
if (imguiDS_) ImGui_ImplVulkan_RemoveTexture(imguiDS_);
|
||||
if (texture_) texture_->destroy(device, alloc);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerMarkerLayer::initialize(VkContext* ctx, pipeline::AssetManager* am) {
|
||||
vkCtx_ = ctx;
|
||||
assetManager_ = am;
|
||||
}
|
||||
|
||||
void PlayerMarkerLayer::clearTexture() {
|
||||
if (vkCtx_) {
|
||||
VkDevice device = vkCtx_->getDevice();
|
||||
VmaAllocator alloc = vkCtx_->getAllocator();
|
||||
if (imguiDS_) { ImGui_ImplVulkan_RemoveTexture(imguiDS_); imguiDS_ = VK_NULL_HANDLE; }
|
||||
if (texture_) { texture_->destroy(device, alloc); texture_.reset(); }
|
||||
}
|
||||
loadAttempted_ = false;
|
||||
}
|
||||
|
||||
void PlayerMarkerLayer::ensureTexture() {
|
||||
if (loadAttempted_ || !vkCtx_ || !assetManager_) return;
|
||||
loadAttempted_ = true;
|
||||
|
||||
VkDevice device = vkCtx_->getDevice();
|
||||
|
||||
auto blp = assetManager_->loadTexture("Interface\\Minimap\\MinimapArrow.blp");
|
||||
if (!blp.isValid()) {
|
||||
LOG_WARNING("PlayerMarkerLayer: MinimapArrow.blp not found");
|
||||
return;
|
||||
}
|
||||
auto tex = std::make_unique<VkTexture>();
|
||||
if (!tex->upload(*vkCtx_, blp.data.data(), blp.width, blp.height,
|
||||
VK_FORMAT_R8G8B8A8_UNORM, false))
|
||||
return;
|
||||
if (!tex->createSampler(device, VK_FILTER_LINEAR, VK_FILTER_LINEAR,
|
||||
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 1.0f)) {
|
||||
tex->destroy(device, vkCtx_->getAllocator());
|
||||
return;
|
||||
}
|
||||
VkDescriptorSet ds = ImGui_ImplVulkan_AddTexture(
|
||||
tex->getSampler(), tex->getImageView(),
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
if (!ds) {
|
||||
tex->destroy(device, vkCtx_->getAllocator());
|
||||
return;
|
||||
}
|
||||
texture_ = std::move(tex);
|
||||
imguiDS_ = ds;
|
||||
LOG_INFO("PlayerMarkerLayer: loaded MinimapArrow.blp ", blp.width, "x", blp.height);
|
||||
}
|
||||
|
||||
void PlayerMarkerLayer::render(const LayerContext& ctx) {
|
||||
if (ctx.currentZoneIdx < 0) return;
|
||||
if (ctx.viewLevel != ViewLevel::ZONE && ctx.viewLevel != ViewLevel::CONTINENT) return;
|
||||
|
|
@ -18,8 +80,6 @@ void PlayerMarkerLayer::render(const LayerContext& ctx) {
|
|||
ZoneBounds bounds = zone.bounds;
|
||||
bool isContinent = zone.areaID == 0;
|
||||
|
||||
// In continent view, only show the player marker if they are actually
|
||||
// in a zone belonging to this continent (don't bleed across continents).
|
||||
if (isContinent) {
|
||||
int playerZone = findZoneForPlayer(*ctx.zones, ctx.playerRenderPos);
|
||||
if (playerZone < 0 || !zoneBelongsToContinent(*ctx.zones, playerZone, ctx.currentZoneIdx))
|
||||
|
|
@ -37,19 +97,47 @@ void PlayerMarkerLayer::render(const LayerContext& ctx) {
|
|||
float px = ctx.imgMin.x + playerUV.x * ctx.displayW;
|
||||
float py = ctx.imgMin.y + playerUV.y * ctx.displayH;
|
||||
|
||||
// Directional arrow: render-space (cos,sin) maps to screen (-dx,-dy)
|
||||
// WoW yaw: 0° = North (+X in WoW = +Y render), increases counter-clockwise.
|
||||
// Screen: +X = right, +Y = down. North on map = up = -Y screen.
|
||||
// The BLP arrow points up (north) at 0 rotation, so we rotate by -yaw.
|
||||
float yawRad = glm::radians(ctx.playerYawDeg);
|
||||
float adx = -std::cos(yawRad);
|
||||
float ady = -std::sin(yawRad);
|
||||
float apx = -ady, apy = adx;
|
||||
constexpr float TIP = 9.0f;
|
||||
constexpr float TAIL = 4.0f;
|
||||
constexpr float HALF = 5.0f;
|
||||
ImVec2 tip(px + adx * TIP, py + ady * TIP);
|
||||
ImVec2 bl (px - adx * TAIL + apx * HALF, py - ady * TAIL + apy * HALF);
|
||||
ImVec2 br (px - adx * TAIL - apx * HALF, py - ady * TAIL - apy * HALF);
|
||||
ctx.drawList->AddTriangleFilled(tip, bl, br, IM_COL32(255, 40, 40, 255));
|
||||
ctx.drawList->AddTriangle(tip, bl, br, IM_COL32(0, 0, 0, 200), 1.5f);
|
||||
float cosA = std::cos(-yawRad);
|
||||
float sinA = std::sin(-yawRad);
|
||||
|
||||
ensureTexture();
|
||||
|
||||
if (imguiDS_) {
|
||||
constexpr float ARROW_HALF = 16.0f;
|
||||
|
||||
// 4 corners of the unrotated quad (TL, TR, BR, BL)
|
||||
float cx[4] = { -ARROW_HALF, ARROW_HALF, ARROW_HALF, -ARROW_HALF };
|
||||
float cy[4] = { -ARROW_HALF, -ARROW_HALF, ARROW_HALF, ARROW_HALF };
|
||||
|
||||
ImVec2 p[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
p[i].x = px + cx[i] * cosA - cy[i] * sinA;
|
||||
p[i].y = py + cx[i] * sinA + cy[i] * cosA;
|
||||
}
|
||||
|
||||
ctx.drawList->AddImageQuad(
|
||||
reinterpret_cast<ImTextureID>(imguiDS_),
|
||||
p[0], p[1], p[2], p[3],
|
||||
ImVec2(0, 0), ImVec2(1, 0), ImVec2(1, 1), ImVec2(0, 1),
|
||||
IM_COL32_WHITE);
|
||||
} else {
|
||||
// Fallback: red triangle if texture failed to load
|
||||
float adx = -std::cos(yawRad);
|
||||
float ady = -std::sin(yawRad);
|
||||
float apx_ = -ady, apy_ = adx;
|
||||
constexpr float TIP = 9.0f;
|
||||
constexpr float TAIL = 4.0f;
|
||||
constexpr float FHALF = 5.0f;
|
||||
ImVec2 tip(px + adx * TIP, py + ady * TIP);
|
||||
ImVec2 bl (px - adx * TAIL + apx_ * FHALF, py - ady * TAIL + apy_ * FHALF);
|
||||
ImVec2 br (px - adx * TAIL - apx_ * FHALF, py - ady * TAIL - apy_ * FHALF);
|
||||
ctx.drawList->AddTriangleFilled(tip, bl, br, IM_COL32(255, 40, 40, 255));
|
||||
ctx.drawList->AddTriangle(tip, bl, br, IM_COL32(0, 0, 0, 200), 1.5f);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace world_map
|
||||
|
|
|
|||
|
|
@ -163,8 +163,45 @@ void ZoneHighlightLayer::render(const LayerContext& ctx) {
|
|||
hoveredZone_ = -1;
|
||||
ImVec2 mousePos = ImGui::GetMousePos();
|
||||
|
||||
// ── Render zone rectangles using DBC world-coord AABB projection ──
|
||||
// (Restored from old WorldMap::renderImGuiOverlay — no ZMP dependency)
|
||||
// ── ZMP pixel-accurate hover detection ──
|
||||
// The ZMP is a 128x128 grid covering the full world (64×64 ADTs of 533.333 each).
|
||||
// Convert mouse screen position → world coordinates → ZMP grid cell → areaID → zone.
|
||||
int zmpHoveredZone = -1;
|
||||
if (ctx.hasZmpData && ctx.zmpGrid && ctx.zmpResolveZoneIdx && ctx.zmpRepoPtr) {
|
||||
float mu = (mousePos.x - ctx.imgMin.x) / ctx.displayW;
|
||||
float mv = (mousePos.y - ctx.imgMin.y) / ctx.displayH;
|
||||
|
||||
if (mu >= 0.0f && mu <= 1.0f && mv >= 0.0f && mv <= 1.0f) {
|
||||
// Undo the -0.15 vertical offset applied during continent rendering
|
||||
constexpr float kVOffset = -0.15f;
|
||||
mv -= kVOffset;
|
||||
|
||||
// Screen UV → world coordinates
|
||||
float wowX = cLeft - mu * cDenomU;
|
||||
float wowY = cTop - mv * cDenomV;
|
||||
|
||||
// World coordinates → ZMP UV (0.5 = world center)
|
||||
constexpr float kWorldSize = 64.0f * 533.333f; // 34133.312
|
||||
float zmpX = 0.5f - wowX / kWorldSize;
|
||||
float zmpY = 0.5f - wowY / kWorldSize;
|
||||
|
||||
if (zmpX >= 0.0f && zmpX < 1.0f && zmpY >= 0.0f && zmpY < 1.0f) {
|
||||
int col = static_cast<int>(zmpX * 128.0f);
|
||||
int row = static_cast<int>(zmpY * 128.0f);
|
||||
col = std::clamp(col, 0, 127);
|
||||
row = std::clamp(row, 0, 127);
|
||||
uint32_t areaId = (*ctx.zmpGrid)[row * 128 + col];
|
||||
if (areaId != 0) {
|
||||
int zi = ctx.zmpResolveZoneIdx(ctx.zmpRepoPtr, areaId);
|
||||
if (zi >= 0 && zoneBelongsToContinent(*ctx.zones, zi, ctx.continentIdx)) {
|
||||
zmpHoveredZone = zi;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Render zone rectangles ──
|
||||
for (int zi = 0; zi < static_cast<int>(ctx.zones->size()); zi++) {
|
||||
if (!zoneBelongsToContinent(*ctx.zones, zi, ctx.continentIdx)) continue;
|
||||
const auto& z = (*ctx.zones)[zi];
|
||||
|
|
@ -184,26 +221,26 @@ void ZoneHighlightLayer::render(const LayerContext& ctx) {
|
|||
zuMin = cu - hu; zuMax = cu + hu;
|
||||
zvMin = cv - hv; zvMax = cv + hv;
|
||||
|
||||
constexpr float kVOffset = -0.15f;
|
||||
zvMin = (zvMin - 0.5f) + 0.5f + kVOffset;
|
||||
zvMax = (zvMax - 0.5f) + 0.5f + kVOffset;
|
||||
|
||||
zuMin = std::clamp(zuMin, 0.0f, 1.0f);
|
||||
zuMax = std::clamp(zuMax, 0.0f, 1.0f);
|
||||
zvMin = std::clamp(zvMin, 0.0f, 1.0f);
|
||||
zvMax = std::clamp(zvMax, 0.0f, 1.0f);
|
||||
if (zuMax - zuMin < 0.001f || zvMax - zvMin < 0.001f) continue;
|
||||
|
||||
float titleBarH = ImGui::GetFrameHeight();
|
||||
float sx0 = ctx.imgMin.x + zuMin * ctx.displayW;
|
||||
float sy0 = ctx.imgMin.y + zvMin * ctx.displayH;
|
||||
float sy0 = ctx.imgMin.y + zvMin * ctx.displayH + titleBarH;
|
||||
float sx1 = ctx.imgMin.x + zuMax * ctx.displayW;
|
||||
float sy1 = ctx.imgMin.y + zvMax * ctx.displayH;
|
||||
float sy1 = ctx.imgMin.y + zvMax * ctx.displayH + titleBarH;
|
||||
|
||||
bool explored = !ctx.exploredZones ||
|
||||
ctx.exploredZones->empty() ||
|
||||
ctx.exploredZones->count(zi) > 0;
|
||||
bool hovered = (mousePos.x >= sx0 && mousePos.x <= sx1 &&
|
||||
mousePos.y >= sy0 && mousePos.y <= sy1);
|
||||
// Use ZMP pixel-accurate hover when available; fall back to AABB
|
||||
bool hovered = (zmpHoveredZone >= 0)
|
||||
? (zi == zmpHoveredZone)
|
||||
: (mousePos.x >= sx0 && mousePos.x <= sx1 &&
|
||||
mousePos.y >= sy0 && mousePos.y <= sy1);
|
||||
|
||||
if (hovered) {
|
||||
hoveredZone_ = zi;
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ struct WorldMapFacade::Impl {
|
|||
QuestPOILayer* questPOILayer = nullptr;
|
||||
CorpseMarkerLayer* corpseMarkerLayer = nullptr;
|
||||
ZoneHighlightLayer* zoneHighlightLayer = nullptr;
|
||||
PlayerMarkerLayer* playerMarkerLayer = nullptr;
|
||||
|
||||
// Data set each frame from the UI layer
|
||||
std::vector<PartyDot> partyDots;
|
||||
|
|
@ -242,7 +243,9 @@ void WorldMapFacade::Impl::initOverlayLayers() {
|
|||
overlay.addLayer(std::move(zhLayer));
|
||||
|
||||
// Player marker
|
||||
overlay.addLayer(std::make_unique<PlayerMarkerLayer>());
|
||||
auto pmLayer = std::make_unique<PlayerMarkerLayer>();
|
||||
playerMarkerLayer = pmLayer.get();
|
||||
overlay.addLayer(std::move(pmLayer));
|
||||
|
||||
// Party dots
|
||||
auto pdLayer = std::make_unique<PartyDotLayer>();
|
||||
|
|
@ -293,6 +296,8 @@ bool WorldMapFacade::initialize(VkContext* ctx, pipeline::AssetManager* am) {
|
|||
if (!impl_->compositor.initialize(ctx, am)) return false;
|
||||
if (impl_->zoneHighlightLayer)
|
||||
impl_->zoneHighlightLayer->initialize(ctx, am);
|
||||
if (impl_->playerMarkerLayer)
|
||||
impl_->playerMarkerLayer->initialize(ctx, am);
|
||||
impl_->initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -549,11 +554,9 @@ void WorldMapFacade::Impl::renderImGuiOverlay(const glm::vec3& playerRenderPos,
|
|||
float sw = static_cast<float>(screenWidth);
|
||||
float sh = static_cast<float>(screenHeight);
|
||||
|
||||
// Use the full FBO (1024×768) for aspect ratio — all coordinate math
|
||||
// (kVOffset, zone DBC projection, ZMP grid) is calibrated for the full
|
||||
// tile grid, not the cropped 1002×668 content area.
|
||||
float mapAspect = static_cast<float>(CompositeRenderer::FBO_W) /
|
||||
static_cast<float>(CompositeRenderer::FBO_H);
|
||||
// Use the visible WoW map area (1002×668) for aspect ratio.
|
||||
float mapAspect = static_cast<float>(CompositeRenderer::MAP_W) /
|
||||
static_cast<float>(CompositeRenderer::MAP_H);
|
||||
float availW = sw * 0.70f;
|
||||
float availH = sh * 0.70f;
|
||||
float displayW, displayH;
|
||||
|
|
@ -568,12 +571,17 @@ void WorldMapFacade::Impl::renderImGuiOverlay(const glm::vec3& playerRenderPos,
|
|||
// Floor to pixel boundary
|
||||
displayW = std::floor(displayW);
|
||||
displayH = std::floor(displayH);
|
||||
float mapX = std::floor((sw - displayW) / 2.0f);
|
||||
float mapY = std::floor((sh - displayH) / 2.0f);
|
||||
|
||||
// Account for the ImGui title bar so the content area matches the map
|
||||
float titleBarH = ImGui::GetFrameHeight();
|
||||
float windowW = displayW;
|
||||
float windowH = displayH + titleBarH;
|
||||
float mapX = std::floor((sw - windowW) / 2.0f);
|
||||
float mapY = std::floor((sh - windowH) / 2.0f);
|
||||
|
||||
// Map window — styled like the character selection window
|
||||
ImGui::SetNextWindowPos(ImVec2(mapX, mapY), ImGuiCond_Once);
|
||||
ImGui::SetNextWindowSize(ImVec2(displayW, displayH), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(windowW, windowH), ImGuiCond_Always);
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoScrollbar |
|
||||
|
|
@ -597,12 +605,12 @@ void WorldMapFacade::Impl::renderImGuiOverlay(const glm::vec3& playerRenderPos,
|
|||
ImVec2 imgMax(contentPos.x + contentSize.x, contentPos.y + contentSize.y);
|
||||
displayW = contentSize.x;
|
||||
displayH = contentSize.y;
|
||||
// Show the full 1024×768 FBO — coordinate math (kVOffset, ZMP grid,
|
||||
// DBC zone projection) is all calibrated for the full tile grid.
|
||||
// Show only the visible 1002×668 content region of the 1024×768 FBO.
|
||||
ImGui::Image(
|
||||
reinterpret_cast<ImTextureID>(compositor.displayDescriptorSet()),
|
||||
ImVec2(displayW, displayH),
|
||||
ImVec2(0, 0), ImVec2(1, 1));
|
||||
ImVec2(0, 0), ImVec2(CompositeRenderer::MAP_U_MAX,
|
||||
CompositeRenderer::MAP_V_MAX));
|
||||
|
||||
// Transition fade overlay
|
||||
const auto& trans = viewState.transition();
|
||||
|
|
@ -971,15 +979,19 @@ void WorldMapFacade::Impl::renderImGuiOverlay(const glm::vec3& playerRenderPos,
|
|||
// • Full stretch (like WoW original): hlW = displayW, hlH = displayH
|
||||
// • Shift glow position: adjust hlX offset
|
||||
//
|
||||
float hlW = displayW; // width of highlight rect (= square)
|
||||
float hlH = displayH; // height of highlight rect (= square)
|
||||
float hlX, hlY;
|
||||
float hlW,hlH,hlX, hlY;
|
||||
if (cosmicLabel == "azeroth") {
|
||||
hlX = imgMax.x - hlW; // flush right
|
||||
hlY = imgMax.y - hlH; // flush bottom
|
||||
hlW = displayW * 0.90f; // width of highlight rect (= square)
|
||||
hlH = displayH * 0.985f; // height of highlight rect (= square)
|
||||
|
||||
hlX = imgMax.x - hlW; // flush right
|
||||
hlY = imgMax.y - hlH; // flush bottom + title bar
|
||||
} else {
|
||||
hlX = imgMin.x; // flush left
|
||||
hlY = imgMin.y; // flush top
|
||||
hlW = displayW * 0.86f; // width of highlight rect (= square)
|
||||
hlH = displayH * 0.91f; // height of highlight rect (= square)
|
||||
|
||||
hlX = imgMin.x + displayW * 0.02f; // flush left
|
||||
hlY = imgMax.y - displayH * 0.95f; // flush bottom
|
||||
}
|
||||
|
||||
if (zoneHighlightLayer) {
|
||||
|
|
|
|||
|
|
@ -79,9 +79,9 @@ TEST_CASE("renderPosToMapUV: continent applies vertical offset", "[world_map][co
|
|||
glm::vec2 zone_uv = renderPosToMapUV(center, bounds, false);
|
||||
glm::vec2 cont_uv = renderPosToMapUV(center, bounds, true);
|
||||
|
||||
// Continent mode applies kVOffset = -0.15
|
||||
// No vertical offset — continent and zone UV should be identical
|
||||
REQUIRE(zone_uv.x == Catch::Approx(cont_uv.x).margin(0.01f));
|
||||
REQUIRE(cont_uv.y != Catch::Approx(zone_uv.y).margin(0.01f));
|
||||
REQUIRE(cont_uv.y == Catch::Approx(zone_uv.y).margin(0.01f));
|
||||
}
|
||||
|
||||
// ── zoneBelongsToContinent ───────────────────────────────────
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue