mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 17:43:52 +00:00
Preload terrain textures on background thread and fix ramp Z-snapping
Load BLP texture data during prepareTile() and upload to GL cache in finalizeTile(), eliminating file I/O stalls on the main thread. Reduce ready tiles per frame to 1. Fix camera sweep to snap Z to ramp surfaces. Change hearthstone action bar slot from spell to item.
This commit is contained in:
parent
0ce38cfb99
commit
d910073d7a
6 changed files with 66 additions and 13 deletions
|
|
@ -4,6 +4,7 @@
|
||||||
#include "pipeline/terrain_mesh.hpp"
|
#include "pipeline/terrain_mesh.hpp"
|
||||||
#include "pipeline/m2_loader.hpp"
|
#include "pipeline/m2_loader.hpp"
|
||||||
#include "pipeline/wmo_loader.hpp"
|
#include "pipeline/wmo_loader.hpp"
|
||||||
|
#include "pipeline/blp_loader.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
@ -103,6 +104,10 @@ struct PendingTile {
|
||||||
glm::mat4 modelMatrix; // Pre-computed world transform
|
glm::mat4 modelMatrix; // Pre-computed world transform
|
||||||
};
|
};
|
||||||
std::vector<WMODoodadReady> wmoDoodads;
|
std::vector<WMODoodadReady> wmoDoodads;
|
||||||
|
|
||||||
|
// Pre-loaded terrain texture BLP data (loaded on background thread to avoid
|
||||||
|
// blocking file I/O on the main thread during finalizeTile)
|
||||||
|
std::unordered_map<std::string, pipeline::BLPImage> preloadedTextures;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pipeline/terrain_mesh.hpp"
|
#include "pipeline/terrain_mesh.hpp"
|
||||||
|
#include "pipeline/blp_loader.hpp"
|
||||||
#include "rendering/shader.hpp"
|
#include "rendering/shader.hpp"
|
||||||
#include "rendering/texture.hpp"
|
#include "rendering/texture.hpp"
|
||||||
#include "rendering/camera.hpp"
|
#include "rendering/camera.hpp"
|
||||||
|
|
@ -87,6 +88,12 @@ public:
|
||||||
*/
|
*/
|
||||||
void removeTile(int tileX, int tileY);
|
void removeTile(int tileX, int tileY);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload pre-loaded BLP textures to the GL texture cache.
|
||||||
|
* Called before loadTerrain() so texture loading avoids file I/O.
|
||||||
|
*/
|
||||||
|
void uploadPreloadedTextures(const std::unordered_map<std::string, pipeline::BLPImage>& textures);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render loaded terrain
|
* Render loaded terrain
|
||||||
* @param camera Camera for view/projection matrices
|
* @param camera Camera for view/projection matrices
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,12 @@ GameHandler::GameHandler() {
|
||||||
|
|
||||||
// Default spells always available
|
// Default spells always available
|
||||||
knownSpells.push_back(6603); // Attack
|
knownSpells.push_back(6603); // Attack
|
||||||
knownSpells.push_back(8690); // Hearthstone
|
|
||||||
|
|
||||||
// Default action bar layout
|
// Default action bar layout
|
||||||
actionBar[0].type = ActionBarSlot::SPELL;
|
actionBar[0].type = ActionBarSlot::SPELL;
|
||||||
actionBar[0].id = 6603; // Attack in slot 1
|
actionBar[0].id = 6603; // Attack in slot 1
|
||||||
actionBar[11].type = ActionBarSlot::SPELL;
|
actionBar[11].type = ActionBarSlot::ITEM;
|
||||||
actionBar[11].id = 8690; // Hearthstone in slot 12
|
actionBar[11].id = 6948; // Hearthstone item in slot 12
|
||||||
}
|
}
|
||||||
|
|
||||||
GameHandler::~GameHandler() {
|
GameHandler::~GameHandler() {
|
||||||
|
|
@ -3788,13 +3787,10 @@ void GameHandler::handleInitialSpells(network::Packet& packet) {
|
||||||
|
|
||||||
knownSpells = data.spellIds;
|
knownSpells = data.spellIds;
|
||||||
|
|
||||||
// Ensure Attack (6603) and Hearthstone (8690) are always present
|
// Ensure Attack (6603) is always present
|
||||||
if (std::find(knownSpells.begin(), knownSpells.end(), 6603u) == knownSpells.end()) {
|
if (std::find(knownSpells.begin(), knownSpells.end(), 6603u) == knownSpells.end()) {
|
||||||
knownSpells.insert(knownSpells.begin(), 6603u);
|
knownSpells.insert(knownSpells.begin(), 6603u);
|
||||||
}
|
}
|
||||||
if (std::find(knownSpells.begin(), knownSpells.end(), 8690u) == knownSpells.end()) {
|
|
||||||
knownSpells.push_back(8690u);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set initial cooldowns
|
// Set initial cooldowns
|
||||||
for (const auto& cd : data.cooldowns) {
|
for (const auto& cd : data.cooldowns) {
|
||||||
|
|
@ -3803,11 +3799,11 @@ void GameHandler::handleInitialSpells(network::Packet& packet) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load saved action bar or use defaults (Attack slot 1, Hearthstone slot 12)
|
// Load saved action bar or use defaults (Attack slot 1, Hearthstone item slot 12)
|
||||||
actionBar[0].type = ActionBarSlot::SPELL;
|
actionBar[0].type = ActionBarSlot::SPELL;
|
||||||
actionBar[0].id = 6603; // Attack
|
actionBar[0].id = 6603; // Attack
|
||||||
actionBar[11].type = ActionBarSlot::SPELL;
|
actionBar[11].type = ActionBarSlot::ITEM;
|
||||||
actionBar[11].id = 8690; // Hearthstone
|
actionBar[11].id = 6948; // Hearthstone item
|
||||||
loadCharacterConfig();
|
loadCharacterConfig();
|
||||||
|
|
||||||
LOG_INFO("Learned ", knownSpells.size(), " spells");
|
LOG_INFO("Learned ", knownSpells.size(), " spells");
|
||||||
|
|
|
||||||
|
|
@ -465,6 +465,11 @@ void CameraController::update(float deltaTime) {
|
||||||
if (!walkable) {
|
if (!walkable) {
|
||||||
candidate.x = adjusted.x;
|
candidate.x = adjusted.x;
|
||||||
candidate.y = adjusted.y;
|
candidate.y = adjusted.y;
|
||||||
|
} else if (floorH && *floorH > candidate.z) {
|
||||||
|
// Snap Z to ramp surface so subsequent sweep
|
||||||
|
// steps measure feetZ from the ramp, not the
|
||||||
|
// starting position.
|
||||||
|
candidate.z = *floorH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -465,11 +465,19 @@ std::unique_ptr<PendingTile> TerrainManager::prepareTile(int x, int y) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pre-load terrain texture BLP data on background thread so finalizeTile
|
||||||
|
// doesn't block the main thread with file I/O.
|
||||||
|
for (const auto& texPath : pending->terrain.textures) {
|
||||||
|
if (pending->preloadedTextures.find(texPath) != pending->preloadedTextures.end()) continue;
|
||||||
|
pending->preloadedTextures[texPath] = assetManager->loadTexture(texPath);
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Prepared tile [", x, ",", y, "]: ",
|
LOG_DEBUG("Prepared tile [", x, ",", y, "]: ",
|
||||||
pending->m2Models.size(), " M2 models, ",
|
pending->m2Models.size(), " M2 models, ",
|
||||||
pending->m2Placements.size(), " M2 placements, ",
|
pending->m2Placements.size(), " M2 placements, ",
|
||||||
pending->wmoModels.size(), " WMOs, ",
|
pending->wmoModels.size(), " WMOs, ",
|
||||||
pending->wmoDoodads.size(), " WMO doodads");
|
pending->wmoDoodads.size(), " WMO doodads, ",
|
||||||
|
pending->preloadedTextures.size(), " textures");
|
||||||
|
|
||||||
return pending;
|
return pending;
|
||||||
}
|
}
|
||||||
|
|
@ -489,6 +497,11 @@ void TerrainManager::finalizeTile(std::unique_ptr<PendingTile> pending) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Upload pre-loaded textures to the GL cache so loadTerrain avoids file I/O
|
||||||
|
if (!pending->preloadedTextures.empty()) {
|
||||||
|
terrainRenderer->uploadPreloadedTextures(pending->preloadedTextures);
|
||||||
|
}
|
||||||
|
|
||||||
// Upload terrain to GPU
|
// Upload terrain to GPU
|
||||||
if (!terrainRenderer->loadTerrain(pending->mesh, pending->terrain.textures, x, y)) {
|
if (!terrainRenderer->loadTerrain(pending->mesh, pending->terrain.textures, x, y)) {
|
||||||
LOG_ERROR("Failed to upload terrain to GPU for tile [", x, ",", y, "]");
|
LOG_ERROR("Failed to upload terrain to GPU for tile [", x, ",", y, "]");
|
||||||
|
|
@ -657,9 +670,9 @@ void TerrainManager::workerLoop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerrainManager::processReadyTiles() {
|
void TerrainManager::processReadyTiles() {
|
||||||
// Process up to 2 ready tiles per frame to spread GPU work
|
// Process up to 1 ready tile per frame to avoid main-thread stalls
|
||||||
int processed = 0;
|
int processed = 0;
|
||||||
const int maxPerFrame = 2;
|
const int maxPerFrame = 1;
|
||||||
|
|
||||||
while (processed < maxPerFrame) {
|
while (processed < maxPerFrame) {
|
||||||
std::unique_ptr<PendingTile> pending;
|
std::unique_ptr<PendingTile> pending;
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,33 @@ GLuint TerrainRenderer::loadTexture(const std::string& path) {
|
||||||
return textureID;
|
return textureID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerrainRenderer::uploadPreloadedTextures(const std::unordered_map<std::string, pipeline::BLPImage>& textures) {
|
||||||
|
for (const auto& [path, blp] : textures) {
|
||||||
|
// Skip if already cached
|
||||||
|
if (textureCache.find(path) != textureCache.end()) continue;
|
||||||
|
if (!blp.isValid()) {
|
||||||
|
textureCache[path] = whiteTexture;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint textureID;
|
||||||
|
glGenTextures(1, &textureID);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
|
||||||
|
blp.width, blp.height, 0,
|
||||||
|
GL_RGBA, GL_UNSIGNED_BYTE, blp.data.data());
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
applyAnisotropicFiltering();
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
textureCache[path] = textureID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GLuint TerrainRenderer::createAlphaTexture(const std::vector<uint8_t>& alphaData) {
|
GLuint TerrainRenderer::createAlphaTexture(const std::vector<uint8_t>& alphaData) {
|
||||||
if (alphaData.empty()) {
|
if (alphaData.empty()) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue