Rework land texture handling

This commit is contained in:
Evil Eye 2024-06-12 17:09:28 +02:00
parent 965bc20bab
commit fbc6629d40
25 changed files with 284 additions and 630 deletions

View File

@ -25,7 +25,7 @@ opencs_units (model/world
opencs_units (model/world opencs_units (model/world
universalid record commands columnbase columnimp scriptcontext cell refidcollection universalid record commands columnbase columnimp scriptcontext cell refidcollection
refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope 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 idcompletionmanager metadata defaultgmsts infoselectwrapper commandmacro
) )
@ -70,7 +70,7 @@ opencs_units (view/world
cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
bodypartcreator landtexturecreator landcreator tableheadermouseeventhandler bodypartcreator landcreator tableheadermouseeventhandler
) )
opencs_units (view/world opencs_units (view/world

View File

@ -17,7 +17,6 @@
#include <apps/opencs/model/world/idcollection.hpp> #include <apps/opencs/model/world/idcollection.hpp>
#include <apps/opencs/model/world/info.hpp> #include <apps/opencs/model/world/info.hpp>
#include <apps/opencs/model/world/land.hpp> #include <apps/opencs/model/world/land.hpp>
#include <apps/opencs/model/world/landtexture.hpp>
#include <apps/opencs/model/world/metadata.hpp> #include <apps/opencs/model/world/metadata.hpp>
#include <apps/opencs/model/world/pathgrid.hpp> #include <apps/opencs/model/world/pathgrid.hpp>
#include <apps/opencs/model/world/record.hpp> #include <apps/opencs/model/world/record.hpp>
@ -498,11 +497,11 @@ int CSMDoc::WriteLandTextureCollectionStage::setup()
void CSMDoc::WriteLandTextureCollectionStage::perform(int stage, Messages& messages) void CSMDoc::WriteLandTextureCollectionStage::perform(int stage, Messages& messages)
{ {
ESM::ESMWriter& writer = mState.getWriter(); ESM::ESMWriter& writer = mState.getWriter();
const CSMWorld::Record<CSMWorld::LandTexture>& landTexture = mDocument.getData().getLandTextures().getRecord(stage); const CSMWorld::Record<ESM::LandTexture>& landTexture = mDocument.getData().getLandTextures().getRecord(stage);
if (landTexture.isModified() || landTexture.mState == CSMWorld::RecordBase::State_Deleted) if (landTexture.isModified() || landTexture.mState == CSMWorld::RecordBase::State_Deleted)
{ {
CSMWorld::LandTexture record = landTexture.get(); ESM::LandTexture record = landTexture.get();
writer.startRecord(record.sRecordId); writer.startRecord(record.sRecordId);
record.save(writer, landTexture.mState == CSMWorld::RecordBase::State_Deleted); record.save(writer, landTexture.mState == CSMWorld::RecordBase::State_Deleted);
writer.endRecord(record.sRecordId); writer.endRecord(record.sRecordId);

View File

@ -6,7 +6,6 @@
#include <vector> #include <vector>
#include <apps/opencs/model/world/land.hpp> #include <apps/opencs/model/world/land.hpp>
#include <apps/opencs/model/world/landtexture.hpp>
#include <apps/opencs/model/world/metadata.hpp> #include <apps/opencs/model/world/metadata.hpp>
#include <apps/opencs/model/world/ref.hpp> #include <apps/opencs/model/world/ref.hpp>
#include <apps/opencs/model/world/refcollection.hpp> #include <apps/opencs/model/world/refcollection.hpp>
@ -137,13 +136,12 @@ int CSMTools::PopulateLandTexturesMergeStage::setup()
void CSMTools::PopulateLandTexturesMergeStage::perform(int stage, CSMDoc::Messages& messages) void CSMTools::PopulateLandTexturesMergeStage::perform(int stage, CSMDoc::Messages& messages)
{ {
const CSMWorld::Record<CSMWorld::LandTexture>& record = mState.mSource.getData().getLandTextures().getRecord(stage); const CSMWorld::Record<ESM::LandTexture>& record = mState.mSource.getData().getLandTextures().getRecord(stage);
if (!record.isDeleted()) if (!record.isDeleted())
{ {
mState.mTarget->getData().getLandTextures().appendRecord( mState.mTarget->getData().getLandTextures().appendRecord(std::make_unique<CSMWorld::Record<ESM::LandTexture>>(
std::make_unique<CSMWorld::Record<CSMWorld::LandTexture>>(CSMWorld::Record<CSMWorld::LandTexture>( CSMWorld::Record<ESM::LandTexture>(CSMWorld::RecordBase::State_ModifiedOnly, nullptr, &record.get())));
CSMWorld::RecordBase::State_ModifiedOnly, nullptr, &record.get())));
} }
} }

View File

@ -24,7 +24,6 @@
#include "columnimp.hpp" #include "columnimp.hpp"
#include "info.hpp" #include "info.hpp"
#include "land.hpp" #include "land.hpp"
#include "landtexture.hpp"
#include "record.hpp" #include "record.hpp"
#include "ref.hpp" #include "ref.hpp"
@ -74,16 +73,6 @@ namespace CSMWorld
return ESM::RefId::stringRefId(Land::createUniqueRecordId(record.mX, record.mY)); 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) inline ESM::RefId getRecordId(const ESM::MagicEffect& record)
{ {
return ESM::RefId::stringRefId(CSMWorld::getStringId(record.mId)); return ESM::RefId::stringRefId(CSMWorld::getStringId(record.mId));
@ -95,11 +84,6 @@ namespace CSMWorld
record.mId = ESM::RefId::index(ESM::REC_MGEF, static_cast<std::uint32_t>(index)); record.mId = ESM::RefId::index(ESM::REC_MGEF, static_cast<std::uint32_t>(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) inline void setRecordId(const ESM::RefId& id, ESM::Skill& record)
{ {
if (const auto* skillId = id.getIf<ESM::SkillId>()) if (const auto* skillId = id.getIf<ESM::SkillId>())
@ -339,7 +323,7 @@ namespace CSMWorld
const ESM::RefId& origin, const ESM::RefId& destination, const UniversalId::Type type) const ESM::RefId& origin, const ESM::RefId& destination, const UniversalId::Type type)
{ {
const int index = cloneRecordImp(origin, destination, type); const int index = cloneRecordImp(origin, destination, type);
mRecords.at(index)->get().setPlugin(0); mRecords.at(index)->get().setPlugin(-1);
} }
template <typename ESXRecordT> template <typename ESXRecordT>
@ -354,7 +338,7 @@ namespace CSMWorld
const int index = touchRecordImp(id); const int index = touchRecordImp(id);
if (index >= 0) if (index >= 0)
{ {
mRecords.at(index)->get().setPlugin(0); mRecords.at(index)->get().setPlugin(-1);
return true; return true;
} }

View File

@ -3,10 +3,10 @@
#include <apps/opencs/model/world/columnbase.hpp> #include <apps/opencs/model/world/columnbase.hpp>
#include <apps/opencs/model/world/columns.hpp> #include <apps/opencs/model/world/columns.hpp>
#include <apps/opencs/model/world/land.hpp> #include <apps/opencs/model/world/land.hpp>
#include <apps/opencs/model/world/landtexture.hpp>
#include <apps/opencs/model/world/record.hpp> #include <apps/opencs/model/world/record.hpp>
#include <components/esm3/loadland.hpp> #include <components/esm3/loadland.hpp>
#include <components/esm3/loadltex.hpp>
#include <components/esm3/loadmgef.hpp> #include <components/esm3/loadmgef.hpp>
#include <algorithm> #include <algorithm>
@ -45,36 +45,13 @@ namespace CSMWorld
}; };
} }
/* LandTextureNicknameColumn */
LandTextureNicknameColumn::LandTextureNicknameColumn()
: Column<LandTexture>(Columns::ColumnId_TextureNickname, ColumnBase::Display_String)
{
}
QVariant LandTextureNicknameColumn::get(const Record<LandTexture>& record) const
{
return QString::fromStdString(record.get().mId.toString());
}
void LandTextureNicknameColumn::set(Record<LandTexture>& 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::LandTextureIndexColumn() LandTextureIndexColumn::LandTextureIndexColumn()
: Column<LandTexture>(Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) : Column<ESM::LandTexture>(Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer)
{ {
} }
QVariant LandTextureIndexColumn::get(const Record<LandTexture>& record) const QVariant LandTextureIndexColumn::get(const Record<ESM::LandTexture>& record) const
{ {
return record.get().mIndex; return record.get().mIndex;
} }
@ -100,22 +77,6 @@ namespace CSMWorld
return false; return false;
} }
/* LandTexturePluginIndexColumn */
LandTexturePluginIndexColumn::LandTexturePluginIndexColumn()
: Column<LandTexture>(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0)
{
}
QVariant LandTexturePluginIndexColumn::get(const Record<LandTexture>& record) const
{
return record.get().mPluginIndex;
}
bool LandTexturePluginIndexColumn::isEditable() const
{
return false;
}
/* LandNormalsColumn */ /* LandNormalsColumn */
LandNormalsColumn::LandNormalsColumn() LandNormalsColumn::LandNormalsColumn()
: Column<Land>(Columns::ColumnId_LandNormalsIndex, ColumnBase::Display_String, 0) : Column<Land>(Columns::ColumnId_LandNormalsIndex, ColumnBase::Display_String, 0)

View File

@ -14,6 +14,7 @@
#include <components/esm3/loadbody.hpp> #include <components/esm3/loadbody.hpp>
#include <components/esm3/loaddial.hpp> #include <components/esm3/loaddial.hpp>
#include <components/esm3/loadinfo.hpp> #include <components/esm3/loadinfo.hpp>
#include <components/esm3/loadltex.hpp>
#include <components/esm3/loadrace.hpp> #include <components/esm3/loadrace.hpp>
#include <components/esm3/loadskil.hpp> #include <components/esm3/loadskil.hpp>
#include <components/esm3/selectiongroup.hpp> #include <components/esm3/selectiongroup.hpp>
@ -29,7 +30,6 @@
#include "columns.hpp" #include "columns.hpp"
#include "info.hpp" #include "info.hpp"
#include "land.hpp" #include "land.hpp"
#include "landtexture.hpp"
#include "record.hpp" #include "record.hpp"
namespace CSMWorld namespace CSMWorld
@ -83,13 +83,6 @@ namespace CSMWorld
return QString::fromUtf8(Land::createUniqueRecordId(land.mX, land.mY).c_str()); return QString::fromUtf8(Land::createUniqueRecordId(land.mX, land.mY).c_str());
} }
template <>
inline QVariant StringIdColumn<LandTexture>::get(const Record<LandTexture>& record) const
{
const LandTexture& ltex = record.get();
return QString::fromUtf8(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str());
}
template <typename ESXRecordT> template <typename ESXRecordT>
struct RecordStateColumn : public Column<ESXRecordT> struct RecordStateColumn : public Column<ESXRecordT>
{ {
@ -2365,20 +2358,11 @@ namespace CSMWorld
bool isEditable() const override { return true; } bool isEditable() const override { return true; }
}; };
struct LandTextureNicknameColumn : public Column<LandTexture> struct LandTextureIndexColumn : public Column<ESM::LandTexture>
{
LandTextureNicknameColumn();
QVariant get(const Record<LandTexture>& record) const override;
void set(Record<LandTexture>& record, const QVariant& data) override;
bool isEditable() const override;
};
struct LandTextureIndexColumn : public Column<LandTexture>
{ {
LandTextureIndexColumn(); LandTextureIndexColumn();
QVariant get(const Record<LandTexture>& record) const override; QVariant get(const Record<ESM::LandTexture>& record) const override;
bool isEditable() const override; bool isEditable() const override;
}; };
@ -2390,14 +2374,6 @@ namespace CSMWorld
bool isEditable() const override; bool isEditable() const override;
}; };
struct LandTexturePluginIndexColumn : public Column<LandTexture>
{
LandTexturePluginIndexColumn();
QVariant get(const Record<LandTexture>& record) const override;
bool isEditable() const override;
};
struct LandNormalsColumn : public Column<Land> struct LandNormalsColumn : public Column<Land>
{ {
using DataType = QVector<signed char>; using DataType = QVector<signed char>;

View File

@ -7,7 +7,6 @@
#include <apps/opencs/model/world/columns.hpp> #include <apps/opencs/model/world/columns.hpp>
#include <apps/opencs/model/world/land.hpp> #include <apps/opencs/model/world/land.hpp>
#include <apps/opencs/model/world/landtexture.hpp>
#include <apps/opencs/model/world/record.hpp> #include <apps/opencs/model/world/record.hpp>
#include <apps/opencs/model/world/universalid.hpp> #include <apps/opencs/model/world/universalid.hpp>
@ -61,11 +60,11 @@ CSMWorld::ImportLandTexturesCommand::ImportLandTexturesCommand(
void CSMWorld::ImportLandTexturesCommand::redo() void CSMWorld::ImportLandTexturesCommand::redo()
{ {
int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex); const int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex);
int oldPlugin = mLands.data(mLands.getModelIndex(getOriginId(), pluginColumn)).toInt(); const int oldPlugin = mLands.data(mLands.getModelIndex(getOriginId(), pluginColumn)).toInt();
// Original data // 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<DataType>(); mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).value<DataType>();
// Need to make a copy so the old values can be looked up // 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... // Perform touch/copy/etc...
onRedo(); onRedo();
// Find all indices used std::unordered_map<uint16_t, uint16_t> indexMapping;
std::unordered_set<int> texIndices; for (uint16_t index : mOld)
for (int i = 0; i < mOld.size(); ++i)
{ {
// All indices are offset by 1 for a default texture // All indices are offset by 1 for a default texture
if (mOld[i] > 0) if (index == 0)
texIndices.insert(mOld[i] - 1); continue;
if (indexMapping.contains(index))
continue;
const CSMWorld::Record<ESM::LandTexture>* record
= static_cast<LandTextureIdTable&>(mLtexs).searchRecord(index - 1, oldPlugin);
if (!record || record->isDeleted())
{
indexMapping.emplace(index, 0);
continue;
} }
if (!record->isModified())
std::vector<std::string> oldTextures;
oldTextures.reserve(texIndices.size());
for (int index : texIndices)
{ {
oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); mTouchedTextures.emplace_back(record->clone());
mLtexs.touchRecord(record->get().mId.getRefIdString());
}
indexMapping.emplace(index, record->get().mIndex + 1);
} }
// Import the textures, replace old values
LandTextureIdTable::ImportResults results = dynamic_cast<LandTextureIdTable&>(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)
{
for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i)
{ {
// All indices are offset by 1 for a default texture uint16_t oldIndex = mOld[i];
if (mOld[i] == oldIndex + 1) uint16_t newIndex = indexMapping[oldIndex];
copy[i] = newIndex + 1; copy[i] = newIndex;
}
}
} }
// Apply modification // 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(); mOldState = mLands.data(mLands.getModelIndex(getDestinationId(), stateColumn)).toInt();
QVariant variant; QVariant variant;
@ -133,12 +125,12 @@ void CSMWorld::ImportLandTexturesCommand::undo()
// Undo copy/touch/etc... // Undo copy/touch/etc...
onUndo(); onUndo();
for (const std::string& id : mCreatedTextures) for (auto& ltex : mTouchedTextures)
{ {
int row = mLtexs.getModelIndex(id, 0).row(); ESM::RefId id = static_cast<Record<ESM::LandTexture>*>(ltex.get())->get().mId;
mLtexs.removeRows(row, 1); mLtexs.setRecord(id.getRefIdString(), std::move(ltex));
} }
mCreatedTextures.clear(); mTouchedTextures.clear();
} }
CSMWorld::CopyLandTexturesCommand::CopyLandTexturesCommand( CSMWorld::CopyLandTexturesCommand::CopyLandTexturesCommand(

View File

@ -69,7 +69,7 @@ namespace CSMWorld
IdTable& mLtexs; IdTable& mLtexs;
DataType mOld; DataType mOld;
int mOldState; int mOldState;
std::vector<std::string> mCreatedTextures; std::vector<std::unique_ptr<RecordBase>> mTouchedTextures;
}; };
/// \brief This command is used to fix LandTexture records and texture /// \brief This command is used to fix LandTexture records and texture

View File

@ -16,7 +16,6 @@
#include <apps/opencs/model/world/info.hpp> #include <apps/opencs/model/world/info.hpp>
#include <apps/opencs/model/world/infocollection.hpp> #include <apps/opencs/model/world/infocollection.hpp>
#include <apps/opencs/model/world/land.hpp> #include <apps/opencs/model/world/land.hpp>
#include <apps/opencs/model/world/landtexture.hpp>
#include <apps/opencs/model/world/metadata.hpp> #include <apps/opencs/model/world/metadata.hpp>
#include <apps/opencs/model/world/nestedidcollection.hpp> #include <apps/opencs/model/world/nestedidcollection.hpp>
#include <apps/opencs/model/world/nestedinfocollection.hpp> #include <apps/opencs/model/world/nestedinfocollection.hpp>
@ -36,6 +35,7 @@
#include <components/esm3/loadcell.hpp> #include <components/esm3/loadcell.hpp>
#include <components/esm3/loaddoor.hpp> #include <components/esm3/loaddoor.hpp>
#include <components/esm3/loadglob.hpp> #include <components/esm3/loadglob.hpp>
#include <components/esm3/loadltex.hpp>
#include <components/esm3/loadstat.hpp> #include <components/esm3/loadstat.hpp>
#include <components/files/collections.hpp> #include <components/files/collections.hpp>
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
@ -530,13 +530,11 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
mLand.addColumn(new LandColoursColumn); mLand.addColumn(new LandColoursColumn);
mLand.addColumn(new LandTexturesColumn); mLand.addColumn(new LandTexturesColumn);
mLandTextures.addColumn(new StringIdColumn<LandTexture>(true)); mLandTextures.addColumn(new StringIdColumn<ESM::LandTexture>);
mLandTextures.addColumn(new RecordStateColumn<LandTexture>); mLandTextures.addColumn(new RecordStateColumn<ESM::LandTexture>);
mLandTextures.addColumn(new FixedRecordTypeColumn<LandTexture>(UniversalId::Type_LandTexture)); mLandTextures.addColumn(new FixedRecordTypeColumn<ESM::LandTexture>(UniversalId::Type_LandTexture));
mLandTextures.addColumn(new LandTextureNicknameColumn);
mLandTextures.addColumn(new LandTexturePluginIndexColumn);
mLandTextures.addColumn(new LandTextureIndexColumn); mLandTextures.addColumn(new LandTextureIndexColumn);
mLandTextures.addColumn(new TextureColumn<LandTexture>); mLandTextures.addColumn(new TextureColumn<ESM::LandTexture>);
mPathgrids.addColumn(new StringIdColumn<Pathgrid>); mPathgrids.addColumn(new StringIdColumn<Pathgrid>);
mPathgrids.addColumn(new RecordStateColumn<Pathgrid>); mPathgrids.addColumn(new RecordStateColumn<Pathgrid>);
@ -939,12 +937,12 @@ CSMWorld::IdCollection<CSMWorld::Land>& CSMWorld::Data::getLand()
return mLand; return mLand;
} }
const CSMWorld::IdCollection<CSMWorld::LandTexture>& CSMWorld::Data::getLandTextures() const const CSMWorld::IdCollection<ESM::LandTexture>& CSMWorld::Data::getLandTextures() const
{ {
return mLandTextures; return mLandTextures;
} }
CSMWorld::IdCollection<CSMWorld::LandTexture>& CSMWorld::Data::getLandTextures() CSMWorld::IdCollection<ESM::LandTexture>& CSMWorld::Data::getLandTextures()
{ {
return mLandTextures; return mLandTextures;
} }

View File

@ -24,6 +24,7 @@
#include <components/esm3/loadfact.hpp> #include <components/esm3/loadfact.hpp>
#include <components/esm3/loadglob.hpp> #include <components/esm3/loadglob.hpp>
#include <components/esm3/loadgmst.hpp> #include <components/esm3/loadgmst.hpp>
#include <components/esm3/loadltex.hpp>
#include <components/esm3/loadmgef.hpp> #include <components/esm3/loadmgef.hpp>
#include <components/esm3/loadrace.hpp> #include <components/esm3/loadrace.hpp>
#include <components/esm3/loadregn.hpp> #include <components/esm3/loadregn.hpp>
@ -43,7 +44,6 @@
#include "idcollection.hpp" #include "idcollection.hpp"
#include "infocollection.hpp" #include "infocollection.hpp"
#include "land.hpp" #include "land.hpp"
#include "landtexture.hpp"
#include "metadata.hpp" #include "metadata.hpp"
#include "nestedidcollection.hpp" #include "nestedidcollection.hpp"
#include "nestedinfocollection.hpp" #include "nestedinfocollection.hpp"
@ -114,7 +114,7 @@ namespace CSMWorld
InfoCollection mJournalInfos; InfoCollection mJournalInfos;
NestedIdCollection<Cell> mCells; NestedIdCollection<Cell> mCells;
SubCellCollection<Pathgrid> mPathgrids; SubCellCollection<Pathgrid> mPathgrids;
IdCollection<LandTexture> mLandTextures; IdCollection<ESM::LandTexture> mLandTextures;
IdCollection<Land> mLand; IdCollection<Land> mLand;
RefIdCollection mReferenceables; RefIdCollection mReferenceables;
RefCollection mRefs; RefCollection mRefs;
@ -259,9 +259,9 @@ namespace CSMWorld
IdCollection<CSMWorld::Land>& getLand(); IdCollection<CSMWorld::Land>& getLand();
const IdCollection<CSMWorld::LandTexture>& getLandTextures() const; const IdCollection<ESM::LandTexture>& getLandTextures() const;
IdCollection<CSMWorld::LandTexture>& getLandTextures(); IdCollection<ESM::LandTexture>& getLandTextures();
const IdCollection<ESM::SoundGenerator>& getSoundGens() const; const IdCollection<ESM::SoundGenerator>& getSoundGens() const;

View File

@ -8,6 +8,7 @@
#include <apps/opencs/model/world/pathgrid.hpp> #include <apps/opencs/model/world/pathgrid.hpp>
#include <apps/opencs/model/world/record.hpp> #include <apps/opencs/model/world/record.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/loadpgrd.hpp> #include <components/esm3/loadpgrd.hpp>
namespace ESM namespace ESM
@ -18,12 +19,12 @@ namespace ESM
namespace CSMWorld namespace CSMWorld
{ {
template <> template <>
int IdCollection<Pathgrid>::load(ESM::ESMReader& reader, bool base) int BaseIdCollection<Pathgrid>::load(ESM::ESMReader& reader, bool base)
{ {
Pathgrid record; Pathgrid record;
bool isDeleted = false; bool isDeleted = false;
loadRecord(record, reader, isDeleted); loadRecord(record, reader, isDeleted, base);
const ESM::RefId id = getRecordId(record); const ESM::RefId id = getRecordId(record);
int index = this->searchId(id); int index = this->searchId(id);
@ -55,4 +56,115 @@ namespace CSMWorld
return load(record, base, index); return load(record, base, index);
} }
const Record<ESM::LandTexture>* IdCollection<ESM::LandTexture>::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<ESM::LandTexture>::getLandTexture(std::uint16_t index, int plugin) const
{
const Record<ESM::LandTexture>* record = searchRecord(index, plugin);
if (record && !record->isDeleted())
return &record->get().mTexture;
return nullptr;
}
void IdCollection<ESM::LandTexture>::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<ESM::LandTexture>::assignNewIndex(ESM::RefId id)
{
std::uint16_t index = 0;
if (!mIndices.empty())
{
auto end = mIndices.lower_bound({ -1, std::numeric_limits<std::uint16_t>::max() });
if (end != mIndices.begin())
end = std::prev(end);
if (end->first.first == -1)
{
constexpr std::uint16_t maxIndex = std::numeric_limits<std::uint16_t>::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<ESM::LandTexture>::touchRecord(const ESM::RefId& id)
{
int row = BaseIdCollection<ESM::LandTexture>::touchRecordImp(id);
if (row != -1)
{
const_cast<ESM::LandTexture&>(getRecord(row).get()).mIndex = assignNewIndex(id);
return true;
}
return false;
}
void IdCollection<ESM::LandTexture>::cloneRecord(
const ESM::RefId& origin, const ESM::RefId& destination, const UniversalId::Type type)
{
int row = cloneRecordImp(origin, destination, type);
const_cast<ESM::LandTexture&>(getRecord(row).get()).mIndex = assignNewIndex(destination);
}
void IdCollection<ESM::LandTexture>::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<Record<ESM::LandTexture>>();
record2->mState = Record<ESM::LandTexture>::State_ModifiedOnly;
record2->mModified = std::move(record);
insertRecord(std::move(record2), getAppendIndex(id, type), type);
}
void IdCollection<ESM::LandTexture>::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<ESM::LandTexture>::removeRows(index, count);
}
void IdCollection<ESM::LandTexture>::replace(int index, std::unique_ptr<RecordBase> record)
{
const auto& current = getRecord(index);
if (current.isModified() && !record->isModified())
mIndices.erase({ -1, current.get().mIndex });
BaseIdCollection<ESM::LandTexture>::replace(index, std::move(record));
}
} }

View File

@ -17,6 +17,7 @@
namespace ESM namespace ESM
{ {
class ESMReader; class ESMReader;
struct LandTexture;
} }
namespace CSMWorld namespace CSMWorld
@ -25,9 +26,9 @@ namespace CSMWorld
/// \brief Single type collection of top level records /// \brief Single type collection of top level records
template <typename ESXRecordT> template <typename ESXRecordT>
class IdCollection : public Collection<ESXRecordT> class BaseIdCollection : public Collection<ESXRecordT>
{ {
virtual void loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted); virtual void loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted, bool base);
public: public:
/// \return Index of loaded record (-1 if no record was loaded) /// \return Index of loaded record (-1 if no record was loaded)
@ -46,14 +47,46 @@ namespace CSMWorld
/// \return Has the ID been deleted? /// \return Has the ID been deleted?
}; };
template <class ESXRecordT>
class IdCollection : public BaseIdCollection<ESXRecordT>
{
};
template <>
class IdCollection<ESM::LandTexture> : public BaseIdCollection<ESM::LandTexture>
{
std::map<std::pair<int, std::uint16_t>, 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<ESM::LandTexture>* 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<RecordBase> record) override;
};
template <typename ESXRecordT> template <typename ESXRecordT>
void IdCollection<ESXRecordT>::loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted) void BaseIdCollection<ESXRecordT>::loadRecord(
ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted, bool base)
{ {
record.load(reader, isDeleted); record.load(reader, isDeleted);
} }
template <> template <>
inline void IdCollection<Land>::loadRecord(Land& record, ESM::ESMReader& reader, bool& isDeleted) inline void BaseIdCollection<Land>::loadRecord(Land& record, ESM::ESMReader& reader, bool& isDeleted, bool base)
{ {
record.load(reader, isDeleted); record.load(reader, isDeleted);
@ -64,22 +97,17 @@ namespace CSMWorld
// Prevent data from being reloaded. // Prevent data from being reloaded.
record.mContext.filename.clear(); record.mContext.filename.clear();
if (!base)
record.setPlugin(-1);
} }
template <typename ESXRecordT> template <typename ESXRecordT>
int IdCollection<ESXRecordT>::load(ESM::ESMReader& reader, bool base) int BaseIdCollection<ESXRecordT>::load(ESM::ESMReader& reader, bool base)
{ {
ESXRecordT record; ESXRecordT record;
bool isDeleted = false; bool isDeleted = false;
loadRecord(record, reader, isDeleted); loadRecord(record, reader, isDeleted, base);
if constexpr (std::is_same_v<ESXRecordT, LandTexture>)
{
// 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;
}
ESM::RefId id = getRecordId(record); ESM::RefId id = getRecordId(record);
int index = this->searchId(id); int index = this->searchId(id);
@ -110,7 +138,7 @@ namespace CSMWorld
} }
template <typename ESXRecordT> template <typename ESXRecordT>
int IdCollection<ESXRecordT>::load(const ESXRecordT& record, bool base, int index) int BaseIdCollection<ESXRecordT>::load(const ESXRecordT& record, bool base, int index)
{ {
if (index == -2) // index unknown if (index == -2) // index unknown
index = this->searchId(getRecordId(record)); index = this->searchId(getRecordId(record));
@ -142,7 +170,7 @@ namespace CSMWorld
} }
template <typename ESXRecordT> template <typename ESXRecordT>
bool IdCollection<ESXRecordT>::tryDelete(const ESM::RefId& id) bool BaseIdCollection<ESXRecordT>::tryDelete(const ESM::RefId& id)
{ {
int index = this->searchId(id); int index = this->searchId(id);
@ -169,7 +197,7 @@ namespace CSMWorld
} }
template <> template <>
int IdCollection<Pathgrid>::load(ESM::ESMReader& reader, bool base); int BaseIdCollection<Pathgrid>::load(ESM::ESMReader& reader, bool base);
} }
#endif #endif

View File

@ -12,6 +12,7 @@
#include <type_traits> #include <type_traits>
#include <apps/opencs/model/world/columns.hpp> #include <apps/opencs/model/world/columns.hpp>
#include <apps/opencs/model/world/idcollection.hpp>
#include <apps/opencs/model/world/idtablebase.hpp> #include <apps/opencs/model/world/idtablebase.hpp>
#include <apps/opencs/model/world/record.hpp> #include <apps/opencs/model/world/record.hpp>
#include <apps/opencs/model/world/universalid.hpp> #include <apps/opencs/model/world/universalid.hpp>
@ -21,7 +22,6 @@
#include "collectionbase.hpp" #include "collectionbase.hpp"
#include "columnbase.hpp" #include "columnbase.hpp"
#include "landtexture.hpp"
CSMWorld::IdTable::IdTable(CollectionBase* idCollection, unsigned int features) CSMWorld::IdTable::IdTable(CollectionBase* idCollection, unsigned int features)
: IdTableBase(features) : IdTableBase(features)
@ -361,73 +361,8 @@ CSMWorld::LandTextureIdTable::LandTextureIdTable(CollectionBase* idCollection, u
{ {
} }
CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::importTextures( const CSMWorld::Record<ESM::LandTexture>* CSMWorld::LandTextureIdTable::searchRecord(
const std::vector<std::string>& ids) std::uint16_t index, int plugin) const
{ {
ImportResults results; return static_cast<CSMWorld::IdCollection<ESM::LandTexture>*>(idCollection())->searchRecord(index, plugin);
// Map existing textures to ids
std::map<std::string, std::string> reverseLookupMap;
for (int i = 0; i < idCollection()->getSize(); ++i)
{
auto& record = static_cast<const Record<LandTexture>&>(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<const Record<LandTexture>&>(idCollection()->getRecord(oldRow));
// If it is in the current plugin, it can be skipped.
if (record.mState == Record<LandTexture>::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<uint16_t>::max() - 1;
index = (index + 1) % MaxIndex;
} while (index != startIndex);
}
return results;
} }

View File

@ -16,10 +16,17 @@
class QObject; class QObject;
namespace ESM
{
struct LandTexture;
}
namespace CSMWorld namespace CSMWorld
{ {
class CollectionBase; class CollectionBase;
struct RecordBase; struct RecordBase;
template <typename ESXRecordT>
struct Record;
class IdTable : public IdTableBase class IdTable : public IdTableBase
{ {
@ -103,26 +110,12 @@ namespace CSMWorld
virtual CollectionBase* idCollection() const; 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 class LandTextureIdTable : public IdTable
{ {
public: public:
struct ImportResults
{
using StringPair = std::pair<std::string, std::string>;
/// The newly added records
std::vector<std::string> createdRecords;
/// The 1st string is the original id, the 2nd is the mapped id
std::vector<StringPair> recordMapping;
};
LandTextureIdTable(CollectionBase* idCollection, unsigned int features = 0); LandTextureIdTable(CollectionBase* idCollection, unsigned int features = 0);
/// Finds and maps/recreates the specified ids. const CSMWorld::Record<ESM::LandTexture>* searchRecord(std::uint16_t index, int plugin) const;
ImportResults importTextures(const std::vector<std::string>& ids);
}; };
} }

View File

@ -1,35 +0,0 @@
#include "landtexture.hpp"
#include <sstream>
#include <stdexcept>
#include <components/esm3/esmreader.hpp>
#include <components/misc/strings/conversion.hpp>
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<int>(id.substr(1, middle - 1), 0);
index = Misc::StringUtils::toNumeric<int>(id.substr(middle + 1), 0);
}
}

View File

@ -1,29 +0,0 @@
#ifndef CSM_WORLD_LANDTEXTURE_H
#define CSM_WORLD_LANDTEXTURE_H
#include <string>
#include <components/esm3/loadltex.hpp>
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

View File

@ -18,14 +18,15 @@ namespace CSMWorld
{ {
const IdCollection<Cell>& mCells; const IdCollection<Cell>& mCells;
void loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted) override; void loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted, bool base) override;
public: public:
SubCellCollection(const IdCollection<Cell>& cells); SubCellCollection(const IdCollection<Cell>& cells);
}; };
template <typename ESXRecordT> template <typename ESXRecordT>
void SubCellCollection<ESXRecordT>::loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted) void SubCellCollection<ESXRecordT>::loadRecord(
ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted, bool base)
{ {
record.load(reader, isDeleted, mCells); record.load(reader, isDeleted, mCells);
} }

View File

@ -7,7 +7,6 @@
#include <apps/opencs/model/world/data.hpp> #include <apps/opencs/model/world/data.hpp>
#include <apps/opencs/model/world/idcollection.hpp> #include <apps/opencs/model/world/idcollection.hpp>
#include <apps/opencs/model/world/land.hpp> #include <apps/opencs/model/world/land.hpp>
#include <apps/opencs/model/world/landtexture.hpp>
#include <apps/opencs/model/world/record.hpp> #include <apps/opencs/model/world/record.hpp>
#include <algorithm> #include <algorithm>
@ -44,12 +43,7 @@ namespace CSVRender
const std::string* 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( return mData.getLandTextures().getLandTexture(index, plugin);
ESM::RefId::stringRefId(CSMWorld::LandTexture::createUniqueRecordId(plugin, index)));
if (row == -1)
return nullptr;
return &mData.getLandTextures().getRecord(row).get().mTexture;
} }
void TerrainStorage::setAlteredHeight(int inCellX, int inCellY, float height) void TerrainStorage::setAlteredHeight(int inCellX, int inCellY, float height)

View File

@ -38,7 +38,6 @@
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/idtree.hpp" #include "../../model/world/idtree.hpp"
#include "../../model/world/landtexture.hpp"
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
@ -52,7 +51,6 @@ CSVRender::TerrainTextureMode::TerrainTextureMode(
WorldspaceWidget* worldspaceWidget, osg::Group* parentNode, QWidget* parent) WorldspaceWidget* worldspaceWidget, osg::Group* parentNode, QWidget* parent)
: EditMode(worldspaceWidget, Misc::ScalableIcon::load(":scenetoolbar/editing-terrain-texture"), : EditMode(worldspaceWidget, Misc::ScalableIcon::load(":scenetoolbar/editing-terrain-texture"),
Mask_Terrain | Mask_Reference, "Terrain texture editing", parent) Mask_Terrain | Mask_Reference, "Terrain texture editing", parent)
, mBrushTexture("L0#0")
, mBrushSize(1) , mBrushSize(1)
, mBrushShape(CSVWidget::BrushShape_Point) , mBrushShape(CSVWidget::BrushShape_Point)
, mTextureBrushScenetool(nullptr) , mTextureBrushScenetool(nullptr)
@ -137,8 +135,8 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult
mCellId = getWorldspaceWidget().getCellId(hit.worldPos); mCellId = getWorldspaceWidget().getCellId(hit.worldPos);
QUndoStack& undoStack = document.getUndoStack(); QUndoStack& undoStack = document.getUndoStack();
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures(); CSMWorld::IdCollection<ESM::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
int index = landtexturesCollection.searchId(ESM::RefId::stringRefId(mBrushTexture)); int index = landtexturesCollection.searchId(mBrushTexture);
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == nullptr) 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; mDragMode = InteractionType_PrimaryEdit;
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures(); CSMWorld::IdCollection<ESM::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
const int index = landtexturesCollection.searchId(ESM::RefId::stringRefId(mBrushTexture)); const int index = landtexturesCollection.searchId(mBrushTexture);
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == nullptr) 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); std::string cellId = getWorldspaceWidget().getCellId(hit.worldPos);
CSMDoc::Document& document = getWorldspaceWidget().getDocument(); CSMDoc::Document& document = getWorldspaceWidget().getDocument();
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures(); CSMWorld::IdCollection<ESM::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
const int index = landtexturesCollection.searchId(ESM::RefId::stringRefId(mBrushTexture)); const int index = landtexturesCollection.searchId(mBrushTexture);
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == nullptr) 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(); CSMDoc::Document& document = getWorldspaceWidget().getDocument();
QUndoStack& undoStack = document.getUndoStack(); QUndoStack& undoStack = document.getUndoStack();
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures(); CSMWorld::IdCollection<ESM::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
const int index = landtexturesCollection.searchId(ESM::RefId::stringRefId(mBrushTexture)); const int index = landtexturesCollection.searchId(mBrushTexture);
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
{ {
@ -303,18 +301,7 @@ void CSVRender::TerrainTextureMode::handleDropEvent(QDropEvent* event)
for (const CSMWorld::UniversalId& uid : ids) for (const CSMWorld::UniversalId& uid : ids)
{ {
mBrushTexture = uid.getId(); mBrushTexture = ESM::RefId::stringRefId(uid.getId());
emit passBrushTexture(mBrushTexture);
}
}
if (mime->holdsType(CSMWorld::UniversalId::Type_Texture))
{
const std::vector<CSMWorld::UniversalId> ids = mime->getData();
for (const CSMWorld::UniversalId& uid : ids)
{
std::string textureFileName = uid.toString();
createTexture(textureFileName);
emit passBrushTexture(mBrushTexture); emit passBrushTexture(mBrushTexture);
} }
} }
@ -359,11 +346,8 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex); 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 // All indices are offset by +1
int brushInt = Misc::StringUtils::toNumeric<int>(mBrushTexture.substr(hashlocation + 1), 0) + 1; uint32_t brushInt = document.getData().getLandTextures().getRecord(mBrushTexture).get().mIndex + 1;
int r = static_cast<float>(mBrushSize) / 2; int r = static_cast<float>(mBrushSize) / 2;
@ -662,50 +646,6 @@ void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColu
undoStack.push(new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId)); 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<CSMWorld::IdTable&>(*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<uint16_t>::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) bool CSVRender::TerrainTextureMode::allowLandTextureEditing(const std::string& cellId)
{ {
CSMDoc::Document& document = getWorldspaceWidget().getDocument(); 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;
} }

View File

@ -117,14 +117,11 @@ namespace CSVRender
void pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, void pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
CSMWorld::IdTable& landTable, std::string cellId); 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 /// \brief Create new cell and land if needed
bool allowLandTextureEditing(const std::string& textureFileName); bool allowLandTextureEditing(const std::string& textureFileName);
std::string mCellId; std::string mCellId;
std::string mBrushTexture; ESM::RefId mBrushTexture;
int mBrushSize; int mBrushSize;
CSVWidget::BrushShape mBrushShape; CSVWidget::BrushShape mBrushShape;
std::unique_ptr<BrushDraw> mBrushDraw; std::unique_ptr<BrushDraw> mBrushDraw;
@ -139,13 +136,13 @@ namespace CSVRender
const int landTextureSize{ ESM::Land::LAND_TEXTURE_SIZE }; const int landTextureSize{ ESM::Land::LAND_TEXTURE_SIZE };
signals: signals:
void passBrushTexture(std::string brushTexture); void passBrushTexture(ESM::RefId brushTexture);
public slots: public slots:
void handleDropEvent(QDropEvent* event); void handleDropEvent(QDropEvent* event);
void setBrushSize(int brushSize); void setBrushSize(int brushSize);
void setBrushShape(CSVWidget::BrushShape brushShape); void setBrushShape(CSVWidget::BrushShape brushShape);
void setBrushTexture(std::string brushShape); void setBrushTexture(ESM::RefId brushShape);
}; };
} }

View File

@ -27,6 +27,7 @@
#include <apps/opencs/model/prefs/category.hpp> #include <apps/opencs/model/prefs/category.hpp>
#include <apps/opencs/model/prefs/setting.hpp> #include <apps/opencs/model/prefs/setting.hpp>
#include <apps/opencs/model/world/columns.hpp> #include <apps/opencs/model/world/columns.hpp>
#include <apps/opencs/model/world/commandmacro.hpp>
#include <apps/opencs/model/world/record.hpp> #include <apps/opencs/model/world/record.hpp>
#include <apps/opencs/view/widget/brushshapes.hpp> #include <apps/opencs/view/widget/brushshapes.hpp>
#include <apps/opencs/view/widget/pushbutton.hpp> #include <apps/opencs/view/widget/pushbutton.hpp>
@ -39,7 +40,6 @@
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/idcollection.hpp" #include "../../model/world/idcollection.hpp"
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/landtexture.hpp"
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
namespace CSVWidget namespace CSVWidget
@ -74,12 +74,12 @@ CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QW
: QFrame(parent, Qt::Popup) : QFrame(parent, Qt::Popup)
, mDocument(document) , mDocument(document)
{ {
mBrushTextureLabel = "Selected texture: " + mBrushTexture + " "; mBrushTextureLabel = "Selected texture: " + mBrushTexture.getRefIdString() + " ";
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures(); CSMWorld::IdCollection<ESM::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); 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()) if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
{ {
@ -154,68 +154,38 @@ void CSVWidget::TextureBrushWindow::configureButtonInitialSettings(QPushButton*
button->setCheckable(true); button->setCheckable(true);
} }
void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture) void CSVWidget::TextureBrushWindow::setBrushTexture(ESM::RefId brushTexture)
{ {
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&>( CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&>(
*mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); *mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures));
QUndoStack& undoStack = mDocument.getUndoStack(); QUndoStack& undoStack = mDocument.getUndoStack();
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures(); CSMWorld::IdCollection<ESM::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture);
int index = 0; int row = landtexturesCollection.getIndex(brushTexture);
int pluginInDragged = 0; const auto& record = landtexturesCollection.getRecord(row);
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 if (!record.isDeleted())
// 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)
{ {
if (rowInBase == -1) // Ensure the texture is defined by the current plugin
if (!record.isModified())
{ {
int counter = 0; CSMWorld::CommandMacro macro(undoStack);
bool freeIndexFound = false; macro.push(new CSMWorld::TouchCommand(ltexTable, brushTexture.getRefIdString()));
const int maxCounter = std::numeric_limits<uint16_t>::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);
} }
mBrushTextureLabel = "Selected texture: " + 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 + " ";
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel) mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel)
+ landtexturesCollection.getData(rowInNew, landTextureFilename).value<QString>()); + landtexturesCollection.getData(row, landTextureFilename).value<QString>());
} }
else else
{ {
newBrushTextureId.clear(); brushTexture = {};
mBrushTextureLabel = "No selected texture or invalid texture"; mBrushTextureLabel = "No selected texture or invalid texture";
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel)); mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel));
} }
mBrushTexture = std::move(newBrushTextureId); mBrushTexture = brushTexture;
emit passTextureId(mBrushTexture); emit passTextureId(mBrushTexture);
emit passBrushShape(mBrushShape); // updates the icon tooltip emit passBrushShape(mBrushShape); // updates the icon tooltip
@ -250,7 +220,6 @@ CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush(
, mTextureBrushWindow(new TextureBrushWindow(document, this)) , mTextureBrushWindow(new TextureBrushWindow(document, this))
{ {
mBrushHistory.resize(1); mBrushHistory.resize(1);
mBrushHistory[0] = "L0#0";
setAcceptDrops(true); setAcceptDrops(true);
connect(mTextureBrushWindow, &TextureBrushWindow::passBrushShape, this, &SceneToolTextureBrush::setButtonIcon); connect(mTextureBrushWindow, &TextureBrushWindow::passBrushShape, this, &SceneToolTextureBrush::setButtonIcon);
@ -309,14 +278,15 @@ void CSVWidget::SceneToolTextureBrush::setButtonIcon(CSVWidget::BrushShape brush
tooltip += "<p>(right click to access of previously used brush settings)"; tooltip += "<p>(right click to access of previously used brush settings)";
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures(); CSMWorld::IdCollection<ESM::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); 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()) if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
{ {
tooltip += "<p>Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture) + " "; tooltip += "<p>Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture.getRefIdString())
+ " ";
tooltip += landtexturesCollection.getData(index, landTextureFilename).value<QString>(); tooltip += landtexturesCollection.getData(index, landTextureFilename).value<QString>();
} }
@ -342,25 +312,25 @@ void CSVWidget::SceneToolTextureBrush::updatePanel()
for (int i = mBrushHistory.size() - 1; i >= 0; --i) for (int i = mBrushHistory.size() - 1; i >= 0; --i)
{ {
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures(); CSMWorld::IdCollection<ESM::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture); 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()) if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
{ {
mTable->setItem(i, 1, mTable->setItem(i, 1,
new QTableWidgetItem(landtexturesCollection.getData(index, landTextureFilename).value<QString>())); new QTableWidgetItem(landtexturesCollection.getData(index, landTextureFilename).value<QString>()));
mTable->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(mBrushHistory[i]))); mTable->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(mBrushHistory[i].getRefIdString())));
} }
else else
{ {
mTable->setItem(i, 1, new QTableWidgetItem("Invalid/deleted texture")); 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); mBrushHistory.insert(mBrushHistory.begin(), brushTexture);
if (mBrushHistory.size() > 5) if (mBrushHistory.size() > 5)
@ -371,7 +341,7 @@ void CSVWidget::SceneToolTextureBrush::clicked(const QModelIndex& index)
{ {
if (index.column() == 0 || index.column() == 1) 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]); std::swap(mBrushHistory[index.row()], mBrushHistory[0]);
mTextureBrushWindow->setBrushTexture(brushTexture); mTextureBrushWindow->setBrushTexture(brushTexture);
emit passTextureId(brushTexture); emit passTextureId(brushTexture);

View File

@ -9,6 +9,8 @@
#include "scenetool.hpp" #include "scenetool.hpp"
#endif #endif
#include <components/esm/refid.hpp>
class QTableWidget; class QTableWidget;
class QDragEnterEvent; class QDragEnterEvent;
class QDropEvent; class QDropEvent;
@ -70,7 +72,7 @@ namespace CSVWidget
private: private:
CSVWidget::BrushShape mBrushShape = CSVWidget::BrushShape_Point; CSVWidget::BrushShape mBrushShape = CSVWidget::BrushShape_Point;
int mBrushSize = 1; int mBrushSize = 1;
std::string mBrushTexture = "L0#0"; ESM::RefId mBrushTexture;
CSMDoc::Document& mDocument; CSMDoc::Document& mDocument;
QLabel* mSelectedBrush; QLabel* mSelectedBrush;
QGroupBox* mHorizontalGroupBox; QGroupBox* mHorizontalGroupBox;
@ -85,14 +87,14 @@ namespace CSVWidget
friend class CSVRender::TerrainTextureMode; friend class CSVRender::TerrainTextureMode;
public slots: public slots:
void setBrushTexture(std::string brushTexture); void setBrushTexture(ESM::RefId brushTexture);
void setBrushShape(); void setBrushShape();
void setBrushSize(int brushSize); void setBrushSize(int brushSize);
signals: signals:
void passBrushSize(int brushSize); void passBrushSize(int brushSize);
void passBrushShape(CSVWidget::BrushShape brushShape); void passBrushShape(CSVWidget::BrushShape brushShape);
void passTextureId(std::string brushTexture); void passTextureId(ESM::RefId brushTexture);
}; };
class SceneToolTextureBrush : public SceneTool class SceneToolTextureBrush : public SceneTool
@ -103,7 +105,7 @@ namespace CSVWidget
CSMDoc::Document& mDocument; CSMDoc::Document& mDocument;
QFrame* mPanel; QFrame* mPanel;
QTableWidget* mTable; QTableWidget* mTable;
std::vector<std::string> mBrushHistory; std::vector<ESM::RefId> mBrushHistory;
TextureBrushWindow* mTextureBrushWindow; TextureBrushWindow* mTextureBrushWindow;
private: private:
@ -122,14 +124,14 @@ namespace CSVWidget
public slots: public slots:
void setButtonIcon(CSVWidget::BrushShape brushShape); void setButtonIcon(CSVWidget::BrushShape brushShape);
void updateBrushHistory(const std::string& mBrushTexture); void updateBrushHistory(ESM::RefId mBrushTexture);
void clicked(const QModelIndex& index); void clicked(const QModelIndex& index);
void activate() override; void activate() override;
signals: signals:
void passEvent(QDropEvent* event); void passEvent(QDropEvent* event);
void passEvent(QDragEnterEvent* event); void passEvent(QDragEnterEvent* event);
void passTextureId(std::string brushTexture); void passTextureId(ESM::RefId brushTexture);
}; };
} }

View File

@ -1,107 +0,0 @@
#include "landtexturecreator.hpp"
#include <cstdint>
#include <limits>
#include <stddef.h>
#include <QLabel>
#include <QLineEdit>
#include <QSpinBox>
#include <apps/opencs/model/world/columns.hpp>
#include <apps/opencs/model/world/data.hpp>
#include <apps/opencs/model/world/idcollection.hpp>
#include <apps/opencs/view/world/genericcreator.hpp>
#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<uint16_t>::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<int>(&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<CSMWorld::IdTable&>(*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<CSMWorld::IdTable&>(*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();
}
}

View File

@ -1,54 +0,0 @@
#ifndef CSV_WORLD_LANDTEXTURECREATOR_H
#define CSV_WORLD_LANDTEXTURECREATOR_H
#include <string>
#include "genericcreator.hpp"
#include <apps/opencs/model/world/universalid.hpp>
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

View File

@ -10,7 +10,6 @@
#include "globalcreator.hpp" #include "globalcreator.hpp"
#include "infocreator.hpp" #include "infocreator.hpp"
#include "landcreator.hpp" #include "landcreator.hpp"
#include "landtexturecreator.hpp"
#include "pathgridcreator.hpp" #include "pathgridcreator.hpp"
#include "previewsubview.hpp" #include "previewsubview.hpp"
#include "referenceablecreator.hpp" #include "referenceablecreator.hpp"
@ -92,7 +91,7 @@ void CSVWorld::addSubViewFactories(CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<LandCreator>>); new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<LandCreator>>);
manager.add(CSMWorld::UniversalId::Type_LandTextures, manager.add(CSMWorld::UniversalId::Type_LandTextures,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<LandTextureCreator>>); new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GenericCreator>>);
manager.add(CSMWorld::UniversalId::Type_Globals, manager.add(CSMWorld::UniversalId::Type_Globals,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GlobalCreator>>); new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GlobalCreator>>);
@ -195,7 +194,7 @@ void CSVWorld::addSubViewFactories(CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<LandCreator>>(false)); new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<LandCreator>>(false));
manager.add(CSMWorld::UniversalId::Type_LandTexture, manager.add(CSMWorld::UniversalId::Type_LandTexture,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<LandTextureCreator>>(false)); new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator>>(false));
manager.add(CSMWorld::UniversalId::Type_DebugProfile, manager.add(CSMWorld::UniversalId::Type_DebugProfile,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, new CSVDoc::SubViewFactoryWithCreator<DialogueSubView,