From fbc6629d40933c3678427749ac0f49c9072dde5d Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 12 Jun 2024 17:09:28 +0200 Subject: [PATCH] Rework land texture handling --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/doc/savingstages.cpp | 5 +- apps/opencs/model/tools/mergestages.cpp | 8 +- apps/opencs/model/world/collection.hpp | 20 +-- apps/opencs/model/world/columnimp.cpp | 45 +------ apps/opencs/model/world/columnimp.hpp | 30 +---- apps/opencs/model/world/commands.cpp | 70 +++++------ apps/opencs/model/world/commands.hpp | 2 +- apps/opencs/model/world/data.cpp | 16 ++- apps/opencs/model/world/data.hpp | 8 +- apps/opencs/model/world/idcollection.cpp | 116 +++++++++++++++++- apps/opencs/model/world/idcollection.hpp | 60 ++++++--- apps/opencs/model/world/idtable.cpp | 73 +---------- apps/opencs/model/world/idtable.hpp | 23 ++-- apps/opencs/model/world/landtexture.cpp | 35 ------ apps/opencs/model/world/landtexture.hpp | 29 ----- apps/opencs/model/world/subcellcollection.hpp | 5 +- apps/opencs/view/render/terrainstorage.cpp | 8 +- .../opencs/view/render/terraintexturemode.cpp | 84 ++----------- .../opencs/view/render/terraintexturemode.hpp | 9 +- .../view/widget/scenetooltexturebrush.cpp | 86 +++++-------- .../view/widget/scenetooltexturebrush.hpp | 14 ++- apps/opencs/view/world/landtexturecreator.cpp | 107 ---------------- apps/opencs/view/world/landtexturecreator.hpp | 54 -------- apps/opencs/view/world/subviews.cpp | 5 +- 25 files changed, 285 insertions(+), 631 deletions(-) delete mode 100644 apps/opencs/model/world/landtexture.cpp delete mode 100644 apps/opencs/model/world/landtexture.hpp delete mode 100644 apps/opencs/view/world/landtexturecreator.cpp delete mode 100644 apps/opencs/view/world/landtexturecreator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d10882e0ae..577ef25313 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -25,7 +25,7 @@ opencs_units (model/world opencs_units (model/world universalid record commands columnbase columnimp scriptcontext cell refidcollection refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope - pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection + pathgrid land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection idcompletionmanager metadata defaultgmsts infoselectwrapper commandmacro ) @@ -70,7 +70,7 @@ opencs_units (view/world cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator - bodypartcreator landtexturecreator landcreator tableheadermouseeventhandler + bodypartcreator landcreator tableheadermouseeventhandler ) opencs_units (view/world diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 5a1666da17..12fa6e811f 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -498,11 +497,11 @@ int CSMDoc::WriteLandTextureCollectionStage::setup() void CSMDoc::WriteLandTextureCollectionStage::perform(int stage, Messages& messages) { ESM::ESMWriter& writer = mState.getWriter(); - const CSMWorld::Record& landTexture = mDocument.getData().getLandTextures().getRecord(stage); + const CSMWorld::Record& landTexture = mDocument.getData().getLandTextures().getRecord(stage); if (landTexture.isModified() || landTexture.mState == CSMWorld::RecordBase::State_Deleted) { - CSMWorld::LandTexture record = landTexture.get(); + ESM::LandTexture record = landTexture.get(); writer.startRecord(record.sRecordId); record.save(writer, landTexture.mState == CSMWorld::RecordBase::State_Deleted); writer.endRecord(record.sRecordId); diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 8af612573a..88cad267cb 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -137,13 +136,12 @@ int CSMTools::PopulateLandTexturesMergeStage::setup() void CSMTools::PopulateLandTexturesMergeStage::perform(int stage, CSMDoc::Messages& messages) { - const CSMWorld::Record& record = mState.mSource.getData().getLandTextures().getRecord(stage); + const CSMWorld::Record& record = mState.mSource.getData().getLandTextures().getRecord(stage); if (!record.isDeleted()) { - mState.mTarget->getData().getLandTextures().appendRecord( - std::make_unique>(CSMWorld::Record( - CSMWorld::RecordBase::State_ModifiedOnly, nullptr, &record.get()))); + mState.mTarget->getData().getLandTextures().appendRecord(std::make_unique>( + CSMWorld::Record(CSMWorld::RecordBase::State_ModifiedOnly, nullptr, &record.get()))); } } diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 83c8de656a..fa42ee0f09 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -24,7 +24,6 @@ #include "columnimp.hpp" #include "info.hpp" #include "land.hpp" -#include "landtexture.hpp" #include "record.hpp" #include "ref.hpp" @@ -74,16 +73,6 @@ namespace CSMWorld return ESM::RefId::stringRefId(Land::createUniqueRecordId(record.mX, record.mY)); } - inline void setRecordId(const ESM::RefId& id, LandTexture& record) - { - int plugin = 0; - int index = 0; - - LandTexture::parseUniqueRecordId(id.getRefIdString(), plugin, index); - record.mPluginIndex = plugin; - record.mIndex = index; - } - inline ESM::RefId getRecordId(const ESM::MagicEffect& record) { return ESM::RefId::stringRefId(CSMWorld::getStringId(record.mId)); @@ -95,11 +84,6 @@ namespace CSMWorld record.mId = ESM::RefId::index(ESM::REC_MGEF, static_cast(index)); } - inline ESM::RefId getRecordId(const LandTexture& record) - { - return ESM::RefId::stringRefId(LandTexture::createUniqueRecordId(record.mPluginIndex, record.mIndex)); - } - inline void setRecordId(const ESM::RefId& id, ESM::Skill& record) { if (const auto* skillId = id.getIf()) @@ -339,7 +323,7 @@ namespace CSMWorld const ESM::RefId& origin, const ESM::RefId& destination, const UniversalId::Type type) { const int index = cloneRecordImp(origin, destination, type); - mRecords.at(index)->get().setPlugin(0); + mRecords.at(index)->get().setPlugin(-1); } template @@ -354,7 +338,7 @@ namespace CSMWorld const int index = touchRecordImp(id); if (index >= 0) { - mRecords.at(index)->get().setPlugin(0); + mRecords.at(index)->get().setPlugin(-1); return true; } diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 215e4c3dfc..53ced504e4 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -3,10 +3,10 @@ #include #include #include -#include #include #include +#include #include #include @@ -45,36 +45,13 @@ namespace CSMWorld }; } - /* LandTextureNicknameColumn */ - LandTextureNicknameColumn::LandTextureNicknameColumn() - : Column(Columns::ColumnId_TextureNickname, ColumnBase::Display_String) - { - } - - QVariant LandTextureNicknameColumn::get(const Record& record) const - { - return QString::fromStdString(record.get().mId.toString()); - } - - void LandTextureNicknameColumn::set(Record& record, const QVariant& data) - { - LandTexture copy = record.get(); - copy.mId = ESM::RefId::stringRefId(data.toString().toUtf8().constData()); - record.setModified(copy); - } - - bool LandTextureNicknameColumn::isEditable() const - { - return true; - } - /* LandTextureIndexColumn */ LandTextureIndexColumn::LandTextureIndexColumn() - : Column(Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) + : Column(Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) { } - QVariant LandTextureIndexColumn::get(const Record& record) const + QVariant LandTextureIndexColumn::get(const Record& record) const { return record.get().mIndex; } @@ -100,22 +77,6 @@ namespace CSMWorld return false; } - /* LandTexturePluginIndexColumn */ - LandTexturePluginIndexColumn::LandTexturePluginIndexColumn() - : Column(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0) - { - } - - QVariant LandTexturePluginIndexColumn::get(const Record& record) const - { - return record.get().mPluginIndex; - } - - bool LandTexturePluginIndexColumn::isEditable() const - { - return false; - } - /* LandNormalsColumn */ LandNormalsColumn::LandNormalsColumn() : Column(Columns::ColumnId_LandNormalsIndex, ColumnBase::Display_String, 0) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 5fbded5a15..192f27ed46 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,6 @@ #include "columns.hpp" #include "info.hpp" #include "land.hpp" -#include "landtexture.hpp" #include "record.hpp" namespace CSMWorld @@ -83,13 +83,6 @@ namespace CSMWorld return QString::fromUtf8(Land::createUniqueRecordId(land.mX, land.mY).c_str()); } - template <> - inline QVariant StringIdColumn::get(const Record& record) const - { - const LandTexture& ltex = record.get(); - return QString::fromUtf8(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str()); - } - template struct RecordStateColumn : public Column { @@ -2365,20 +2358,11 @@ namespace CSMWorld bool isEditable() const override { return true; } }; - struct LandTextureNicknameColumn : public Column - { - LandTextureNicknameColumn(); - - QVariant get(const Record& record) const override; - void set(Record& record, const QVariant& data) override; - bool isEditable() const override; - }; - - struct LandTextureIndexColumn : public Column + struct LandTextureIndexColumn : public Column { LandTextureIndexColumn(); - QVariant get(const Record& record) const override; + QVariant get(const Record& record) const override; bool isEditable() const override; }; @@ -2390,14 +2374,6 @@ namespace CSMWorld bool isEditable() const override; }; - struct LandTexturePluginIndexColumn : public Column - { - LandTexturePluginIndexColumn(); - - QVariant get(const Record& record) const override; - bool isEditable() const override; - }; - struct LandNormalsColumn : public Column { using DataType = QVector; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index b2ad84966f..168049641a 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -61,11 +60,11 @@ CSMWorld::ImportLandTexturesCommand::ImportLandTexturesCommand( void CSMWorld::ImportLandTexturesCommand::redo() { - int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex); - int oldPlugin = mLands.data(mLands.getModelIndex(getOriginId(), pluginColumn)).toInt(); + const int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex); + const int oldPlugin = mLands.data(mLands.getModelIndex(getOriginId(), pluginColumn)).toInt(); // Original data - int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); + const int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).value(); // Need to make a copy so the old values can be looked up @@ -74,44 +73,37 @@ void CSMWorld::ImportLandTexturesCommand::redo() // Perform touch/copy/etc... onRedo(); - // Find all indices used - std::unordered_set texIndices; - for (int i = 0; i < mOld.size(); ++i) + std::unordered_map indexMapping; + for (uint16_t index : mOld) { // All indices are offset by 1 for a default texture - if (mOld[i] > 0) - texIndices.insert(mOld[i] - 1); - } - - std::vector oldTextures; - oldTextures.reserve(texIndices.size()); - for (int index : texIndices) - { - oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); - } - - // Import the textures, replace old values - LandTextureIdTable::ImportResults results = dynamic_cast(mLtexs).importTextures(oldTextures); - mCreatedTextures = std::move(results.createdRecords); - for (const auto& it : results.recordMapping) - { - int plugin = 0, newIndex = 0, oldIndex = 0; - LandTexture::parseUniqueRecordId(it.first, plugin, oldIndex); - LandTexture::parseUniqueRecordId(it.second, plugin, newIndex); - - if (newIndex != oldIndex) + if (index == 0) + continue; + if (indexMapping.contains(index)) + continue; + const CSMWorld::Record* record + = static_cast(mLtexs).searchRecord(index - 1, oldPlugin); + if (!record || record->isDeleted()) + { + indexMapping.emplace(index, 0); + continue; + } + if (!record->isModified()) { - for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) - { - // All indices are offset by 1 for a default texture - if (mOld[i] == oldIndex + 1) - copy[i] = newIndex + 1; - } + mTouchedTextures.emplace_back(record->clone()); + mLtexs.touchRecord(record->get().mId.getRefIdString()); } + indexMapping.emplace(index, record->get().mIndex + 1); + } + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) + { + uint16_t oldIndex = mOld[i]; + uint16_t newIndex = indexMapping[oldIndex]; + copy[i] = newIndex; } // Apply modification - int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); + const int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); mOldState = mLands.data(mLands.getModelIndex(getDestinationId(), stateColumn)).toInt(); QVariant variant; @@ -133,12 +125,12 @@ void CSMWorld::ImportLandTexturesCommand::undo() // Undo copy/touch/etc... onUndo(); - for (const std::string& id : mCreatedTextures) + for (auto& ltex : mTouchedTextures) { - int row = mLtexs.getModelIndex(id, 0).row(); - mLtexs.removeRows(row, 1); + ESM::RefId id = static_cast*>(ltex.get())->get().mId; + mLtexs.setRecord(id.getRefIdString(), std::move(ltex)); } - mCreatedTextures.clear(); + mTouchedTextures.clear(); } CSMWorld::CopyLandTexturesCommand::CopyLandTexturesCommand( diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index a243950003..f6b0caeb1a 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -69,7 +69,7 @@ namespace CSMWorld IdTable& mLtexs; DataType mOld; int mOldState; - std::vector mCreatedTextures; + std::vector> mTouchedTextures; }; /// \brief This command is used to fix LandTexture records and texture diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index dddbb8a850..5637099d0c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -530,13 +530,11 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data mLand.addColumn(new LandColoursColumn); mLand.addColumn(new LandTexturesColumn); - mLandTextures.addColumn(new StringIdColumn(true)); - mLandTextures.addColumn(new RecordStateColumn); - mLandTextures.addColumn(new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); - mLandTextures.addColumn(new LandTextureNicknameColumn); - mLandTextures.addColumn(new LandTexturePluginIndexColumn); + mLandTextures.addColumn(new StringIdColumn); + mLandTextures.addColumn(new RecordStateColumn); + mLandTextures.addColumn(new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); mLandTextures.addColumn(new LandTextureIndexColumn); - mLandTextures.addColumn(new TextureColumn); + mLandTextures.addColumn(new TextureColumn); mPathgrids.addColumn(new StringIdColumn); mPathgrids.addColumn(new RecordStateColumn); @@ -939,12 +937,12 @@ CSMWorld::IdCollection& CSMWorld::Data::getLand() return mLand; } -const CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() const +const CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() const { return mLandTextures; } -CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() +CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() { return mLandTextures; } diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 0cf25883af..237b746746 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -43,7 +44,6 @@ #include "idcollection.hpp" #include "infocollection.hpp" #include "land.hpp" -#include "landtexture.hpp" #include "metadata.hpp" #include "nestedidcollection.hpp" #include "nestedinfocollection.hpp" @@ -114,7 +114,7 @@ namespace CSMWorld InfoCollection mJournalInfos; NestedIdCollection mCells; SubCellCollection mPathgrids; - IdCollection mLandTextures; + IdCollection mLandTextures; IdCollection mLand; RefIdCollection mReferenceables; RefCollection mRefs; @@ -259,9 +259,9 @@ namespace CSMWorld IdCollection& getLand(); - const IdCollection& getLandTextures() const; + const IdCollection& getLandTextures() const; - IdCollection& getLandTextures(); + IdCollection& getLandTextures(); const IdCollection& getSoundGens() const; diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp index faab5a20cb..ca56eceb69 100644 --- a/apps/opencs/model/world/idcollection.cpp +++ b/apps/opencs/model/world/idcollection.cpp @@ -8,6 +8,7 @@ #include #include +#include #include namespace ESM @@ -18,12 +19,12 @@ namespace ESM namespace CSMWorld { template <> - int IdCollection::load(ESM::ESMReader& reader, bool base) + int BaseIdCollection::load(ESM::ESMReader& reader, bool base) { Pathgrid record; bool isDeleted = false; - loadRecord(record, reader, isDeleted); + loadRecord(record, reader, isDeleted, base); const ESM::RefId id = getRecordId(record); int index = this->searchId(id); @@ -55,4 +56,115 @@ namespace CSMWorld return load(record, base, index); } + + const Record* IdCollection::searchRecord(std::uint16_t index, int plugin) const + { + auto found = mIndices.find({ plugin, index }); + if (found != mIndices.end()) + { + int index = searchId(found->second); + if (index != -1) + return &getRecord(index); + } + return nullptr; + } + + const std::string* IdCollection::getLandTexture(std::uint16_t index, int plugin) const + { + const Record* record = searchRecord(index, plugin); + if (record && !record->isDeleted()) + return &record->get().mTexture; + return nullptr; + } + + void IdCollection::loadRecord( + ESM::LandTexture& record, ESM::ESMReader& reader, bool& isDeleted, bool base) + { + record.load(reader, isDeleted); + int plugin = base ? reader.getIndex() : -1; + mIndices.emplace(std::make_pair(plugin, record.mIndex), record.mId); + } + + std::uint16_t IdCollection::assignNewIndex(ESM::RefId id) + { + std::uint16_t index = 0; + if (!mIndices.empty()) + { + auto end = mIndices.lower_bound({ -1, std::numeric_limits::max() }); + if (end != mIndices.begin()) + end = std::prev(end); + if (end->first.first == -1) + { + constexpr std::uint16_t maxIndex = std::numeric_limits::max() - 1; + if (end->first.second < maxIndex) + index = end->first.second + 1; + else + { + std::uint16_t prevIndex = 0; + for (auto it = mIndices.lower_bound({ -1, 0 }); it != end; ++it) + { + if (prevIndex != it->first.second) + { + index = prevIndex; + break; + } + ++prevIndex; + } + } + } + } + mIndices.emplace(std::make_pair(-1, index), id); + return index; + } + + bool IdCollection::touchRecord(const ESM::RefId& id) + { + int row = BaseIdCollection::touchRecordImp(id); + if (row != -1) + { + const_cast(getRecord(row).get()).mIndex = assignNewIndex(id); + return true; + } + return false; + } + + void IdCollection::cloneRecord( + const ESM::RefId& origin, const ESM::RefId& destination, const UniversalId::Type type) + { + int row = cloneRecordImp(origin, destination, type); + const_cast(getRecord(row).get()).mIndex = assignNewIndex(destination); + } + + void IdCollection::appendBlankRecord(const ESM::RefId& id, UniversalId::Type type) + { + ESM::LandTexture record; + record.blank(); + record.mId = id; + record.mIndex = assignNewIndex(id); + + auto record2 = std::make_unique>(); + record2->mState = Record::State_ModifiedOnly; + record2->mModified = std::move(record); + + insertRecord(std::move(record2), getAppendIndex(id, type), type); + } + + void IdCollection::removeRows(int index, int count) + { + for (int row = index; row < index + count; ++row) + { + const auto& record = getRecord(row); + if (record.isModified()) + mIndices.erase({ -1, record.get().mIndex }); + } + BaseIdCollection::removeRows(index, count); + } + + void IdCollection::replace(int index, std::unique_ptr record) + { + const auto& current = getRecord(index); + if (current.isModified() && !record->isModified()) + mIndices.erase({ -1, current.get().mIndex }); + BaseIdCollection::replace(index, std::move(record)); + } } diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index c15193fe46..d4aa82ffc9 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -17,6 +17,7 @@ namespace ESM { class ESMReader; + struct LandTexture; } namespace CSMWorld @@ -25,9 +26,9 @@ namespace CSMWorld /// \brief Single type collection of top level records template - class IdCollection : public Collection + class BaseIdCollection : public Collection { - virtual void loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted); + virtual void loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted, bool base); public: /// \return Index of loaded record (-1 if no record was loaded) @@ -46,14 +47,46 @@ namespace CSMWorld /// \return Has the ID been deleted? }; + template + class IdCollection : public BaseIdCollection + { + }; + + template <> + class IdCollection : public BaseIdCollection + { + std::map, ESM::RefId> mIndices; + + void loadRecord(ESM::LandTexture& record, ESM::ESMReader& reader, bool& isDeleted, bool base) override; + + std::uint16_t assignNewIndex(ESM::RefId id); + + public: + const Record* searchRecord(std::uint16_t index, int plugin) const; + + const std::string* getLandTexture(std::uint16_t index, int plugin) const; + + bool touchRecord(const ESM::RefId& id) override; + + void cloneRecord( + const ESM::RefId& origin, const ESM::RefId& destination, const UniversalId::Type type) override; + + void appendBlankRecord(const ESM::RefId& id, UniversalId::Type type) override; + + void removeRows(int index, int count) override; + + void replace(int index, std::unique_ptr record) override; + }; + template - void IdCollection::loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted) + void BaseIdCollection::loadRecord( + ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted, bool base) { record.load(reader, isDeleted); } template <> - inline void IdCollection::loadRecord(Land& record, ESM::ESMReader& reader, bool& isDeleted) + inline void BaseIdCollection::loadRecord(Land& record, ESM::ESMReader& reader, bool& isDeleted, bool base) { record.load(reader, isDeleted); @@ -64,22 +97,17 @@ namespace CSMWorld // Prevent data from being reloaded. record.mContext.filename.clear(); + if (!base) + record.setPlugin(-1); } template - int IdCollection::load(ESM::ESMReader& reader, bool base) + int BaseIdCollection::load(ESM::ESMReader& reader, bool base) { ESXRecordT record; bool isDeleted = false; - loadRecord(record, reader, isDeleted); - if constexpr (std::is_same_v) - { - // This doesn't really matter since the value never gets saved, but it makes the index uniqueness check more - // sensible - if (!base) - record.mPluginIndex = -1; - } + loadRecord(record, reader, isDeleted, base); ESM::RefId id = getRecordId(record); int index = this->searchId(id); @@ -110,7 +138,7 @@ namespace CSMWorld } template - int IdCollection::load(const ESXRecordT& record, bool base, int index) + int BaseIdCollection::load(const ESXRecordT& record, bool base, int index) { if (index == -2) // index unknown index = this->searchId(getRecordId(record)); @@ -142,7 +170,7 @@ namespace CSMWorld } template - bool IdCollection::tryDelete(const ESM::RefId& id) + bool BaseIdCollection::tryDelete(const ESM::RefId& id) { int index = this->searchId(id); @@ -169,7 +197,7 @@ namespace CSMWorld } template <> - int IdCollection::load(ESM::ESMReader& reader, bool base); + int BaseIdCollection::load(ESM::ESMReader& reader, bool base); } #endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index baa453fc8b..5ed0c6f0e7 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -21,7 +22,6 @@ #include "collectionbase.hpp" #include "columnbase.hpp" -#include "landtexture.hpp" CSMWorld::IdTable::IdTable(CollectionBase* idCollection, unsigned int features) : IdTableBase(features) @@ -361,73 +361,8 @@ CSMWorld::LandTextureIdTable::LandTextureIdTable(CollectionBase* idCollection, u { } -CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::importTextures( - const std::vector& ids) +const CSMWorld::Record* CSMWorld::LandTextureIdTable::searchRecord( + std::uint16_t index, int plugin) const { - ImportResults results; - - // Map existing textures to ids - std::map reverseLookupMap; - for (int i = 0; i < idCollection()->getSize(); ++i) - { - auto& record = static_cast&>(idCollection()->getRecord(i)); - if (record.isModified()) - reverseLookupMap.emplace( - Misc::StringUtils::lowerCase(record.get().mTexture), idCollection()->getId(i).getRefIdString()); - } - - for (const std::string& id : ids) - { - int plugin, index; - LandTexture::parseUniqueRecordId(id, plugin, index); - - const ESM::RefId refId = ESM::RefId::stringRefId(id); - const int oldRow = idCollection()->searchId(refId); - - // If it does not exist, it can be skipped. - if (oldRow < 0) - { - results.recordMapping.emplace_back(id, id); - continue; - } - // Look for a pre-existing record - auto& record = static_cast&>(idCollection()->getRecord(oldRow)); - // If it is in the current plugin, it can be skipped. - if (record.mState == Record::State_ModifiedOnly) - { - results.recordMapping.emplace_back(id, id); - continue; - } - std::string texture = Misc::StringUtils::lowerCase(record.get().mTexture); - auto searchIt = reverseLookupMap.find(texture); - if (searchIt != reverseLookupMap.end()) - { - results.recordMapping.emplace_back(id, searchIt->second); - continue; - } - - // Iterate until an unused index or found, or the index has completely wrapped around. - int startIndex = index; - do - { - std::string newId = LandTexture::createUniqueRecordId(-1, index); - const ESM::RefId newRefId = ESM::RefId::stringRefId(newId); - int newRow = idCollection()->searchId(newRefId); - - if (newRow < 0) - { - // Id not taken, clone it - cloneRecord(refId, newRefId, UniversalId::Type_LandTexture); - results.createdRecords.push_back(newId); - results.recordMapping.emplace_back(id, newId); - reverseLookupMap.emplace(texture, newId); - break; - } - - const size_t MaxIndex = std::numeric_limits::max() - 1; - index = (index + 1) % MaxIndex; - } while (index != startIndex); - } - - return results; + return static_cast*>(idCollection())->searchRecord(index, plugin); } diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 3ec075ca95..9247c6c1e8 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -16,10 +16,17 @@ class QObject; +namespace ESM +{ + struct LandTexture; +} + namespace CSMWorld { class CollectionBase; struct RecordBase; + template + struct Record; class IdTable : public IdTableBase { @@ -103,26 +110,12 @@ namespace CSMWorld virtual CollectionBase* idCollection() const; }; - /// An IdTable customized to handle the more unique needs of LandTextureId's which behave - /// differently from other records. The major difference is that base records cannot be - /// modified. class LandTextureIdTable : public IdTable { public: - struct ImportResults - { - using StringPair = std::pair; - - /// The newly added records - std::vector createdRecords; - /// The 1st string is the original id, the 2nd is the mapped id - std::vector recordMapping; - }; - LandTextureIdTable(CollectionBase* idCollection, unsigned int features = 0); - /// Finds and maps/recreates the specified ids. - ImportResults importTextures(const std::vector& ids); + const CSMWorld::Record* searchRecord(std::uint16_t index, int plugin) const; }; } diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp deleted file mode 100644 index ecf370c282..0000000000 --- a/apps/opencs/model/world/landtexture.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "landtexture.hpp" - -#include -#include - -#include -#include - -namespace CSMWorld -{ - void LandTexture::load(ESM::ESMReader& esm, bool& isDeleted) - { - ESM::LandTexture::load(esm, isDeleted); - - mPluginIndex = esm.getIndex(); - } - - std::string LandTexture::createUniqueRecordId(int plugin, int index) - { - std::stringstream ss; - ss << 'L' << plugin << '#' << index; - return ss.str(); - } - - void LandTexture::parseUniqueRecordId(const std::string& id, int& plugin, int& index) - { - size_t middle = id.find('#'); - - if (middle == std::string::npos || id[0] != 'L') - throw std::runtime_error("Invalid LandTexture ID"); - - plugin = Misc::StringUtils::toNumeric(id.substr(1, middle - 1), 0); - index = Misc::StringUtils::toNumeric(id.substr(middle + 1), 0); - } -} diff --git a/apps/opencs/model/world/landtexture.hpp b/apps/opencs/model/world/landtexture.hpp deleted file mode 100644 index d3cac5d3d7..0000000000 --- a/apps/opencs/model/world/landtexture.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef CSM_WORLD_LANDTEXTURE_H -#define CSM_WORLD_LANDTEXTURE_H - -#include - -#include - -namespace ESM -{ - class ESMReader; -} - -namespace CSMWorld -{ - /// \brief Wrapper for LandTexture record, providing info which plugin the LandTexture was loaded from. - struct LandTexture : public ESM::LandTexture - { - int mPluginIndex; - - void load(ESM::ESMReader& esm, bool& isDeleted); - - /// Returns a string identifier that will be unique to any LandTexture. - static std::string createUniqueRecordId(int plugin, int index); - /// Deconstructs a unique string identifier into plugin and index. - static void parseUniqueRecordId(const std::string& id, int& plugin, int& index); - }; -} - -#endif diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index f7cb896aca..a025d407c7 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -18,14 +18,15 @@ namespace CSMWorld { const IdCollection& mCells; - void loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted) override; + void loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted, bool base) override; public: SubCellCollection(const IdCollection& cells); }; template - void SubCellCollection::loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted) + void SubCellCollection::loadRecord( + ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted, bool base) { record.load(reader, isDeleted, mCells); } diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index ff9a8e09b1..07745a449d 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include @@ -44,12 +43,7 @@ namespace CSVRender 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().mTexture; + return mData.getLandTextures().getLandTexture(index, plugin); } void TerrainStorage::setAlteredHeight(int inCellX, int inCellY, float height) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 554e312527..cfc7f50cf1 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -38,7 +38,6 @@ #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/idtree.hpp" -#include "../../model/world/landtexture.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/universalid.hpp" @@ -52,7 +51,6 @@ CSVRender::TerrainTextureMode::TerrainTextureMode( WorldspaceWidget* worldspaceWidget, osg::Group* parentNode, QWidget* parent) : EditMode(worldspaceWidget, Misc::ScalableIcon::load(":scenetoolbar/editing-terrain-texture"), Mask_Terrain | Mask_Reference, "Terrain texture editing", parent) - , mBrushTexture("L0#0") , mBrushSize(1) , mBrushShape(CSVWidget::BrushShape_Point) , mTextureBrushScenetool(nullptr) @@ -137,8 +135,8 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult mCellId = getWorldspaceWidget().getCellId(hit.worldPos); QUndoStack& undoStack = document.getUndoStack(); - CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); - int index = landtexturesCollection.searchId(ESM::RefId::stringRefId(mBrushTexture)); + CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); + int index = landtexturesCollection.searchId(mBrushTexture); if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == nullptr) { @@ -186,8 +184,8 @@ bool CSVRender::TerrainTextureMode::primaryEditStartDrag(const QPoint& pos) mDragMode = InteractionType_PrimaryEdit; - CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); - const int index = landtexturesCollection.searchId(ESM::RefId::stringRefId(mBrushTexture)); + CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); + const int index = landtexturesCollection.searchId(mBrushTexture); if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == nullptr) { @@ -242,8 +240,8 @@ void CSVRender::TerrainTextureMode::drag(const QPoint& pos, int diffX, int diffY std::string cellId = getWorldspaceWidget().getCellId(hit.worldPos); CSMDoc::Document& document = getWorldspaceWidget().getDocument(); - CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); - const int index = landtexturesCollection.searchId(ESM::RefId::stringRefId(mBrushTexture)); + CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); + const int index = landtexturesCollection.searchId(mBrushTexture); if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == nullptr) { @@ -273,8 +271,8 @@ void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) CSMDoc::Document& document = getWorldspaceWidget().getDocument(); QUndoStack& undoStack = document.getUndoStack(); - CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); - const int index = landtexturesCollection.searchId(ESM::RefId::stringRefId(mBrushTexture)); + CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); + const int index = landtexturesCollection.searchId(mBrushTexture); if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) { @@ -303,18 +301,7 @@ void CSVRender::TerrainTextureMode::handleDropEvent(QDropEvent* event) for (const CSMWorld::UniversalId& uid : ids) { - mBrushTexture = uid.getId(); - emit passBrushTexture(mBrushTexture); - } - } - if (mime->holdsType(CSMWorld::UniversalId::Type_Texture)) - { - const std::vector ids = mime->getData(); - - for (const CSMWorld::UniversalId& uid : ids) - { - std::string textureFileName = uid.toString(); - createTexture(textureFileName); + mBrushTexture = ESM::RefId::stringRefId(uid.getId()); emit passBrushTexture(mBrushTexture); } } @@ -359,11 +346,8 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex); - std::size_t hashlocation = mBrushTexture.find('#'); - std::string mBrushTextureInt = mBrushTexture.substr(hashlocation + 1); - // All indices are offset by +1 - int brushInt = Misc::StringUtils::toNumeric(mBrushTexture.substr(hashlocation + 1), 0) + 1; + uint32_t brushInt = document.getData().getLandTextures().getRecord(mBrushTexture).get().mIndex + 1; int r = static_cast(mBrushSize) / 2; @@ -662,50 +646,6 @@ void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColu undoStack.push(new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId)); } -void CSVRender::TerrainTextureMode::createTexture(const std::string& textureFileName) -{ - CSMDoc::Document& document = getWorldspaceWidget().getDocument(); - - CSMWorld::IdTable& ltexTable - = dynamic_cast(*document.getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); - - QUndoStack& undoStack = document.getUndoStack(); - - std::string newId; - - int counter = 0; - bool freeIndexFound = false; - do - { - const size_t maxCounter = std::numeric_limits::max() - 1; - try - { - newId = CSMWorld::LandTexture::createUniqueRecordId(-1, counter); - if (!ltexTable.getRecord(newId).isDeleted()) - counter = (counter + 1) % maxCounter; - } - catch (const std::exception&) - { - newId = CSMWorld::LandTexture::createUniqueRecordId(-1, counter); - freeIndexFound = true; - } - } while (freeIndexFound == false); - - std::size_t idlocation = textureFileName.find("Texture: "); - QString fileName = QString::fromStdString(textureFileName.substr(idlocation + 9)); - - QVariant textureFileNameVariant; - textureFileNameVariant.setValue(fileName); - - undoStack.beginMacro("Add land texture record"); - - undoStack.push(new CSMWorld::CreateCommand(ltexTable, newId)); - QModelIndex index(ltexTable.getModelIndex(newId, ltexTable.findColumnIndex(CSMWorld::Columns::ColumnId_Texture))); - undoStack.push(new CSMWorld::ModifyCommand(ltexTable, index, textureFileNameVariant)); - undoStack.endMacro(); - mBrushTexture = std::move(newId); -} - bool CSVRender::TerrainTextureMode::allowLandTextureEditing(const std::string& cellId) { CSMDoc::Document& document = getWorldspaceWidget().getDocument(); @@ -832,7 +772,7 @@ void CSVRender::TerrainTextureMode::setBrushShape(CSVWidget::BrushShape brushSha } } -void CSVRender::TerrainTextureMode::setBrushTexture(std::string brushTexture) +void CSVRender::TerrainTextureMode::setBrushTexture(ESM::RefId brushTexture) { - mBrushTexture = std::move(brushTexture); + mBrushTexture = brushTexture; } diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index c4b0b5ffd4..6045f2e26b 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -117,14 +117,11 @@ namespace CSVRender void pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, CSMWorld::IdTable& landTable, std::string cellId); - /// \brief Create new land texture record from texture asset - void createTexture(const std::string& textureFileName); - /// \brief Create new cell and land if needed bool allowLandTextureEditing(const std::string& textureFileName); std::string mCellId; - std::string mBrushTexture; + ESM::RefId mBrushTexture; int mBrushSize; CSVWidget::BrushShape mBrushShape; std::unique_ptr mBrushDraw; @@ -139,13 +136,13 @@ namespace CSVRender const int landTextureSize{ ESM::Land::LAND_TEXTURE_SIZE }; signals: - void passBrushTexture(std::string brushTexture); + void passBrushTexture(ESM::RefId brushTexture); public slots: void handleDropEvent(QDropEvent* event); void setBrushSize(int brushSize); void setBrushShape(CSVWidget::BrushShape brushShape); - void setBrushTexture(std::string brushShape); + void setBrushTexture(ESM::RefId brushShape); }; } diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index dcdd2f0412..27d628a384 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,6 @@ #include "../../model/world/data.hpp" #include "../../model/world/idcollection.hpp" #include "../../model/world/idtable.hpp" -#include "../../model/world/landtexture.hpp" #include "../../model/world/universalid.hpp" namespace CSVWidget @@ -74,12 +74,12 @@ CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QW : QFrame(parent, Qt::Popup) , mDocument(document) { - mBrushTextureLabel = "Selected texture: " + mBrushTexture + " "; + mBrushTextureLabel = "Selected texture: " + mBrushTexture.getRefIdString() + " "; - CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); + CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); - const int index = landtexturesCollection.searchId(ESM::RefId::stringRefId(mBrushTexture)); + const int index = landtexturesCollection.searchId(mBrushTexture); if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) { @@ -154,68 +154,38 @@ void CSVWidget::TextureBrushWindow::configureButtonInitialSettings(QPushButton* button->setCheckable(true); } -void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture) +void CSVWidget::TextureBrushWindow::setBrushTexture(ESM::RefId brushTexture) { CSMWorld::IdTable& ltexTable = dynamic_cast( *mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); QUndoStack& undoStack = mDocument.getUndoStack(); - CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); + CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); - int index = 0; - int pluginInDragged = 0; - CSMWorld::LandTexture::parseUniqueRecordId(brushTexture, pluginInDragged, index); - const ESM::RefId brushTextureRefId = ESM::RefId::stringRefId(brushTexture); - std::string newBrushTextureId = CSMWorld::LandTexture::createUniqueRecordId(-1, index); - ESM::RefId newBrushTextureRefId = ESM::RefId::stringRefId(newBrushTextureId); - int rowInBase = landtexturesCollection.searchId(brushTextureRefId); - int rowInNew = landtexturesCollection.searchId(newBrushTextureRefId); - - // Check if texture exists in current plugin, and clone if id found in base, otherwise reindex the texture - // TO-DO: Handle case when texture is not found in neither base or plugin properly (finding new index is not enough) - // TO-DO: Handle conflicting plugins properly - if (rowInNew == -1) + int row = landtexturesCollection.getIndex(brushTexture); + const auto& record = landtexturesCollection.getRecord(row); + + if (!record.isDeleted()) { - if (rowInBase == -1) + // Ensure the texture is defined by the current plugin + if (!record.isModified()) { - int counter = 0; - bool freeIndexFound = false; - const int maxCounter = std::numeric_limits::max() - 1; - do - { - newBrushTextureId = CSMWorld::LandTexture::createUniqueRecordId(-1, counter); - newBrushTextureRefId = ESM::RefId::stringRefId(newBrushTextureId); - if (landtexturesCollection.searchId(brushTextureRefId) != -1 - && landtexturesCollection.getRecord(brushTextureRefId).isDeleted() == 0 - && landtexturesCollection.searchId(newBrushTextureRefId) != -1 - && landtexturesCollection.getRecord(newBrushTextureRefId).isDeleted() == 0) - counter = (counter + 1) % maxCounter; - else - freeIndexFound = true; - } while (freeIndexFound == false || counter < maxCounter); + CSMWorld::CommandMacro macro(undoStack); + macro.push(new CSMWorld::TouchCommand(ltexTable, brushTexture.getRefIdString())); } - - undoStack.beginMacro("Add land texture record"); - undoStack.push(new CSMWorld::CloneCommand( - ltexTable, brushTexture, newBrushTextureId, CSMWorld::UniversalId::Type_LandTexture)); - undoStack.endMacro(); - } - - if (index != -1 && !landtexturesCollection.getRecord(rowInNew).isDeleted()) - { - mBrushTextureLabel = "Selected texture: " + newBrushTextureId + " "; + mBrushTextureLabel = "Selected texture: " + brushTexture.getRefIdString() + " "; mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel) - + landtexturesCollection.getData(rowInNew, landTextureFilename).value()); + + landtexturesCollection.getData(row, landTextureFilename).value()); } else { - newBrushTextureId.clear(); + brushTexture = {}; mBrushTextureLabel = "No selected texture or invalid texture"; mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel)); } - mBrushTexture = std::move(newBrushTextureId); + mBrushTexture = brushTexture; emit passTextureId(mBrushTexture); emit passBrushShape(mBrushShape); // updates the icon tooltip @@ -250,7 +220,6 @@ CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush( , mTextureBrushWindow(new TextureBrushWindow(document, this)) { mBrushHistory.resize(1); - mBrushHistory[0] = "L0#0"; setAcceptDrops(true); connect(mTextureBrushWindow, &TextureBrushWindow::passBrushShape, this, &SceneToolTextureBrush::setButtonIcon); @@ -309,14 +278,15 @@ void CSVWidget::SceneToolTextureBrush::setButtonIcon(CSVWidget::BrushShape brush tooltip += "

(right click to access of previously used brush settings)"; - CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); + CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); - const int index = landtexturesCollection.searchId(ESM::RefId::stringRefId(mTextureBrushWindow->mBrushTexture)); + const int index = landtexturesCollection.searchId(mTextureBrushWindow->mBrushTexture); if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) { - tooltip += "

Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture) + " "; + tooltip += "

Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture.getRefIdString()) + + " "; tooltip += landtexturesCollection.getData(index, landTextureFilename).value(); } @@ -342,25 +312,25 @@ void CSVWidget::SceneToolTextureBrush::updatePanel() for (int i = mBrushHistory.size() - 1; i >= 0; --i) { - CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); + CSMWorld::IdCollection& landtexturesCollection = mDocument.getData().getLandTextures(); int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); - const int index = landtexturesCollection.searchId(ESM::RefId::stringRefId(mBrushHistory[i])); + const int index = landtexturesCollection.searchId(mBrushHistory[i]); if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) { mTable->setItem(i, 1, new QTableWidgetItem(landtexturesCollection.getData(index, landTextureFilename).value())); - mTable->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(mBrushHistory[i]))); + mTable->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(mBrushHistory[i].getRefIdString()))); } else { mTable->setItem(i, 1, new QTableWidgetItem("Invalid/deleted texture")); - mTable->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(mBrushHistory[i]))); + mTable->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(mBrushHistory[i].getRefIdString()))); } } } -void CSVWidget::SceneToolTextureBrush::updateBrushHistory(const std::string& brushTexture) +void CSVWidget::SceneToolTextureBrush::updateBrushHistory(ESM::RefId brushTexture) { mBrushHistory.insert(mBrushHistory.begin(), brushTexture); if (mBrushHistory.size() > 5) @@ -371,7 +341,7 @@ void CSVWidget::SceneToolTextureBrush::clicked(const QModelIndex& index) { if (index.column() == 0 || index.column() == 1) { - std::string brushTexture = mBrushHistory[index.row()]; + ESM::RefId brushTexture = mBrushHistory[index.row()]; std::swap(mBrushHistory[index.row()], mBrushHistory[0]); mTextureBrushWindow->setBrushTexture(brushTexture); emit passTextureId(brushTexture); diff --git a/apps/opencs/view/widget/scenetooltexturebrush.hpp b/apps/opencs/view/widget/scenetooltexturebrush.hpp index 940ab60ee7..09c7ef43f0 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.hpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.hpp @@ -9,6 +9,8 @@ #include "scenetool.hpp" #endif +#include + class QTableWidget; class QDragEnterEvent; class QDropEvent; @@ -70,7 +72,7 @@ namespace CSVWidget private: CSVWidget::BrushShape mBrushShape = CSVWidget::BrushShape_Point; int mBrushSize = 1; - std::string mBrushTexture = "L0#0"; + ESM::RefId mBrushTexture; CSMDoc::Document& mDocument; QLabel* mSelectedBrush; QGroupBox* mHorizontalGroupBox; @@ -85,14 +87,14 @@ namespace CSVWidget friend class CSVRender::TerrainTextureMode; public slots: - void setBrushTexture(std::string brushTexture); + void setBrushTexture(ESM::RefId brushTexture); void setBrushShape(); void setBrushSize(int brushSize); signals: void passBrushSize(int brushSize); void passBrushShape(CSVWidget::BrushShape brushShape); - void passTextureId(std::string brushTexture); + void passTextureId(ESM::RefId brushTexture); }; class SceneToolTextureBrush : public SceneTool @@ -103,7 +105,7 @@ namespace CSVWidget CSMDoc::Document& mDocument; QFrame* mPanel; QTableWidget* mTable; - std::vector mBrushHistory; + std::vector mBrushHistory; TextureBrushWindow* mTextureBrushWindow; private: @@ -122,14 +124,14 @@ namespace CSVWidget public slots: void setButtonIcon(CSVWidget::BrushShape brushShape); - void updateBrushHistory(const std::string& mBrushTexture); + void updateBrushHistory(ESM::RefId mBrushTexture); void clicked(const QModelIndex& index); void activate() override; signals: void passEvent(QDropEvent* event); void passEvent(QDragEnterEvent* event); - void passTextureId(std::string brushTexture); + void passTextureId(ESM::RefId brushTexture); }; } diff --git a/apps/opencs/view/world/landtexturecreator.cpp b/apps/opencs/view/world/landtexturecreator.cpp deleted file mode 100644 index 1d2af5005f..0000000000 --- a/apps/opencs/view/world/landtexturecreator.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "landtexturecreator.hpp" - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include "../../model/world/commands.hpp" -#include "../../model/world/idtable.hpp" -#include "../../model/world/landtexture.hpp" - -namespace CSVWorld -{ - LandTextureCreator::LandTextureCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id) - : GenericCreator(data, undoStack, id) - { - // One index is reserved for a default texture - const size_t MaxIndex = std::numeric_limits::max() - 1; - - setManualEditing(false); - - QLabel* nameLabel = new QLabel("Name"); - insertBeforeButtons(nameLabel, false); - - mNameEdit = new QLineEdit(this); - insertBeforeButtons(mNameEdit, true); - - QLabel* indexLabel = new QLabel("Index"); - insertBeforeButtons(indexLabel, false); - - mIndexBox = new QSpinBox(this); - mIndexBox->setMinimum(0); - mIndexBox->setMaximum(MaxIndex); - insertBeforeButtons(mIndexBox, true); - - connect(mNameEdit, &QLineEdit::textChanged, this, &LandTextureCreator::nameChanged); - connect(mIndexBox, qOverload(&QSpinBox::valueChanged), this, &LandTextureCreator::indexChanged); - } - - void LandTextureCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) - { - GenericCreator::cloneMode(originId, type); - - CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); - - int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureNickname); - mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); - - column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex); - mIndexBox->setValue((table.data(table.getModelIndex(originId, column)).toInt())); - } - - void LandTextureCreator::focus() - { - mIndexBox->setFocus(); - } - - void LandTextureCreator::reset() - { - GenericCreator::reset(); - mNameEdit->setText(""); - mIndexBox->setValue(0); - } - - std::string LandTextureCreator::getErrors() const - { - if (getData().getLandTextures().searchId(ESM::RefId::stringRefId(getId())) >= 0) - { - return "Index is already in use"; - } - - return ""; - } - - void LandTextureCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const - { - GenericCreator::configureCreateCommand(command); - - CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); - int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureNickname); - command.addValue(column, mName.c_str()); - } - - std::string LandTextureCreator::getId() const - { - return CSMWorld::LandTexture::createUniqueRecordId(-1, mIndexBox->value()); - } - - void LandTextureCreator::nameChanged(const QString& value) - { - mName = value.toUtf8().constData(); - update(); - } - - void LandTextureCreator::indexChanged(int value) - { - update(); - } -} diff --git a/apps/opencs/view/world/landtexturecreator.hpp b/apps/opencs/view/world/landtexturecreator.hpp deleted file mode 100644 index a2ebf093fb..0000000000 --- a/apps/opencs/view/world/landtexturecreator.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef CSV_WORLD_LANDTEXTURECREATOR_H -#define CSV_WORLD_LANDTEXTURECREATOR_H - -#include - -#include "genericcreator.hpp" - -#include - -namespace CSMWorld -{ - class CreateCommand; - class Data; -} - -class QLineEdit; -class QSpinBox; - -namespace CSVWorld -{ - class LandTextureCreator : public GenericCreator - { - Q_OBJECT - - public: - LandTextureCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id); - - void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override; - - void focus() override; - - void reset() override; - - std::string getErrors() const override; - - protected: - void configureCreateCommand(CSMWorld::CreateCommand& command) const override; - - std::string getId() const override; - - private slots: - - void nameChanged(const QString& val); - void indexChanged(int val); - - private: - QLineEdit* mNameEdit; - QSpinBox* mIndexBox; - - std::string mName; - }; -} - -#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 0e1f34d2dd..8a47f95e63 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -10,7 +10,6 @@ #include "globalcreator.hpp" #include "infocreator.hpp" #include "landcreator.hpp" -#include "landtexturecreator.hpp" #include "pathgridcreator.hpp" #include "previewsubview.hpp" #include "referenceablecreator.hpp" @@ -92,7 +91,7 @@ void CSVWorld::addSubViewFactories(CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator>); manager.add(CSMWorld::UniversalId::Type_LandTextures, - new CSVDoc::SubViewFactoryWithCreator>); + new CSVDoc::SubViewFactoryWithCreator>); manager.add(CSMWorld::UniversalId::Type_Globals, new CSVDoc::SubViewFactoryWithCreator>); @@ -195,7 +194,7 @@ void CSVWorld::addSubViewFactories(CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator>(false)); manager.add(CSMWorld::UniversalId::Type_LandTexture, - new CSVDoc::SubViewFactoryWithCreator>(false)); + new CSVDoc::SubViewFactoryWithCreator>(false)); manager.add(CSMWorld::UniversalId::Type_DebugProfile, new CSVDoc::SubViewFactoryWithCreator