Skip to content

Commit

Permalink
Fix LTEX overriding and allow deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
Assumeru committed Jun 3, 2024
1 parent 05815b3 commit ca6baed
Show file tree
Hide file tree
Showing 11 changed files with 41 additions and 84 deletions.
4 changes: 2 additions & 2 deletions apps/opencs/view/render/terrainstorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ namespace CSVRender
land, ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX);
}

const ESM::LandTexture* TerrainStorage::getLandTexture(std::uint16_t index, int plugin)
const std::string* TerrainStorage::getLandTexture(std::uint16_t index, int plugin)
{
const int row = mData.getLandTextures().searchId(
ESM::RefId::stringRefId(CSMWorld::LandTexture::createUniqueRecordId(plugin, index)));
if (row == -1)
return nullptr;

return &mData.getLandTextures().getRecord(row).get();
return &mData.getLandTextures().getRecord(row).get().mTexture;
}

void TerrainStorage::setAlteredHeight(int inCellX, int inCellY, float height)
Expand Down
2 changes: 1 addition & 1 deletion apps/opencs/view/render/terrainstorage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace CSVRender
std::array<float, ESM::Land::LAND_SIZE * ESM::Land::LAND_SIZE> mAlteredHeight;

osg::ref_ptr<const ESMTerrain::LandObject> getLand(ESM::ExteriorCellLocation cellLocation) override;
const ESM::LandTexture* getLandTexture(std::uint16_t index, int plugin) override;
const std::string* getLandTexture(std::uint16_t index, int plugin) override;

void getBounds(float& minX, float& maxX, float& minY, float& maxY, ESM::RefId worldspace) override;

Expand Down
3 changes: 1 addition & 2 deletions apps/openmw/mwrender/terrainstorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,8 @@ namespace MWRender
return mLandManager->getLand(cellLocation);
}

const ESM::LandTexture* TerrainStorage::getLandTexture(std::uint16_t index, int plugin)
const std::string* TerrainStorage::getLandTexture(std::uint16_t index, int plugin)
{
assert(plugin >= 0); // Saves don't contain textures
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
return esmStore.get<ESM::LandTexture>().search(index, plugin);
}
Expand Down
2 changes: 1 addition & 1 deletion apps/openmw/mwrender/terrainstorage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace MWRender
~TerrainStorage();

osg::ref_ptr<const ESMTerrain::LandObject> getLand(ESM::ExteriorCellLocation cellLocation) override;
const ESM::LandTexture* getLandTexture(std::uint16_t index, int plugin) override;
const std::string* getLandTexture(std::uint16_t index, int plugin) override;

bool hasData(ESM::ExteriorCellLocation cellLocation) override;

Expand Down
5 changes: 0 additions & 5 deletions apps/openmw/mwworld/esmstore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,11 +391,6 @@ namespace MWWorld
if (listener != nullptr)
listener->setProgressRange(::EsmLoader::fileProgress);

// Land texture loading needs to use a separate internal store for each plugin.
// We set the number of plugins here so we can properly verify if valid plugin
// indices are being passed to the LandTexture Store retrieval methods.
getWritable<ESM::LandTexture>().resize(esm.getIndex() + 1);

// Loop through all records
while (esm.hasMoreRecs())
{
Expand Down
76 changes: 22 additions & 54 deletions apps/openmw/mwworld/store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,83 +379,51 @@ namespace MWWorld

// LandTexture
//=========================================================================
Store<ESM::LandTexture>::Store() {}
const ESM::LandTexture* Store<ESM::LandTexture>::search(size_t index, size_t plugin) const
{
assert(plugin < mStatic.size());
const LandTextureList& ltexl = mStatic[plugin];
Store<ESM::LandTexture>::Store() = default;

if (index >= ltexl.size())
return nullptr;
return &ltexl[index];
}
const ESM::LandTexture* Store<ESM::LandTexture>::find(size_t index, size_t plugin) const
const std::string* Store<ESM::LandTexture>::search(std::uint32_t index, int plugin) const
{
const ESM::LandTexture* ptr = search(index, plugin);
if (ptr == nullptr)
{
const std::string msg = "Land texture with index " + std::to_string(index) + " not found";
throw std::runtime_error(msg);
}
return ptr;
}

void Store<ESM::LandTexture>::resize(std::size_t num)
{
mStatic.resize(num);
auto mapping = mMappings.find(PluginIndex{ plugin, index });
if (mapping == mMappings.end())
return nullptr;
auto texture = mTextures.find(mapping->second);
if (texture == mTextures.end())
return nullptr;
return &texture->second;
}

size_t Store<ESM::LandTexture>::getSize() const
{
return mStatic.size();
}
size_t Store<ESM::LandTexture>::getSize(size_t plugin) const
{
assert(plugin < mStatic.size());
return mStatic[plugin].size();
return mTextures.size();
}

RecordId Store<ESM::LandTexture>::load(ESM::ESMReader& esm)
{
const int plugin = esm.getIndex();

ESM::LandTexture lt;
bool isDeleted = false;

lt.load(esm, isDeleted);

// Replace texture for records with given ID and index from all plugins.
for (unsigned int i = 0; i < mStatic.size(); i++)
if (!isDeleted)
{
ESM::LandTexture* tex = const_cast<ESM::LandTexture*>(search(lt.mIndex, i));
if (tex)
{
if (tex->mId == lt.mId)
tex->mTexture = lt.mTexture;
}
mTextures[lt.mId] = std::move(lt.mTexture);
mMappings.emplace(PluginIndex{ plugin, lt.mIndex }, lt.mId);
}

LandTextureList& ltexl = mStatic.back();
if (lt.mIndex + 1 > (int)ltexl.size())
ltexl.resize(lt.mIndex + 1);

// Store it
auto idx = lt.mIndex;
ltexl[idx] = std::move(lt);

return RecordId(ltexl[idx].mId, isDeleted);
}
Store<ESM::LandTexture>::iterator Store<ESM::LandTexture>::begin(size_t plugin) const
{
assert(plugin < mStatic.size());
return mStatic[plugin].begin();
return RecordId(lt.mId, isDeleted);
}
Store<ESM::LandTexture>::iterator Store<ESM::LandTexture>::end(size_t plugin) const

bool Store<ESM::LandTexture>::eraseStatic(const ESM::RefId& id)
{
assert(plugin < mStatic.size());
return mStatic[plugin].end();
mTextures.erase(id);
return true;
}

// Land
//=========================================================================
Store<ESM::Land>::~Store() {}
Store<ESM::Land>::~Store() = default;
size_t Store<ESM::Land>::getSize() const
{
return mStatic.size();
Expand Down
18 changes: 5 additions & 13 deletions apps/openmw/mwworld/store.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,29 +255,21 @@ namespace MWWorld
template <>
class Store<ESM::LandTexture> : public DynamicStore
{
// For multiple ESM/ESP files we need one list per file.
typedef std::vector<ESM::LandTexture> LandTextureList;
std::vector<LandTextureList> mStatic;
using PluginIndex = std::pair<int, std::uint32_t>; // This is essentially a FormId
std::unordered_map<ESM::RefId, std::string> mTextures;
std::map<PluginIndex, ESM::RefId> mMappings;

public:
Store();

typedef std::vector<ESM::LandTexture>::const_iterator iterator;

// Must be threadsafe! Called from terrain background loading threads.
// Not a big deal here, since ESM::LandTexture can never be modified or inserted/erased
const ESM::LandTexture* search(size_t index, size_t plugin) const;
const ESM::LandTexture* find(size_t index, size_t plugin) const;

void resize(std::size_t num);
const std::string* search(std::uint32_t index, int plugin) const;

size_t getSize() const override;
size_t getSize(size_t plugin) const;
bool eraseStatic(const ESM::RefId& id) override;

RecordId load(ESM::ESMReader& esm) override;

iterator begin(size_t plugin) const;
iterator end(size_t plugin) const;
};

template <>
Expand Down
6 changes: 5 additions & 1 deletion apps/openmw_test_suite/mwworld/test_store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,11 @@ namespace

const RecordType* result = nullptr;
if constexpr (std::is_same_v<RecordType, ESM::LandTexture>)
result = esmStore.get<RecordType>().search(index, 0);
{
const std::string* texture = esmStore.get<RecordType>().search(index, 0);
ASSERT_NE(texture, nullptr);
return;
}
else if constexpr (ESM::hasIndex<RecordType>)
result = esmStore.get<RecordType>().search(index);
else
Expand Down
3 changes: 1 addition & 2 deletions components/esm3/loadltex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ namespace ESM
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string_view getRecordType() { return "LandTexture"; }

// mId is merely a user friendly name for the texture in the editor.
std::string mTexture;
RefId mId;
int32_t mIndex;
uint32_t mIndex;

void load(ESMReader& esm, bool& isDeleted);
void save(ESMWriter& esm, bool isDeleted = false) const;
Expand Down
4 changes: 2 additions & 2 deletions components/esmterrain/storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,9 @@ namespace ESMTerrain
if (id.first != 0)
{
// NB: All vtex ids are +1 compared to the ltex ids
const ESM::LandTexture* ltex = getLandTexture(id.first - 1, id.second);
const std::string* ltex = getLandTexture(id.first - 1, id.second);
if (ltex)
texture = ltex->mTexture;
texture = *ltex;
else
{
Log(Debug::Warning) << "Warning: Unable to find land texture index " << id.first - 1 << " in plugin "
Expand Down
2 changes: 1 addition & 1 deletion components/esmterrain/storage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ namespace ESMTerrain

// Not implemented in this class, because we need different Store implementations for game and editor
virtual osg::ref_ptr<const LandObject> getLand(ESM::ExteriorCellLocation cellLocation) = 0;
virtual const ESM::LandTexture* getLandTexture(std::uint16_t index, int plugin) = 0;
virtual const std::string* getLandTexture(std::uint16_t index, int plugin) = 0;
/// Get bounds of the whole terrain in cell units
void getBounds(float& minX, float& maxX, float& minY, float& maxY, ESM::RefId worldspace) override = 0;

Expand Down

0 comments on commit ca6baed

Please sign in to comment.