mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-02 07:43:51 +00:00
refactor: decompose world map into modular component architecture
Break the monolithic 1360-line world_map.cpp into 16 focused modules under src/rendering/world_map/: Architecture: - world_map_facade: public API composing all components (PIMPL) - world_map_types: Vulkan-free domain types (Zone, ViewLevel, etc.) - data_repository: DBC zone loading, ZMP pixel map, POI/overlay storage - coordinate_projection: UV projection, zone/continent lookups - composite_renderer: Vulkan tile pipeline + off-screen compositing - exploration_state: server mask + local exploration tracking - view_state_machine: COSMIC→WORLD→CONTINENT→ZONE navigation - input_handler: keyboard/mouse input → InputAction mapping - overlay_renderer: layer-based ImGui overlay system (OCP) - map_resolver: cross-map navigation (Outland, Northrend, etc.) - zone_metadata: level ranges and faction data Overlay layers (each an IOverlayLayer): - player_marker, party_dot, taxi_node, poi_marker, quest_poi, corpse_marker, zone_highlight, coordinate_display, subzone_tooltip Fixes: - Player marker no longer bleeds across continents (only shown when player is in a zone belonging to the displayed continent) - Zone hover uses DBC-projected AABB rectangles (restored from original working behavior) - Exploration overlay rendering for zone view subzones Tests: - 6 new test files covering coordinate projection, exploration state, map resolver, view state machine, zone metadata, and integration Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
This commit is contained in:
parent
db3f65a87e
commit
fff06fc932
55 changed files with 6335 additions and 1542 deletions
|
|
@ -1,174 +1,23 @@
|
|||
// world_map.hpp — Shim header for backward compatibility.
|
||||
// Redirects to the modular world_map/world_map_facade.hpp.
|
||||
// Consumers should migrate to #include "rendering/world_map/world_map_facade.hpp" directly.
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include "rendering/world_map/world_map_facade.hpp"
|
||||
|
||||
namespace wowee {
|
||||
namespace pipeline { class AssetManager; }
|
||||
namespace rendering {
|
||||
|
||||
class VkContext;
|
||||
class VkTexture;
|
||||
class VkRenderTarget;
|
||||
// Backward-compatible type aliases for old consumer code
|
||||
// (game_screen_hud.cpp, renderer.cpp, etc.)
|
||||
using WorldMapPartyDot = world_map::PartyDot;
|
||||
using WorldMapTaxiNode = world_map::TaxiNode;
|
||||
using MapPOI = world_map::POI;
|
||||
|
||||
/// Party member dot passed in from the UI layer for world map overlay.
|
||||
struct WorldMapPartyDot {
|
||||
glm::vec3 renderPos; ///< Position in render-space coordinates
|
||||
uint32_t color; ///< RGBA packed color (IM_COL32 format)
|
||||
std::string name; ///< Member name (shown as tooltip on hover)
|
||||
};
|
||||
|
||||
/// Taxi (flight master) node passed from the UI layer for world map overlay.
|
||||
struct WorldMapTaxiNode {
|
||||
uint32_t id = 0; ///< TaxiNodes.dbc ID
|
||||
uint32_t mapId = 0; ///< WoW internal map ID (0=EK,1=Kal,530=Outland,571=Northrend)
|
||||
float wowX = 0, wowY = 0, wowZ = 0; ///< Canonical WoW coordinates
|
||||
std::string name; ///< Node name (shown as tooltip)
|
||||
bool known = false; ///< Player has discovered this node
|
||||
};
|
||||
|
||||
struct WorldMapZone {
|
||||
uint32_t wmaID = 0;
|
||||
uint32_t areaID = 0; // 0 = continent level
|
||||
std::string areaName; // texture folder name (from DBC)
|
||||
float locLeft = 0, locRight = 0, locTop = 0, locBottom = 0;
|
||||
uint32_t displayMapID = 0;
|
||||
uint32_t parentWorldMapID = 0;
|
||||
std::vector<uint32_t> exploreBits; // all AreaBit indices (zone + subzones)
|
||||
|
||||
// Per-zone cached textures (owned by WorldMap::zoneTextures)
|
||||
VkTexture* tileTextures[12] = {};
|
||||
bool tilesLoaded = false;
|
||||
};
|
||||
|
||||
class WorldMap {
|
||||
public:
|
||||
WorldMap();
|
||||
~WorldMap();
|
||||
|
||||
bool initialize(VkContext* ctx, pipeline::AssetManager* assetManager);
|
||||
void shutdown();
|
||||
|
||||
/// Off-screen composite pass — call BEFORE the main render pass begins.
|
||||
void compositePass(VkCommandBuffer cmd);
|
||||
|
||||
/// ImGui overlay — call INSIDE the main render pass (during ImGui frame).
|
||||
void render(const glm::vec3& playerRenderPos, int screenWidth, int screenHeight,
|
||||
float playerYawDeg = 0.0f);
|
||||
|
||||
void setMapName(const std::string& name);
|
||||
void setServerExplorationMask(const std::vector<uint32_t>& masks, bool hasData);
|
||||
void setPartyDots(std::vector<WorldMapPartyDot> dots) { partyDots_ = std::move(dots); }
|
||||
void setTaxiNodes(std::vector<WorldMapTaxiNode> nodes) { taxiNodes_ = std::move(nodes); }
|
||||
|
||||
/// Quest POI marker for world map overlay (from SMSG_QUEST_POI_QUERY_RESPONSE).
|
||||
struct QuestPoi {
|
||||
float wowX = 0, wowY = 0; ///< Canonical WoW coordinates (centroid of POI area)
|
||||
std::string name; ///< Quest title
|
||||
};
|
||||
void setQuestPois(std::vector<QuestPoi> pois) { questPois_ = std::move(pois); }
|
||||
/// Set the player's corpse position for overlay rendering.
|
||||
/// @param hasCorpse True when the player is a ghost with an unclaimed corpse on this map.
|
||||
/// @param renderPos Corpse position in render-space coordinates.
|
||||
void setCorpsePos(bool hasCorpse, glm::vec3 renderPos) {
|
||||
hasCorpse_ = hasCorpse;
|
||||
corpseRenderPos_ = renderPos;
|
||||
}
|
||||
bool isOpen() const { return open; }
|
||||
void close() { open = false; }
|
||||
|
||||
private:
|
||||
enum class ViewLevel { WORLD, CONTINENT, ZONE };
|
||||
|
||||
void enterWorldView();
|
||||
void loadZonesFromDBC();
|
||||
int findBestContinentForPlayer(const glm::vec3& playerRenderPos) const;
|
||||
int findZoneForPlayer(const glm::vec3& playerRenderPos) const;
|
||||
bool zoneBelongsToContinent(int zoneIdx, int contIdx) const;
|
||||
bool getContinentProjectionBounds(int contIdx, float& left, float& right,
|
||||
float& top, float& bottom) const;
|
||||
void loadZoneTextures(int zoneIdx);
|
||||
void requestComposite(int zoneIdx);
|
||||
void renderImGuiOverlay(const glm::vec3& playerRenderPos, int screenWidth, int screenHeight,
|
||||
float playerYawDeg);
|
||||
void updateExploration(const glm::vec3& playerRenderPos);
|
||||
void zoomIn(const glm::vec3& playerRenderPos);
|
||||
void zoomOut();
|
||||
glm::vec2 renderPosToMapUV(const glm::vec3& renderPos, int zoneIdx) const;
|
||||
void destroyZoneTextures();
|
||||
|
||||
VkContext* vkCtx = nullptr;
|
||||
pipeline::AssetManager* assetManager = nullptr;
|
||||
bool initialized = false;
|
||||
bool open = false;
|
||||
|
||||
std::string mapName = "Azeroth";
|
||||
|
||||
// All zones for current map
|
||||
std::vector<WorldMapZone> zones;
|
||||
int continentIdx = -1;
|
||||
int currentIdx = -1;
|
||||
ViewLevel viewLevel = ViewLevel::CONTINENT;
|
||||
int compositedIdx = -1;
|
||||
int pendingCompositeIdx = -1;
|
||||
|
||||
// FBO replacement (4x3 tiles = 1024x768)
|
||||
static constexpr int GRID_COLS = 4;
|
||||
static constexpr int GRID_ROWS = 3;
|
||||
static constexpr int TILE_PX = 256;
|
||||
static constexpr int FBO_W = GRID_COLS * TILE_PX;
|
||||
static constexpr int FBO_H = GRID_ROWS * TILE_PX;
|
||||
|
||||
std::unique_ptr<VkRenderTarget> compositeTarget;
|
||||
|
||||
// Quad vertex buffer (pos2 + uv2)
|
||||
::VkBuffer quadVB = VK_NULL_HANDLE;
|
||||
VmaAllocation quadVBAlloc = VK_NULL_HANDLE;
|
||||
|
||||
// Descriptor resources
|
||||
VkDescriptorSetLayout samplerSetLayout = VK_NULL_HANDLE;
|
||||
VkDescriptorPool descPool = VK_NULL_HANDLE;
|
||||
static constexpr uint32_t MAX_DESC_SETS = 32;
|
||||
|
||||
// Tile composite pipeline
|
||||
VkPipeline tilePipeline = VK_NULL_HANDLE;
|
||||
VkPipelineLayout tilePipelineLayout = VK_NULL_HANDLE;
|
||||
VkDescriptorSet tileDescSets[2][12] = {}; // [frameInFlight][tileSlot]
|
||||
|
||||
// ImGui display descriptor set (points to composite render target)
|
||||
VkDescriptorSet imguiDisplaySet = VK_NULL_HANDLE;
|
||||
|
||||
// Texture storage (owns all VkTexture objects for zone tiles)
|
||||
std::vector<std::unique_ptr<VkTexture>> zoneTextures;
|
||||
|
||||
// Party member dots (set each frame from the UI layer)
|
||||
std::vector<WorldMapPartyDot> partyDots_;
|
||||
|
||||
// Taxi node markers (set each frame from the UI layer)
|
||||
std::vector<WorldMapTaxiNode> taxiNodes_;
|
||||
int currentMapId_ = -1; ///< WoW map ID currently loaded (set in loadZonesFromDBC)
|
||||
|
||||
// Quest POI markers (set each frame from the UI layer)
|
||||
std::vector<QuestPoi> questPois_;
|
||||
|
||||
// Corpse marker (ghost state — set each frame from the UI layer)
|
||||
bool hasCorpse_ = false;
|
||||
glm::vec3 corpseRenderPos_ = {};
|
||||
|
||||
// Exploration / fog of war
|
||||
std::vector<uint32_t> serverExplorationMask;
|
||||
bool hasServerExplorationMask = false;
|
||||
std::unordered_set<int> exploredZones;
|
||||
// Locally accumulated exploration (used as fallback when server mask is unavailable)
|
||||
std::unordered_set<int> locallyExploredZones_;
|
||||
};
|
||||
// WorldMap alias is already provided by world_map_facade.hpp:
|
||||
// using WorldMap = world_map::WorldMapFacade;
|
||||
// WorldMap::QuestPoi alias is provided inside WorldMapFacade:
|
||||
// using QuestPoi = QuestPOI;
|
||||
|
||||
} // namespace rendering
|
||||
} // namespace wowee
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue