From 6d9d98c02cc663d67372a65c1aaea58b35dacc23 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 11:32:42 -0400 Subject: [PATCH 1/5] Merge Land/LandTextures --- apps/opencs/model/tools/mergeoperation.cpp | 4 +- apps/opencs/model/tools/mergestages.cpp | 147 ++++++--------------- apps/opencs/model/tools/mergestages.hpp | 15 ++- 3 files changed, 47 insertions(+), 119 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 9b595046a..cbd2abe0d 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -38,9 +38,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeRefIdsStage (mState)); appendStage (new MergeReferencesStage (mState)); appendStage (new MergeReferencesStage (mState)); - appendStage (new ListLandTexturesMergeStage (mState)); - appendStage (new MergeLandTexturesStage (mState)); + appendStage (new PopulateLandTexturesMergeStage (mState)); appendStage (new MergeLandStage (mState)); + appendStage (new FixLandsAndLandTexturesMergeStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 176d35914..eea0656b7 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -8,7 +8,9 @@ #include "mergestate.hpp" #include "../doc/document.hpp" +#include "../world/commands.hpp" #include "../world/data.hpp" +#include "../world/idtable.hpp" CSMTools::StartMergeStage::StartMergeStage (MergeState& state) @@ -109,102 +111,32 @@ void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messa } -CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state) -: mState (state) -{} - -int CSMTools::ListLandTexturesMergeStage::setup() +CSMTools::PopulateLandTexturesMergeStage::PopulateLandTexturesMergeStage (MergeState& state) + : mState (state) { - return mState.mSource.getData().getLand().getSize(); -} - -void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) -{ - const CSMWorld::Record& record = - mState.mSource.getData().getLand().getRecord (stage); - - if (!record.isDeleted()) - { - const CSMWorld::Land& land = record.get(); - - // make sure record is loaded - land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | - ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX); - - if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX)) - { - // list texture indices - std::pair key; - key.second = land.mPlugin; - - for (int i=0; imTextures[i]; - - mState.mTextureIndices[key] = -1; - } - } - } } - -CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state) -: mState (state), mNext (mState.mTextureIndices.end()) -{} - -int CSMTools::MergeLandTexturesStage::setup() +int CSMTools::PopulateLandTexturesMergeStage::setup() { - // Should use the size of mState.mTextureIndices instead, but that is not available at this - // point. Unless there are any errors in the land and land texture records this will not - // make a difference. return mState.mSource.getData().getLandTextures().getSize(); } -void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages) +void CSMTools::PopulateLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) { - if (stage==0) - mNext = mState.mTextureIndices.begin(); + const CSMWorld::Record& record = + mState.mSource.getData().getLandTextures().getRecord (stage); - bool found = false; - - do + if (!record.isDeleted()) { - if (mNext==mState.mTextureIndices.end()) - return; - - mNext->second = stage+1; - - std::ostringstream stream; - stream << mNext->first.first-1 << "_" << mNext->first.second; - - int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); - - if (index!=-1) - { - CSMWorld::LandTexture texture = - mState.mSource.getData().getLandTextures().getRecord (index).get(); - - stream.clear(); - stream << mNext->second-1 << "_0"; - - texture.mIndex = mNext->second-1; - texture.mId = stream.str(); - - CSMWorld::Record newRecord ( - CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); - - mState.mTarget->getData().getLandTextures().appendRecord (newRecord); - - found = true; - } - - ++mNext; + mState.mTarget->getData().getLandTextures().appendRecord(record); } - while (!found); } -CSMTools::MergeLandStage::MergeLandStage (MergeState& state) : mState (state) {} +CSMTools::MergeLandStage::MergeLandStage (MergeState& state) + : mState (state) +{ +} int CSMTools::MergeLandStage::setup() { @@ -218,40 +150,35 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages) if (!record.isDeleted()) { - const CSMWorld::Land& land = record.get(); - - land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | - ESM::Land::DATA_VTEX); + mState.mTarget->getData().getLand().appendRecord (record); + } +} - CSMWorld::Land newLand (land); - newLand.mPlugin = 0; +CSMTools::FixLandsAndLandTexturesMergeStage::FixLandsAndLandTexturesMergeStage (MergeState& state) + : mState (state) +{ +} - if (land.mDataTypes & ESM::Land::DATA_VTEX) - { - // adjust land texture references - if (ESM::Land::LandData *data = newLand.getLandData()) - { - std::pair key; - key.second = land.mPlugin; +int CSMTools::FixLandsAndLandTexturesMergeStage::setup() +{ + // We will have no more than the source + return mState.mSource.getData().getLand().getSize(); +} - for (int i=0; imTextures[i]; - std::map, int>::const_iterator iter = - mState.mTextureIndices.find (key); +void CSMTools::FixLandsAndLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + if (stage < mState.mTarget->getData().getLand().getSize()) + { + CSMWorld::IdTable& landTable = dynamic_cast( + *mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); - if (iter!=mState.mTextureIndices.end()) - data->mTextures[i] = iter->second; - else - data->mTextures[i] = 0; - } - } - } + CSMWorld::IdTable& ltexTable = dynamic_cast( + *mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); - CSMWorld::Record newRecord ( - CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand); + std::string id = mState.mTarget->getData().getLand().getId(stage); - mState.mTarget->getData().getLand().appendRecord (newRecord); + CSMWorld::TouchLandCommand cmd(landTable, ltexTable, id); + cmd.redo(); } } diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index f88f5be9f..96339ed4c 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -116,13 +116,14 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - class ListLandTexturesMergeStage : public CSMDoc::Stage + /// Adds all land texture records that could potentially be referenced when merging + class PopulateLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; public: - ListLandTexturesMergeStage (MergeState& state); + PopulateLandTexturesMergeStage (MergeState& state); virtual int setup(); ///< \return number of steps @@ -131,14 +132,13 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - class MergeLandTexturesStage : public CSMDoc::Stage + class MergeLandStage : public CSMDoc::Stage { MergeState& mState; - std::map, int>::iterator mNext; public: - MergeLandTexturesStage (MergeState& state); + MergeLandStage (MergeState& state); virtual int setup(); ///< \return number of steps @@ -147,13 +147,14 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - class MergeLandStage : public CSMDoc::Stage + /// Flattens the added land and land texture records. + class FixLandsAndLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; public: - MergeLandStage (MergeState& state); + FixLandsAndLandTexturesMergeStage (MergeState& state); virtual int setup(); ///< \return number of steps From 98c38ad7d1201fe951d8c94ffcff4175f7c90875 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 13:18:31 -0400 Subject: [PATCH 2/5] Merge cleanup. --- apps/opencs/model/tools/mergeoperation.cpp | 1 + apps/opencs/model/tools/mergestages.cpp | 31 ++++++++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 16 +++++++++++ 3 files changed, 48 insertions(+) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index cbd2abe0d..b15b4b83f 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -41,6 +41,7 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new PopulateLandTexturesMergeStage (mState)); appendStage (new MergeLandStage (mState)); appendStage (new FixLandsAndLandTexturesMergeStage (mState)); + appendStage (new CleanupLandTexturesMergeStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index eea0656b7..897c3329c 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -180,5 +180,36 @@ void CSMTools::FixLandsAndLandTexturesMergeStage::perform (int stage, CSMDoc::Me CSMWorld::TouchLandCommand cmd(landTable, ltexTable, id); cmd.redo(); + + // Get rid of base data + const CSMWorld::Record& oldRecord = + mState.mTarget->getData().getLand().getRecord (stage); + + CSMWorld::Record newRecord(CSMWorld::RecordBase::State_ModifiedOnly, + nullptr, &oldRecord.get()); + + mState.mTarget->getData().getLand().setRecord(stage, newRecord); + } +} + +CSMTools::CleanupLandTexturesMergeStage::CleanupLandTexturesMergeStage (MergeState& state) + : mState (state) +{ +} + +int CSMTools::CleanupLandTexturesMergeStage::setup() +{ + return 1; +} + +void CSMTools::CleanupLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + auto& landTextures = mState.mTarget->getData().getLandTextures(); + for (int i = 0; i < landTextures.getSize(); ) + { + if (!landTextures.getRecord(i).isModified()) + landTextures.removeRows(i, 1); + else + ++i; } } diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 96339ed4c..9a16e03ab 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -162,6 +162,22 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + // Removes base LandTexture records. + class CleanupLandTexturesMergeStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + CleanupLandTexturesMergeStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif From d27071f06a1276e1b5450bb8a02a565516b8b575 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 13:18:54 -0400 Subject: [PATCH 3/5] Fix LTEX import bug. --- apps/opencs/model/world/idtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index fcfc8577e..3e503a80c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -336,7 +336,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import int oldRow = idCollection()->searchId(id); // If it does not exist or it is in the current plugin, it can be skipped. - if (oldRow <= 0 || plugin == 0) + if (oldRow < 0 || plugin == 0) { results.recordMapping.push_back(std::make_pair(id, id)); continue; From 11eae166458440c99908e8a38c4b512a3e361062 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 15:09:12 -0400 Subject: [PATCH 4/5] Get rid of duplicate function, fix flag checking --- apps/opencs/model/world/columnimp.cpp | 10 +++++----- components/esm/loadland.cpp | 11 +---------- components/esm/loadland.hpp | 1 - 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 18da81b53..49e4bebe6 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -108,7 +108,7 @@ namespace CSMWorld throw std::runtime_error("invalid land map LOD data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_WNAM); + copy.add(Land::DATA_WNAM); for (int i = 0; i < values.size(); ++i) { @@ -155,7 +155,7 @@ namespace CSMWorld throw std::runtime_error("invalid land normals data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VNML); + copy.add(Land::DATA_VNML); for (int i = 0; i < values.size(); ++i) { @@ -202,7 +202,7 @@ namespace CSMWorld throw std::runtime_error("invalid land heights data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VHGT); + copy.add(Land::DATA_VHGT); for (int i = 0; i < values.size(); ++i) { @@ -249,7 +249,7 @@ namespace CSMWorld throw std::runtime_error("invalid land colours data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VCLR); + copy.add(Land::DATA_VCLR); for (int i = 0; i < values.size(); ++i) { @@ -296,7 +296,7 @@ namespace CSMWorld throw std::runtime_error("invalid land textures data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VTEX); + copy.add(Land::DATA_VTEX); for (int i = 0; i < values.size(); ++i) { diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index f3f72e88a..a91dfe3d3 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -315,16 +315,7 @@ namespace ESM bool Land::isDataLoaded(int flags) const { - return mLandData && (mLandData->mDataLoaded & flags) == (flags & mDataTypes); - } - - void Land::setDataLoaded(int flags) - { - if (!mLandData) - mLandData = new LandData; - - mDataTypes |= flags; - mLandData->mDataLoaded |= flags; + return mLandData && (mLandData->mDataLoaded & flags) == flags; } Land::Land (const Land& land) diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 7be954b3e..2163c30fc 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -132,7 +132,6 @@ struct Land void unloadData() const; /// Check if given data type is loaded - /// @note We only check data types that *can* be loaded (present in mDataTypes) bool isDataLoaded(int flags) const; /// Sets the flags and creates a LandData if needed From 6d7a24224b489c6fee804fc3d05350e615c77046 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 16 Oct 2017 12:52:13 -0400 Subject: [PATCH 5/5] Add documentation. --- apps/opencs/model/tools/mergestages.hpp | 6 ++++-- apps/opencs/model/world/commands.hpp | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 9a16e03ab..4b41c5a04 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -147,7 +147,8 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - /// Flattens the added land and land texture records. + /// During this stage, the complex process of combining LandTextures from + /// potentially multiple plugins is undertaken. class FixLandsAndLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; @@ -163,7 +164,8 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - // Removes base LandTexture records. + /// Removes base LandTexture records. This gets rid of the base records previously + /// needed in FixLandsAndLandTexturesMergeStage. class CleanupLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index be86dd508..58a1b1d1c 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -44,6 +44,15 @@ namespace CSMWorld bool mChanged; }; + /// \brief Adds LandTexture records and modifies texture indices as needed. + /// + /// LandTexture records are different from other types of records, because + /// they only effect the current plugin. Thus, when modifying or copying + /// a Land record, all of the LandTexture records referenced need to be + /// added to the current plugin. Since these newly added LandTextures could + /// have indices that conflict with pre-existing LandTextures in the current + /// plugin, the indices might have to be changed, both for the newly added + /// LandRecord and within the Land record. class ImportLandTexturesCommand : public QUndoCommand { public: @@ -71,6 +80,9 @@ namespace CSMWorld std::vector mCreatedTextures; }; + /// \brief This command is used to fix LandTexture records and texture + /// indices after cloning a Land. See ImportLandTexturesCommand for + /// details. class CopyLandTexturesCommand : public ImportLandTexturesCommand { public: @@ -90,6 +102,9 @@ namespace CSMWorld std::string mDestId; }; + /// \brief This command brings a land record into the current plugin, adding + /// LandTexture records and modifying texture indices as needed. + /// \note See ImportLandTextures for more details. class TouchLandCommand : public ImportLandTexturesCommand { public: