Add interactive world map with continent/zone navigation

This commit is contained in:
Kelsi 2026-02-04 22:27:45 -08:00
parent 47945451be
commit affcfcfce1
6 changed files with 1172 additions and 1 deletions

View file

@ -134,6 +134,7 @@ set(WOWEE_SOURCES
src/rendering/wmo_renderer.cpp
src/rendering/m2_renderer.cpp
src/rendering/minimap.cpp
src/rendering/world_map.cpp
src/rendering/swim_effects.cpp
src/rendering/loading_screen.cpp
@ -217,6 +218,7 @@ set(WOWEE_HEADERS
include/rendering/weather.hpp
include/rendering/lightning.hpp
include/rendering/swim_effects.hpp
include/rendering/world_map.hpp
include/rendering/character_renderer.hpp
include/rendering/wmo_renderer.hpp
include/rendering/loading_screen.hpp

View file

@ -34,9 +34,14 @@ public:
void setViewRadius(float radius) { viewRadius = radius; }
// Public accessors for WorldMap
GLuint getOrLoadTileTexture(int tileX, int tileY);
void ensureTRSParsed() { if (!trsParsed) parseTRS(); }
GLuint getTileQuadVAO() const { return tileQuadVAO; }
const std::string& getMapName() const { return mapName; }
private:
void parseTRS();
GLuint getOrLoadTileTexture(int tileX, int tileY);
void compositeTilesToFBO(const glm::vec3& centerWorldPos);
void renderQuad(const Camera& playerCamera, const glm::vec3& centerWorldPos,
int screenWidth, int screenHeight);

View file

@ -0,0 +1,86 @@
#pragma once
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <memory>
#include <string>
#include <vector>
namespace wowee {
namespace pipeline { class AssetManager; }
namespace rendering {
class Shader;
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;
// Per-zone cached textures
GLuint tileTextures[12] = {};
bool tilesLoaded = false;
};
class WorldMap {
public:
WorldMap();
~WorldMap();
void initialize(pipeline::AssetManager* assetManager);
void render(const glm::vec3& playerRenderPos, int screenWidth, int screenHeight);
void setMapName(const std::string& name);
bool isOpen() const { return open; }
void close() { open = false; }
private:
enum class ViewLevel { WORLD, CONTINENT, ZONE };
void createFBO();
void createTileShader();
void createQuad();
void enterWorldView();
void loadZonesFromDBC();
int findBestContinentForPlayer(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 compositeZone(int zoneIdx);
void renderImGuiOverlay(const glm::vec3& playerRenderPos, int screenWidth, int screenHeight);
// World pos → map UV using a specific zone's bounds
glm::vec2 renderPosToMapUV(const glm::vec3& renderPos, int zoneIdx) const;
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; // index of AreaID=0 entry in zones
int currentIdx = -1; // currently displayed zone index
ViewLevel viewLevel = ViewLevel::CONTINENT;
int compositedIdx = -1; // which zone is currently composited in FBO
// FBO for composited map (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; // 1024
static constexpr int FBO_H = GRID_ROWS * TILE_PX; // 768
GLuint fbo = 0;
GLuint fboTexture = 0;
std::unique_ptr<Shader> tileShader;
GLuint tileQuadVAO = 0;
GLuint tileQuadVBO = 0;
};
} // namespace rendering
} // namespace wowee

View file

@ -2,6 +2,7 @@
#include "game/game_handler.hpp"
#include "game/inventory.hpp"
#include "rendering/world_map.hpp"
#include "ui/inventory_screen.hpp"
#include "ui/spellbook_screen.hpp"
#include <imgui.h>
@ -122,8 +123,11 @@ private:
/**
* Inventory screen
*/
void renderWorldMap(game::GameHandler& gameHandler);
InventoryScreen inventoryScreen;
SpellbookScreen spellbookScreen;
rendering::WorldMap worldMap;
};
}} // namespace wowee::ui

1045
src/rendering/world_map.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,7 @@
#include "core/spawn_presets.hpp"
#include "core/input.hpp"
#include "rendering/renderer.hpp"
#include "rendering/minimap.hpp"
#include "rendering/character_renderer.hpp"
#include "rendering/camera.hpp"
#include "pipeline/asset_manager.hpp"
@ -80,6 +81,9 @@ void GameScreen::render(game::GameHandler& gameHandler) {
renderGossipWindow(gameHandler);
renderVendorWindow(gameHandler);
// World map (M key toggle handled inside)
renderWorldMap(gameHandler);
// Teleporter panel (T key toggle handled in Application event loop)
renderTeleporterPanel();
@ -964,6 +968,31 @@ void GameScreen::updateCharacterTextures(game::Inventory& inventory) {
}
}
// ============================================================
// World Map
// ============================================================
void GameScreen::renderWorldMap(game::GameHandler& /* gameHandler */) {
auto& app = core::Application::getInstance();
auto* renderer = app.getRenderer();
auto* assetMgr = app.getAssetManager();
if (!renderer || !assetMgr) return;
worldMap.initialize(assetMgr);
// Keep map name in sync with minimap's map name
auto* minimap = renderer->getMinimap();
if (minimap) {
worldMap.setMapName(minimap->getMapName());
}
glm::vec3 playerPos = renderer->getCharacterPosition();
auto* window = app.getWindow();
int screenW = window ? window->getWidth() : 1280;
int screenH = window ? window->getHeight() : 720;
worldMap.render(playerPos, screenW, screenH);
}
// ============================================================
// Action Bar (Phase 3)
// ============================================================