From d75c47622167420761626dcdc639624d2377932d Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sat, 3 Dec 2016 21:18:28 +0000 Subject: [PATCH] Remove global texture list and use a slot name to lookup textures --- rwengine/src/engine/GameData.cpp | 73 ++++++++++++++++++----- rwengine/src/engine/GameData.hpp | 27 +++++++-- rwengine/src/engine/GameWorld.cpp | 36 +---------- rwengine/src/objects/PickupObject.cpp | 2 +- rwengine/src/objects/ProjectileObject.cpp | 2 +- rwengine/src/render/GameRenderer.cpp | 12 +--- rwengine/src/render/MapRenderer.cpp | 7 ++- rwengine/src/render/ObjectRenderer.cpp | 11 ---- rwengine/src/render/TextRenderer.cpp | 2 +- rwengine/src/render/WaterRenderer.cpp | 2 +- rwgame/DrawUI.cpp | 2 +- 11 files changed, 92 insertions(+), 84 deletions(-) diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 35d601b8..d70d1bf6 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -37,13 +37,13 @@ void GameData::load() { /// @todo cuts.img files should be loaded differently to gta3.img loadIMG("anim/cuts.img"); - loadLevelFile("data/default.dat"); - loadLevelFile("data/gta3.dat"); - - loadTXD("particle.txd"); - loadTXD("icons.txd"); - loadTXD("hud.txd"); - loadTXD("fonts.txd"); + textureslots["particle"] = loadTextureArchive("particle.txd"); + textureslots["icons"] = loadTextureArchive("icons.txd"); + textureslots["hud"] = loadTextureArchive("hud.txd"); + textureslots["fonts"] = loadTextureArchive("fonts.txd"); + textureslots["generic"] = loadTextureArchive("generic.txd"); + auto misc = loadTextureArchive("misc.txd"); + textureslots["generic"].insert(misc.begin(), misc.end()); loadCarcols("data/carcols.dat"); loadWeather("data/timecyc.dat"); @@ -52,6 +52,9 @@ void GameData::load() { loadWeaponDAT("data/weapon.dat"); loadIFP("ped.ifp"); + + loadLevelFile("data/default.dat"); + loadLevelFile("data/gta3.dat"); } void GameData::loadLevelFile(const std::string& path) { @@ -63,6 +66,9 @@ void GameData::loadLevelFile(const std::string& path) { return; } + // Reset texture slot + currenttextureslot = "generic"; + for (std::string line, cmd; std::getline(datfile, line);) { if (line.size() == 0 || line[0] == '#') continue; #ifndef RW_WINDOWS @@ -296,23 +302,41 @@ void GameData::loadWater(const std::string& path) { } void GameData::loadTXD(const std::string& name) { - if (loadedFiles.find(name) != loadedFiles.end()) { + auto slot = name; + auto ext = name.find(".txd"); + if (ext != std::string::npos) { + slot = name.substr(0, ext); + } + + // Set the current texture slot + currenttextureslot = slot; + + // Check if this texture slot is loaded already + auto slotit = textureslots.find(slot); + if (slotit != textureslots.end()) { return; } - loadedFiles[name] = true; + textureslots[slot] = std::move(loadTextureArchive(name)); +} +TextureArchive GameData::loadTextureArchive(const std::string& name) { /// @todo refactor loadTXD to use correct file locations auto file = index.openFile(name); if (!file) { logger->error("Data", "Failed to open txd: " + name); - return; + return {}; } + TextureArchive textures; + TextureLoader l; if (!l.loadFromMemory(file, textures)) { logger->error("Data", "Error loading txd: " + name); + return {}; } + + return textures; } void GameData::getNameAndLod(std::string& name, int& lod) { @@ -330,6 +354,11 @@ Model* GameData::loadClump(const std::string& name) { return nullptr; } LoaderDFF l; + l.setTextureLookupCallback( + [&](const std::string& texture, const std::string&) { + // Lookup the texture in the current texture slot + return findSlotTexture(currenttextureslot, texture); + }); auto m = l.loadFromMemory(file); if (!m) { logger->error("Data", "Error loading model file " + name); @@ -345,6 +374,12 @@ void GameData::loadModelFile(const std::string& name) { return; } LoaderDFF l; + l.setTextureLookupCallback( + [&](const std::string& texture, const std::string&) { + // Lookup the texture in the current texture slot + return findSlotTexture(currenttextureslot, texture); + }); + auto m = l.loadFromMemory(file); if (!m) { logger->log("Data", Logger::Error, "Error loading model file " + name); @@ -374,14 +409,14 @@ void GameData::loadModel(ModelID model) { auto info = modelinfo[model].get(); /// @todo replace openFile with API for loading from CDIMAGE archives auto name = info->name; + auto slotname = info->textureslot; // Re-direct special models switch (info->type()) { case ModelDataType::ClumpInfo: // Re-direct the hier objects to the special object ids name = engine->state->specialModels[info->id()]; - /// @todo remove this from here - loadTXD(name + ".txd"); + slotname = name; break; case ModelDataType::PedInfo: static const std::string specialPrefix("special"); @@ -389,8 +424,7 @@ void GameData::loadModel(ModelID model) { auto sid = name.substr(specialPrefix.size()); unsigned short specialID = std::atoi(sid.c_str()); name = engine->state->specialCharacters[specialID]; - /// @todo remove this from here - loadTXD(name + ".txd"); + slotname = name; break; } default: @@ -398,6 +432,12 @@ void GameData::loadModel(ModelID model) { } std::transform(name.begin(), name.end(), name.begin(), ::tolower); + std::transform(slotname.begin(), slotname.end(), slotname.begin(), + ::tolower); + + /// @todo remove this from here + loadTXD(slotname + ".txd"); + auto file = index.openFile(name + ".dff"); if (!file) { logger->error("Data", "Failed to load model for " + @@ -405,6 +445,11 @@ void GameData::loadModel(ModelID model) { return; } LoaderDFF l; + l.setTextureLookupCallback( + [&](const std::string& texture, const std::string&) { + // Lookup the texture in the current texture slot + return findSlotTexture(currenttextureslot, texture); + }); auto m = l.loadFromMemory(file); if (!m) { logger->error("Data", diff --git a/rwengine/src/engine/GameData.hpp b/rwengine/src/engine/GameData.hpp index 4b18f5c2..49cf92e5 100644 --- a/rwengine/src/engine/GameData.hpp +++ b/rwengine/src/engine/GameData.hpp @@ -39,6 +39,7 @@ class GameData { private: std::string datpath; std::string splash; + std::string currenttextureslot; Logger* logger; public: @@ -111,10 +112,16 @@ public: void loadLevelFile(const std::string& path); /** - * Attempts to load a TXD, or does nothing if it has already been loaded + * Loads the txt slot if it is not already loaded and sets + * the current TXD slot */ void loadTXD(const std::string& name); + /** + * Loads a named texture archive from the game data + */ + TextureArchive loadTextureArchive(const std::string& name); + /** * Converts combined {name}_l{LOD} into name and lod. */ @@ -155,9 +162,17 @@ public: void loadSplash(const std::string& name); - TextureData::Handle findTexture(const std::string& name, - const std::string& alpha = "") { - return textures[{name, alpha}]; + TextureData::Handle findSlotTexture(const std::string& slot, + const std::string& texture) const { + auto slotit = textureslots.find(slot); + if (slotit == textureslots.end()) { + return nullptr; + } + auto textureit = slotit->second.find(texture); + if (textureit == slotit->second.end()) { + return nullptr; + } + return textureit->second; } FileIndex index; @@ -222,9 +237,9 @@ public: WeatherLoader weatherLoader; /** - * Loaded textures (Textures are ID by name and alpha pairs) + * Texture slots, containing loaded textures. */ - std::map, TextureData::Handle> textures; + std::map textureslots; /** * Texture atlases. diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index 35466136..97167379 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -158,18 +158,6 @@ InstanceObject* GameWorld::createInstance(const uint16_t id, data->loadModel(oi->id()); } - std::string modelname = oi->name; - std::string texturename = oi->textureslot; - - std::transform(std::begin(modelname), std::end(modelname), - std::begin(modelname), tolower); - std::transform(std::begin(texturename), std::end(texturename), - std::begin(texturename), tolower); - - if (!texturename.empty()) { - data->loadTXD(texturename + ".txd"); - } - // Check for dynamic data. auto dyit = data->dynamicObjectData.find(oi->name); std::shared_ptr dydata; @@ -177,7 +165,7 @@ InstanceObject* GameWorld::createInstance(const uint16_t id, dydata = dyit->second; } - if (modelname.empty()) { + if (oi->name.empty()) { logger->warning( "World", "Instance with missing model: " + std::to_string(id)); } @@ -243,15 +231,12 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id, } auto clumpmodel = static_cast(modelinfo); - std::string texturename; if (!clumpmodel->isLoaded()) { data->loadModel(id); } auto model = clumpmodel->getModel(); - texturename = modelinfo->textureslot; - if (id == 0) { auto playerobj = pedestrianPool.find(state->playerObject); if (playerobj) { @@ -259,10 +244,6 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id, } } - if (!texturename.empty()) { - data->loadTXD(texturename + ".txd"); - } - auto instance = new CutsceneObject(this, pos, rot, model, modelinfo); cutscenePool.insert(instance); @@ -285,10 +266,6 @@ VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, data->loadModel(id); } - if (!vti->textureslot.empty()) { - data->loadTXD(vti->textureslot + ".txd"); - } - glm::u8vec3 prim(255), sec(128); auto palit = data->vehiclePalettes.find( vti->name); // modelname is conveniently lowercase (usually) @@ -361,12 +338,6 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id, data->loadModel(id); } - std::string texturename = pt->textureslot; - - if (!texturename.empty()) { - data->loadTXD(texturename + ".txd"); - } - auto ped = new CharacterObject(this, pos, rot, pt); ped->setGameObjectID(gid); new DefaultAIController(ped); @@ -388,13 +359,12 @@ CharacterObject* GameWorld::createPlayer(const glm::vec3& pos, std::string modelname = "player"; std::string texturename = "player"; + data->loadTXD(texturename + ".txd"); if (!pt->isLoaded()) { auto model = data->loadClump(modelname + ".dff"); pt->setModel(model); } - data->loadTXD(texturename + ".txd"); - auto ped = new CharacterObject(this, pos, rot, pt); ped->setGameObjectID(gid); ped->setLifetime(GameObject::PlayerLifetime); @@ -416,8 +386,6 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) { data->loadModel(id); } - data->loadTXD(modelInfo->textureslot + ".txd"); - PickupObject* pickup = nullptr; auto pickuptype = (PickupObject::PickupType)type; diff --git a/rwengine/src/objects/PickupObject.cpp b/rwengine/src/objects/PickupObject.cpp index 89158451..aa1424ff 100644 --- a/rwengine/src/objects/PickupObject.cpp +++ b/rwengine/src/objects/PickupObject.cpp @@ -83,7 +83,7 @@ PickupObject::PickupObject(GameWorld* world, const glm::vec3& position, m_corona->particle.direction = glm::vec3(0.f, 0.f, 1.f); m_corona->particle.orientation = VisualFX::ParticleData::Camera; m_corona->particle.colour = glm::vec4(1.0f, 0.3f, 0.3f, 0.3f); - m_corona->particle.texture = engine->data->findTexture("coronacircle"); + m_corona->particle.texture = engine->data->findSlotTexture("particle", "coronacircle"); auto flags = behaviourFlags(m_type); RW_UNUSED(flags); diff --git a/rwengine/src/objects/ProjectileObject.cpp b/rwengine/src/objects/ProjectileObject.cpp index 2150c9c3..8ee31d6d 100644 --- a/rwengine/src/objects/ProjectileObject.cpp +++ b/rwengine/src/objects/ProjectileObject.cpp @@ -71,7 +71,7 @@ void ProjectileObject::explode() { 0.f}); } - auto tex = engine->data->findTexture("explo02"); + auto tex = engine->data->findSlotTexture("particle", "explo02"); auto explosion = engine->createEffect(VisualFX::Particle); explosion->particle.size = glm::vec2(exp_size); diff --git a/rwengine/src/render/GameRenderer.cpp b/rwengine/src/render/GameRenderer.cpp index 4b4c9bb6..3ab02399 100644 --- a/rwengine/src/render/GameRenderer.cpp +++ b/rwengine/src/render/GameRenderer.cpp @@ -404,7 +404,7 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera, GLuint splashTexName = 0; auto fc = world->state->fadeColour; if ((fc.r + fc.g + fc.b) == 0 && world->state->currentSplash.size() > 0) { - auto splash = world->data->findTexture(world->state->currentSplash); + auto splash = world->data->findSlotTexture("generic", world->state->currentSplash); if (splash) { splashTexName = splash->getName(); } @@ -494,16 +494,6 @@ void GameRenderer::renderGeometry(Model* model, size_t g, if (mat.textures.size() > 0) { auto tex = mat.textures[0].texture; - if (!tex) { - auto& tC = mat.textures[0].name; - auto& tA = mat.textures[0].alphaName; - tex = data->findTexture(tC, tA); - if (!tex) { - // logger->warning("Renderer", "Missing texture: " + tC - // + " " + tA); - } - mat.textures[0].texture = tex; - } if (tex) { dp.textures = {tex->getName()}; } diff --git a/rwengine/src/render/MapRenderer.cpp b/rwengine/src/render/MapRenderer.cpp index f0a29f73..00325f23 100644 --- a/rwengine/src/render/MapRenderer.cpp +++ b/rwengine/src/render/MapRenderer.cpp @@ -115,7 +115,7 @@ void MapRenderer::draw(GameWorld* world, const MapInfo& mi) { for (int m = 0; m < MAP_BLOCK_SIZE; ++m) { std::string num = (m < 10 ? "0" : ""); std::string name = "radar" + num + std::to_string(m); - auto texture = world->data->textures[{name, ""}]; + auto texture = world->data->findSlotTexture(name, name); glBindTexture(GL_TEXTURE_2D, texture->getName()); @@ -140,7 +140,8 @@ void MapRenderer::draw(GameWorld* world, const MapInfo& mi) { glDisable(GL_STENCIL_TEST); // We only need the outer ring if we're clipping. glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ONE, GL_ZERO); - TextureData::Handle radarDisc = data->findTexture("radardisc"); + TextureData::Handle radarDisc = + data->findSlotTexture("hud", "radardisc"); glm::mat4 model; model = glm::translate(model, glm::vec3(mi.screenPosition, 0.0f)); @@ -257,7 +258,7 @@ void MapRenderer::prepareBlip(const glm::vec2& coord, const glm::mat4& view, GLuint tex = 0; if (!texture.empty()) { - auto sprite = data->findTexture(texture); + auto sprite = data->findSlotTexture("hud", texture); tex = sprite->getName(); } renderer->setUniform(rectProg, "colour", colour); diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index 70764fcf..ea371a41 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -61,17 +61,6 @@ void ObjectRenderer::renderGeometry(Model* model, size_t g, if (mat.textures.size() > 0) { auto tex = mat.textures[0].texture; - if (!tex) { - auto& tC = mat.textures[0].name; - auto& tA = mat.textures[0].alphaName; - tex = m_world->data->findTexture(tC, tA); - if (!tex) { - // logger->warning("Renderer", "Missing texture: " + tC - // + " " + tA); - dp.textures = {m_errorTexture}; - } - mat.textures[0].texture = tex; - } if (tex) { if (tex->isTransparent()) { isTransparent = true; diff --git a/rwengine/src/render/TextRenderer.cpp b/rwengine/src/render/TextRenderer.cpp index 56bcc042..471dc034 100644 --- a/rwengine/src/render/TextRenderer.cpp +++ b/rwengine/src/render/TextRenderer.cpp @@ -284,7 +284,7 @@ void TextRenderer::renderText(const TextRenderer::TextInfo& ti, Renderer::DrawParameters dp; dp.start = 0; dp.count = gb.getCount(); - auto ftexture = renderer->getData()->findTexture(fonts[ti.font]); + auto ftexture = renderer->getData()->findSlotTexture("fonts", fonts[ti.font]); dp.textures = {ftexture->getName()}; dp.depthWrite = false; diff --git a/rwengine/src/render/WaterRenderer.cpp b/rwengine/src/render/WaterRenderer.cpp index 9656fbfa..81881705 100644 --- a/rwengine/src/render/WaterRenderer.cpp +++ b/rwengine/src/render/WaterRenderer.cpp @@ -98,7 +98,7 @@ void WaterRenderer::setDataTexture(GLuint fbBinding, GLuint dataTex) { void WaterRenderer::render(GameRenderer* renderer, GameWorld* world) { auto r = renderer->getRenderer(); - auto waterTex = world->data->findTexture("water_old"); + auto waterTex = world->data->findSlotTexture("particle", "water_old"); RW_CHECK(waterTex != nullptr, "Water texture is null"); if (waterTex == nullptr) { // Can't render water if we don't have a texture. diff --git a/rwgame/DrawUI.cpp b/rwgame/DrawUI.cpp index 255c59e1..6033aac0 100644 --- a/rwgame/DrawUI.cpp +++ b/rwgame/DrawUI.cpp @@ -168,7 +168,7 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world, } TextureData::Handle itemTexture = - render->getData()->findTexture(itemTextureName); + render->getData()->findSlotTexture("hud", itemTextureName); RW_CHECK(itemTexture != nullptr, "Item has 0 texture"); if (itemTexture != nullptr) { RW_CHECK(itemTexture->getName() != 0, "Item has 0 texture");