mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-03 13:19:40 +00:00
Merge branch 'mergetool'
Conflicts: apps/opencs/CMakeLists.txt apps/opencs/model/tools/tools.cpp
This commit is contained in:
commit
a445683312
49 changed files with 1207 additions and 150 deletions
|
@ -841,19 +841,13 @@ void Record<ESM::Land>::print()
|
||||||
std::cout << " Flags: " << landFlags(mData.mFlags) << std::endl;
|
std::cout << " Flags: " << landFlags(mData.mFlags) << std::endl;
|
||||||
std::cout << " DataTypes: " << mData.mDataTypes << std::endl;
|
std::cout << " DataTypes: " << mData.mDataTypes << std::endl;
|
||||||
|
|
||||||
// Seems like this should done with reference counting in the
|
if (const ESM::Land::LandData *data = mData.getLandData (mData.mDataTypes))
|
||||||
// loader to me. But I'm not really knowledgable about this
|
|
||||||
// record type yet. --Cory
|
|
||||||
bool wasLoaded = (mData.mDataLoaded != 0);
|
|
||||||
if (mData.mDataTypes) mData.loadData(mData.mDataTypes);
|
|
||||||
if (mData.mDataLoaded)
|
|
||||||
{
|
{
|
||||||
std::cout << " Height Offset: " << mData.mLandData->mHeightOffset << std::endl;
|
std::cout << " Height Offset: " << data->mHeightOffset << std::endl;
|
||||||
// Lots of missing members.
|
// Lots of missing members.
|
||||||
std::cout << " Unknown1: " << mData.mLandData->mUnk1 << std::endl;
|
std::cout << " Unknown1: " << data->mUnk1 << std::endl;
|
||||||
std::cout << " Unknown2: " << mData.mLandData->mUnk2 << std::endl;
|
std::cout << " Unknown2: " << data->mUnk2 << std::endl;
|
||||||
}
|
}
|
||||||
if (!wasLoaded) mData.unloadData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
@ -35,13 +35,18 @@ opencs_hdrs_noqt (model/world
|
||||||
|
|
||||||
|
|
||||||
opencs_units (model/tools
|
opencs_units (model/tools
|
||||||
tools reportmodel
|
tools reportmodel mergeoperation
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (model/tools
|
opencs_units_noqt (model/tools
|
||||||
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
|
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
|
||||||
birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck
|
birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck
|
||||||
startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck
|
startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck
|
||||||
|
mergestages
|
||||||
|
)
|
||||||
|
|
||||||
|
opencs_hdrs_noqt (model/tools
|
||||||
|
mergestate
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,7 +99,7 @@ opencs_hdrs_noqt (view/render
|
||||||
|
|
||||||
|
|
||||||
opencs_units (view/tools
|
opencs_units (view/tools
|
||||||
reportsubview reporttable searchsubview searchbox
|
reportsubview reporttable searchsubview searchbox merge
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/tools
|
opencs_units_noqt (view/tools
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
CS::Editor::Editor ()
|
CS::Editor::Editor ()
|
||||||
: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr),
|
: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr),
|
||||||
mViewManager (mDocumentManager), mPid(""),
|
mViewManager (mDocumentManager), mPid(""),
|
||||||
mLock(), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
|
mLock(), mMerge (mDocumentManager),
|
||||||
|
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
|
||||||
{
|
{
|
||||||
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
||||||
|
|
||||||
|
@ -39,9 +40,12 @@ CS::Editor::Editor ()
|
||||||
|
|
||||||
mNewGame.setLocalData (mLocal);
|
mNewGame.setLocalData (mLocal);
|
||||||
mFileDialog.setLocalData (mLocal);
|
mFileDialog.setLocalData (mLocal);
|
||||||
|
mMerge.setLocalData (mLocal);
|
||||||
|
|
||||||
connect (&mDocumentManager, SIGNAL (documentAdded (CSMDoc::Document *)),
|
connect (&mDocumentManager, SIGNAL (documentAdded (CSMDoc::Document *)),
|
||||||
this, SLOT (documentAdded (CSMDoc::Document *)));
|
this, SLOT (documentAdded (CSMDoc::Document *)));
|
||||||
|
connect (&mDocumentManager, SIGNAL (documentAboutToBeRemoved (CSMDoc::Document *)),
|
||||||
|
this, SLOT (documentAboutToBeRemoved (CSMDoc::Document *)));
|
||||||
connect (&mDocumentManager, SIGNAL (lastDocumentDeleted()),
|
connect (&mDocumentManager, SIGNAL (lastDocumentDeleted()),
|
||||||
this, SLOT (lastDocumentDeleted()));
|
this, SLOT (lastDocumentDeleted()));
|
||||||
|
|
||||||
|
@ -49,6 +53,7 @@ CS::Editor::Editor ()
|
||||||
connect (&mViewManager, SIGNAL (newAddonRequest ()), this, SLOT (createAddon ()));
|
connect (&mViewManager, SIGNAL (newAddonRequest ()), this, SLOT (createAddon ()));
|
||||||
connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ()));
|
connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ()));
|
||||||
connect (&mViewManager, SIGNAL (editSettingsRequest()), this, SLOT (showSettings ()));
|
connect (&mViewManager, SIGNAL (editSettingsRequest()), this, SLOT (showSettings ()));
|
||||||
|
connect (&mViewManager, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SLOT (mergeDocument (CSMDoc::Document *)));
|
||||||
|
|
||||||
connect (&mStartup, SIGNAL (createGame()), this, SLOT (createGame ()));
|
connect (&mStartup, SIGNAL (createGame()), this, SLOT (createGame ()));
|
||||||
connect (&mStartup, SIGNAL (createAddon()), this, SLOT (createAddon ()));
|
connect (&mStartup, SIGNAL (createAddon()), this, SLOT (createAddon ()));
|
||||||
|
@ -359,7 +364,21 @@ void CS::Editor::documentAdded (CSMDoc::Document *document)
|
||||||
mViewManager.addView (document);
|
mViewManager.addView (document);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CS::Editor::documentAboutToBeRemoved (CSMDoc::Document *document)
|
||||||
|
{
|
||||||
|
if (mMerge.getDocument()==document)
|
||||||
|
mMerge.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
void CS::Editor::lastDocumentDeleted()
|
void CS::Editor::lastDocumentDeleted()
|
||||||
{
|
{
|
||||||
QApplication::quit();
|
QApplication::quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CS::Editor::mergeDocument (CSMDoc::Document *document)
|
||||||
|
{
|
||||||
|
mMerge.configure (document);
|
||||||
|
mMerge.show();
|
||||||
|
mMerge.raise();
|
||||||
|
mMerge.activateWindow();
|
||||||
|
}
|
||||||
|
|
|
@ -27,11 +27,18 @@
|
||||||
|
|
||||||
#include "view/settings/dialog.hpp"
|
#include "view/settings/dialog.hpp"
|
||||||
|
|
||||||
|
#include "view/tools/merge.hpp"
|
||||||
|
|
||||||
namespace VFS
|
namespace VFS
|
||||||
{
|
{
|
||||||
class Manager;
|
class Manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace CSMDoc
|
||||||
|
{
|
||||||
|
class Document;
|
||||||
|
}
|
||||||
|
|
||||||
namespace CS
|
namespace CS
|
||||||
{
|
{
|
||||||
class Editor : public QObject
|
class Editor : public QObject
|
||||||
|
@ -55,6 +62,7 @@ namespace CS
|
||||||
boost::interprocess::file_lock mLock;
|
boost::interprocess::file_lock mLock;
|
||||||
boost::filesystem::ofstream mPidFile;
|
boost::filesystem::ofstream mPidFile;
|
||||||
bool mFsStrict;
|
bool mFsStrict;
|
||||||
|
CSVTools::Merge mMerge;
|
||||||
|
|
||||||
void setupDataFiles (const Files::PathContainer& dataDirs);
|
void setupDataFiles (const Files::PathContainer& dataDirs);
|
||||||
|
|
||||||
|
@ -94,8 +102,12 @@ namespace CS
|
||||||
|
|
||||||
void documentAdded (CSMDoc::Document *document);
|
void documentAdded (CSMDoc::Document *document);
|
||||||
|
|
||||||
|
void documentAboutToBeRemoved (CSMDoc::Document *document);
|
||||||
|
|
||||||
void lastDocumentDeleted();
|
void lastDocumentDeleted();
|
||||||
|
|
||||||
|
void mergeDocument (CSMDoc::Document *document);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QString mIpcServerName;
|
QString mIpcServerName;
|
||||||
|
|
|
@ -2250,13 +2250,13 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM
|
||||||
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
|
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
|
||||||
const std::vector<std::string>& blacklistedScripts)
|
const std::vector<std::string>& blacklistedScripts)
|
||||||
: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager),
|
: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager),
|
||||||
mTools (*this),
|
mTools (*this, encoding),
|
||||||
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
||||||
(savePath.filename().string() + ".project")),
|
(savePath.filename().string() + ".project")),
|
||||||
mSavingOperation (*this, mProjectPath, encoding),
|
mSavingOperation (*this, mProjectPath, encoding),
|
||||||
mSaving (&mSavingOperation),
|
mSaving (&mSavingOperation),
|
||||||
mResDir(resDir),
|
mResDir(resDir),
|
||||||
mRunner (mProjectPath), mIdCompletionManager(mData)
|
mRunner (mProjectPath), mDirty (false), mIdCompletionManager(mData)
|
||||||
{
|
{
|
||||||
if (mContentFiles.empty())
|
if (mContentFiles.empty())
|
||||||
throw std::runtime_error ("Empty content file sequence");
|
throw std::runtime_error ("Empty content file sequence");
|
||||||
|
@ -2294,6 +2294,8 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM
|
||||||
|
|
||||||
connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
|
connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
|
||||||
connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
|
connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
|
||||||
|
connect (&mTools, SIGNAL (mergeDone (CSMDoc::Document*)),
|
||||||
|
this, SIGNAL (mergeDone (CSMDoc::Document*)));
|
||||||
|
|
||||||
connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
|
connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
|
||||||
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
|
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
|
||||||
|
@ -2323,7 +2325,7 @@ int CSMDoc::Document::getState() const
|
||||||
{
|
{
|
||||||
int state = 0;
|
int state = 0;
|
||||||
|
|
||||||
if (!mUndoStack.isClean())
|
if (!mUndoStack.isClean() || mDirty)
|
||||||
state |= State_Modified;
|
state |= State_Modified;
|
||||||
|
|
||||||
if (mSaving.isRunning())
|
if (mSaving.isRunning())
|
||||||
|
@ -2388,6 +2390,12 @@ void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const C
|
||||||
emit stateChanged (getState(), this);
|
emit stateChanged (getState(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMDoc::Document::runMerge (std::auto_ptr<CSMDoc::Document> target)
|
||||||
|
{
|
||||||
|
mTools.runMerge (target);
|
||||||
|
emit stateChanged (getState(), this);
|
||||||
|
}
|
||||||
|
|
||||||
void CSMDoc::Document::abortOperation (int type)
|
void CSMDoc::Document::abortOperation (int type)
|
||||||
{
|
{
|
||||||
if (type==State_Saving)
|
if (type==State_Saving)
|
||||||
|
@ -2409,6 +2417,9 @@ void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
|
||||||
|
|
||||||
void CSMDoc::Document::operationDone (int type, bool failed)
|
void CSMDoc::Document::operationDone (int type, bool failed)
|
||||||
{
|
{
|
||||||
|
if (type==CSMDoc::State_Saving && !failed)
|
||||||
|
mDirty = false;
|
||||||
|
|
||||||
emit stateChanged (getState(), this);
|
emit stateChanged (getState(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2485,3 +2496,8 @@ CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager()
|
||||||
{
|
{
|
||||||
return mIdCompletionManager;
|
return mIdCompletionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMDoc::Document::flagAsDirty()
|
||||||
|
{
|
||||||
|
mDirty = true;
|
||||||
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ namespace CSMDoc
|
||||||
boost::filesystem::path mResDir;
|
boost::filesystem::path mResDir;
|
||||||
Blacklist mBlacklist;
|
Blacklist mBlacklist;
|
||||||
Runner mRunner;
|
Runner mRunner;
|
||||||
|
bool mDirty;
|
||||||
|
|
||||||
CSMWorld::IdCompletionManager mIdCompletionManager;
|
CSMWorld::IdCompletionManager mIdCompletionManager;
|
||||||
|
|
||||||
|
@ -129,7 +130,9 @@ namespace CSMDoc
|
||||||
CSMWorld::UniversalId newSearch();
|
CSMWorld::UniversalId newSearch();
|
||||||
|
|
||||||
void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search);
|
void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search);
|
||||||
|
|
||||||
|
void runMerge (std::auto_ptr<CSMDoc::Document> target);
|
||||||
|
|
||||||
void abortOperation (int type);
|
void abortOperation (int type);
|
||||||
|
|
||||||
const CSMWorld::Data& getData() const;
|
const CSMWorld::Data& getData() const;
|
||||||
|
@ -150,12 +153,18 @@ namespace CSMDoc
|
||||||
|
|
||||||
CSMWorld::IdCompletionManager &getIdCompletionManager();
|
CSMWorld::IdCompletionManager &getIdCompletionManager();
|
||||||
|
|
||||||
|
void flagAsDirty();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void stateChanged (int state, CSMDoc::Document *document);
|
void stateChanged (int state, CSMDoc::Document *document);
|
||||||
|
|
||||||
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
|
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
|
||||||
|
|
||||||
|
/// \attention When this signal is emitted, *this hands over the ownership of the
|
||||||
|
/// document. This signal must be handled to avoid a leak.
|
||||||
|
void mergeDone (CSMDoc::Document *document);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void modificationStateChanged (bool clean);
|
void modificationStateChanged (bool clean);
|
||||||
|
@ -173,4 +182,3 @@ namespace CSMDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -56,10 +56,24 @@ bool CSMDoc::DocumentManager::isEmpty()
|
||||||
void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
|
void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
|
||||||
bool new_)
|
bool new_)
|
||||||
{
|
{
|
||||||
Document *document = new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts);
|
Document *document = makeDocument (files, savePath, new_);
|
||||||
|
insertDocument (document);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMDoc::Document *CSMDoc::DocumentManager::makeDocument (
|
||||||
|
const std::vector< boost::filesystem::path >& files,
|
||||||
|
const boost::filesystem::path& savePath, bool new_)
|
||||||
|
{
|
||||||
|
return new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMDoc::DocumentManager::insertDocument (CSMDoc::Document *document)
|
||||||
|
{
|
||||||
mDocuments.push_back (document);
|
mDocuments.push_back (document);
|
||||||
|
|
||||||
|
connect (document, SIGNAL (mergeDone (CSMDoc::Document*)),
|
||||||
|
this, SLOT (insertDocument (CSMDoc::Document*)));
|
||||||
|
|
||||||
emit loadRequest (document);
|
emit loadRequest (document);
|
||||||
|
|
||||||
mLoader.hasThingsToDo().wakeAll();
|
mLoader.hasThingsToDo().wakeAll();
|
||||||
|
@ -72,6 +86,8 @@ void CSMDoc::DocumentManager::removeDocument (CSMDoc::Document *document)
|
||||||
if (iter==mDocuments.end())
|
if (iter==mDocuments.end())
|
||||||
throw std::runtime_error ("removing invalid document");
|
throw std::runtime_error ("removing invalid document");
|
||||||
|
|
||||||
|
emit documentAboutToBeRemoved (document);
|
||||||
|
|
||||||
mDocuments.erase (iter);
|
mDocuments.erase (iter);
|
||||||
document->deleteLater();
|
document->deleteLater();
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,15 @@ namespace CSMDoc
|
||||||
///< \param new_ Do not load the last content file in \a files and instead create in an
|
///< \param new_ Do not load the last content file in \a files and instead create in an
|
||||||
/// appropriate way.
|
/// appropriate way.
|
||||||
|
|
||||||
|
/// Create a new document. The ownership of the created document is transferred to
|
||||||
|
/// the calling function. The DocumentManager does not manage it. Loading has not
|
||||||
|
/// taken place at the point when the document is returned.
|
||||||
|
///
|
||||||
|
/// \param new_ Do not load the last content file in \a files and instead create in an
|
||||||
|
/// appropriate way.
|
||||||
|
Document *makeDocument (const std::vector< boost::filesystem::path >& files,
|
||||||
|
const boost::filesystem::path& savePath, bool new_);
|
||||||
|
|
||||||
void setResourceDir (const boost::filesystem::path& parResDir);
|
void setResourceDir (const boost::filesystem::path& parResDir);
|
||||||
|
|
||||||
void setEncoding (ToUTF8::FromType encoding);
|
void setEncoding (ToUTF8::FromType encoding);
|
||||||
|
@ -84,10 +93,16 @@ namespace CSMDoc
|
||||||
void removeDocument (CSMDoc::Document *document);
|
void removeDocument (CSMDoc::Document *document);
|
||||||
///< Emits the lastDocumentDeleted signal, if applicable.
|
///< Emits the lastDocumentDeleted signal, if applicable.
|
||||||
|
|
||||||
|
/// Hand over document to *this. The ownership is transferred. The DocumentManager
|
||||||
|
/// will initiate the load procedure, if necessary
|
||||||
|
void insertDocument (CSMDoc::Document *document);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void documentAdded (CSMDoc::Document *document);
|
void documentAdded (CSMDoc::Document *document);
|
||||||
|
|
||||||
|
void documentAboutToBeRemoved (CSMDoc::Document *document);
|
||||||
|
|
||||||
void loadRequest (CSMDoc::Document *document);
|
void loadRequest (CSMDoc::Document *document);
|
||||||
|
|
||||||
void lastDocumentDeleted();
|
void lastDocumentDeleted();
|
||||||
|
|
|
@ -83,7 +83,9 @@ namespace CSMDoc
|
||||||
|
|
||||||
void executeStage();
|
void executeStage();
|
||||||
|
|
||||||
void operationDone();
|
protected slots:
|
||||||
|
|
||||||
|
virtual void operationDone();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -415,15 +415,16 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages)
|
||||||
if (land.mState==CSMWorld::RecordBase::State_Modified ||
|
if (land.mState==CSMWorld::RecordBase::State_Modified ||
|
||||||
land.mState==CSMWorld::RecordBase::State_ModifiedOnly)
|
land.mState==CSMWorld::RecordBase::State_ModifiedOnly)
|
||||||
{
|
{
|
||||||
CSMWorld::Land record = land.get();
|
const CSMWorld::Land& record = land.get();
|
||||||
|
|
||||||
mState.getWriter().startRecord (record.mLand->sRecordId);
|
mState.getWriter().startRecord (record.sRecordId);
|
||||||
|
|
||||||
record.mLand->save (mState.getWriter());
|
record.save (mState.getWriter());
|
||||||
if(record.mLand->mLandData)
|
|
||||||
record.mLand->mLandData->save (mState.getWriter());
|
|
||||||
|
|
||||||
mState.getWriter().endRecord (record.mLand->sRecordId);
|
if (const ESM::Land::LandData *data = record.getLandData (record.mDataTypes))
|
||||||
|
data->save (mState.getWriter());
|
||||||
|
|
||||||
|
mState.getWriter().endRecord (record.sRecordId);
|
||||||
}
|
}
|
||||||
else if (land.mState==CSMWorld::RecordBase::State_Deleted)
|
else if (land.mState==CSMWorld::RecordBase::State_Deleted)
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace CSMDoc
|
||||||
|
|
||||||
State_Saving = 16,
|
State_Saving = 16,
|
||||||
State_Verifying = 32,
|
State_Verifying = 32,
|
||||||
State_Compiling = 64, // not implemented yet
|
State_Merging = 64,
|
||||||
State_Searching = 128,
|
State_Searching = 128,
|
||||||
State_Loading = 256 // pseudo-state; can not be encountered in a loaded document
|
State_Loading = 256 // pseudo-state; can not be encountered in a loaded document
|
||||||
};
|
};
|
||||||
|
|
59
apps/opencs/model/tools/mergeoperation.cpp
Normal file
59
apps/opencs/model/tools/mergeoperation.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
|
||||||
|
#include "mergeoperation.hpp"
|
||||||
|
|
||||||
|
#include "../doc/state.hpp"
|
||||||
|
#include "../doc/document.hpp"
|
||||||
|
|
||||||
|
#include "mergestages.hpp"
|
||||||
|
|
||||||
|
CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding)
|
||||||
|
: CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document)
|
||||||
|
{
|
||||||
|
appendStage (new StartMergeStage (mState));
|
||||||
|
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Global> (mState, &CSMWorld::Data::getGlobals));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::GameSetting> (mState, &CSMWorld::Data::getGmsts));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Skill> (mState, &CSMWorld::Data::getSkills));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Class> (mState, &CSMWorld::Data::getClasses));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Faction> (mState, &CSMWorld::Data::getFactions));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Race> (mState, &CSMWorld::Data::getRaces));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Sound> (mState, &CSMWorld::Data::getSounds));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Script> (mState, &CSMWorld::Data::getScripts));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Region> (mState, &CSMWorld::Data::getRegions));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::BirthSign> (mState, &CSMWorld::Data::getBirthsigns));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Spell> (mState, &CSMWorld::Data::getSpells));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Dialogue> (mState, &CSMWorld::Data::getTopics));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Dialogue> (mState, &CSMWorld::Data::getJournals));
|
||||||
|
appendStage (new MergeIdCollectionStage<CSMWorld::Cell> (mState, &CSMWorld::Data::getCells));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Filter> (mState, &CSMWorld::Data::getFilters));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::Enchantment> (mState, &CSMWorld::Data::getEnchantments));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::BodyPart> (mState, &CSMWorld::Data::getBodyParts));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::DebugProfile> (mState, &CSMWorld::Data::getDebugProfiles));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::SoundGenerator> (mState, &CSMWorld::Data::getSoundGens));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::MagicEffect> (mState, &CSMWorld::Data::getMagicEffects));
|
||||||
|
appendStage (new MergeIdCollectionStage<ESM::StartScript> (mState, &CSMWorld::Data::getStartScripts));
|
||||||
|
appendStage (new MergeIdCollectionStage<CSMWorld::Pathgrid, CSMWorld::SubCellCollection<CSMWorld::Pathgrid> > (mState, &CSMWorld::Data::getPathgrids));
|
||||||
|
appendStage (new MergeIdCollectionStage<CSMWorld::Info, CSMWorld::InfoCollection> (mState, &CSMWorld::Data::getTopicInfos));
|
||||||
|
appendStage (new MergeIdCollectionStage<CSMWorld::Info, CSMWorld::InfoCollection> (mState, &CSMWorld::Data::getJournalInfos));
|
||||||
|
appendStage (new MergeRefIdsStage (mState));
|
||||||
|
appendStage (new MergeReferencesStage (mState));
|
||||||
|
appendStage (new MergeReferencesStage (mState));
|
||||||
|
appendStage (new ListLandTexturesMergeStage (mState));
|
||||||
|
appendStage (new MergeLandTexturesStage (mState));
|
||||||
|
appendStage (new MergeLandStage (mState));
|
||||||
|
|
||||||
|
appendStage (new FinishMergedDocumentStage (mState, encoding));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMTools::MergeOperation::setTarget (std::auto_ptr<CSMDoc::Document> document)
|
||||||
|
{
|
||||||
|
mState.mTarget = document;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMTools::MergeOperation::operationDone()
|
||||||
|
{
|
||||||
|
CSMDoc::Operation::operationDone();
|
||||||
|
|
||||||
|
if (mState.mCompleted)
|
||||||
|
emit mergeDone (mState.mTarget.release());
|
||||||
|
}
|
45
apps/opencs/model/tools/mergeoperation.hpp
Normal file
45
apps/opencs/model/tools/mergeoperation.hpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef CSM_TOOLS_MERGEOPERATION_H
|
||||||
|
#define CSM_TOOLS_MERGEOPERATION_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
|
#include "../doc/operation.hpp"
|
||||||
|
|
||||||
|
#include "mergestate.hpp"
|
||||||
|
|
||||||
|
namespace CSMDoc
|
||||||
|
{
|
||||||
|
class Document;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSMTools
|
||||||
|
{
|
||||||
|
class MergeOperation : public CSMDoc::Operation
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
MergeState mState;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding);
|
||||||
|
|
||||||
|
/// \attention Do not call this function while a merge is running.
|
||||||
|
void setTarget (std::auto_ptr<CSMDoc::Document> document);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
|
||||||
|
virtual void operationDone();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
/// \attention When this signal is emitted, *this hands over the ownership of the
|
||||||
|
/// document. This signal must be handled to avoid a leak.
|
||||||
|
void mergeDone (CSMDoc::Document *document);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
258
apps/opencs/model/tools/mergestages.cpp
Normal file
258
apps/opencs/model/tools/mergestages.cpp
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
|
||||||
|
#include "mergestages.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
#include "mergestate.hpp"
|
||||||
|
|
||||||
|
#include "../doc/document.hpp"
|
||||||
|
#include "../world/data.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
CSMTools::StartMergeStage::StartMergeStage (MergeState& state)
|
||||||
|
: mState (state)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int CSMTools::StartMergeStage::setup()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMTools::StartMergeStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
|
{
|
||||||
|
mState.mCompleted = false;
|
||||||
|
mState.mTextureIndices.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding)
|
||||||
|
: mState (state), mEncoder (encoding)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int CSMTools::FinishMergedDocumentStage::setup()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
|
{
|
||||||
|
// We know that the content file list contains at least two entries and that the first one
|
||||||
|
// does exist on disc (otherwise it would have been impossible to initiate a merge on that
|
||||||
|
// document).
|
||||||
|
boost::filesystem::path path = mState.mSource.getContentFiles()[0];
|
||||||
|
|
||||||
|
ESM::ESMReader reader;
|
||||||
|
reader.setEncoder (&mEncoder);
|
||||||
|
reader.open (path.string());
|
||||||
|
|
||||||
|
CSMWorld::MetaData source;
|
||||||
|
source.mId = "sys::meta";
|
||||||
|
source.load (reader);
|
||||||
|
|
||||||
|
CSMWorld::MetaData target = mState.mTarget->getData().getMetaData();
|
||||||
|
|
||||||
|
target.mAuthor = source.mAuthor;
|
||||||
|
target.mDescription = source.mDescription;
|
||||||
|
|
||||||
|
mState.mTarget->getData().setMetaData (target);
|
||||||
|
|
||||||
|
mState.mCompleted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CSMTools::MergeRefIdsStage::MergeRefIdsStage (MergeState& state) : mState (state) {}
|
||||||
|
|
||||||
|
int CSMTools::MergeRefIdsStage::setup()
|
||||||
|
{
|
||||||
|
return mState.mSource.getData().getReferenceables().getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMTools::MergeRefIdsStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
|
{
|
||||||
|
mState.mSource.getData().getReferenceables().copyTo (
|
||||||
|
stage, mState.mTarget->getData().getReferenceables());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CSMTools::MergeReferencesStage::MergeReferencesStage (MergeState& state)
|
||||||
|
: mState (state)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int CSMTools::MergeReferencesStage::setup()
|
||||||
|
{
|
||||||
|
mIndex.clear();
|
||||||
|
return mState.mSource.getData().getReferences().getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
|
{
|
||||||
|
const CSMWorld::Record<CSMWorld::CellRef>& record =
|
||||||
|
mState.mSource.getData().getReferences().getRecord (stage);
|
||||||
|
|
||||||
|
if (!record.isDeleted())
|
||||||
|
{
|
||||||
|
CSMWorld::CellRef ref = record.get();
|
||||||
|
|
||||||
|
ref.mOriginalCell = ref.mCell;
|
||||||
|
|
||||||
|
ref.mRefNum.mIndex = mIndex[Misc::StringUtils::lowerCase (ref.mCell)]++;
|
||||||
|
ref.mRefNum.mContentFile = 0;
|
||||||
|
|
||||||
|
CSMWorld::Record<CSMWorld::CellRef> newRecord (
|
||||||
|
CSMWorld::RecordBase::State_ModifiedOnly, 0, &ref);
|
||||||
|
|
||||||
|
mState.mTarget->getData().getReferences().appendRecord (newRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state)
|
||||||
|
: mState (state)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int CSMTools::ListLandTexturesMergeStage::setup()
|
||||||
|
{
|
||||||
|
return mState.mSource.getData().getLand().getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
|
{
|
||||||
|
const CSMWorld::Record<CSMWorld::Land>& 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 | ESM::Land::DATA_WNAM);
|
||||||
|
|
||||||
|
if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX))
|
||||||
|
{
|
||||||
|
// list texture indices
|
||||||
|
std::pair<uint16_t, int> key;
|
||||||
|
key.second = land.mPlugin;
|
||||||
|
|
||||||
|
for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i)
|
||||||
|
{
|
||||||
|
key.first = data->mTextures[i];
|
||||||
|
|
||||||
|
mState.mTextureIndices[key] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state)
|
||||||
|
: mState (state), mNext (mState.mTextureIndices.end())
|
||||||
|
{}
|
||||||
|
|
||||||
|
int CSMTools::MergeLandTexturesStage::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)
|
||||||
|
{
|
||||||
|
if (stage==0)
|
||||||
|
mNext = mState.mTextureIndices.begin();
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
|
||||||
|
std::ostringstream stream;
|
||||||
|
stream << mNext->second-1 << "_0";
|
||||||
|
|
||||||
|
texture.mIndex = mNext->second-1;
|
||||||
|
texture.mId = stream.str();
|
||||||
|
|
||||||
|
CSMWorld::Record<CSMWorld::LandTexture> newRecord (
|
||||||
|
CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture);
|
||||||
|
|
||||||
|
mState.mTarget->getData().getLandTextures().appendRecord (newRecord);
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
++mNext;
|
||||||
|
}
|
||||||
|
while (!found);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CSMTools::MergeLandStage::MergeLandStage (MergeState& state) : mState (state) {}
|
||||||
|
|
||||||
|
int CSMTools::MergeLandStage::setup()
|
||||||
|
{
|
||||||
|
return mState.mSource.getData().getLand().getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
|
{
|
||||||
|
const CSMWorld::Record<CSMWorld::Land>& record =
|
||||||
|
mState.mSource.getData().getLand().getRecord (stage);
|
||||||
|
|
||||||
|
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 | ESM::Land::DATA_WNAM);
|
||||||
|
|
||||||
|
CSMWorld::Land newLand (land);
|
||||||
|
|
||||||
|
newLand.mEsm = 0; // avoid potential dangling pointer (ESMReader isn't needed anyway,
|
||||||
|
// because record is already fully loaded)
|
||||||
|
newLand.mPlugin = 0;
|
||||||
|
|
||||||
|
if (land.mDataTypes & ESM::Land::DATA_VTEX)
|
||||||
|
{
|
||||||
|
// adjust land texture references
|
||||||
|
if (ESM::Land::LandData *data = newLand.getLandData())
|
||||||
|
{
|
||||||
|
std::pair<uint16_t, int> key;
|
||||||
|
key.second = land.mPlugin;
|
||||||
|
|
||||||
|
for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i)
|
||||||
|
{
|
||||||
|
key.first = data->mTextures[i];
|
||||||
|
std::map<std::pair<uint16_t, int>, int>::const_iterator iter =
|
||||||
|
mState.mTextureIndices.find (key);
|
||||||
|
|
||||||
|
if (iter!=mState.mTextureIndices.end())
|
||||||
|
data->mTextures[i] = iter->second;
|
||||||
|
else
|
||||||
|
data->mTextures[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::Record<CSMWorld::Land> newRecord (
|
||||||
|
CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand);
|
||||||
|
|
||||||
|
mState.mTarget->getData().getLand().appendRecord (newRecord);
|
||||||
|
}
|
||||||
|
}
|
166
apps/opencs/model/tools/mergestages.hpp
Normal file
166
apps/opencs/model/tools/mergestages.hpp
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#ifndef CSM_TOOLS_MERGESTAGES_H
|
||||||
|
#define CSM_TOOLS_MERGESTAGES_H
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
|
#include "../doc/stage.hpp"
|
||||||
|
|
||||||
|
#include "../world/data.hpp"
|
||||||
|
|
||||||
|
#include "mergestate.hpp"
|
||||||
|
|
||||||
|
namespace CSMTools
|
||||||
|
{
|
||||||
|
class StartMergeStage : public CSMDoc::Stage
|
||||||
|
{
|
||||||
|
MergeState& mState;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
StartMergeStage (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.
|
||||||
|
};
|
||||||
|
|
||||||
|
class FinishMergedDocumentStage : public CSMDoc::Stage
|
||||||
|
{
|
||||||
|
MergeState& mState;
|
||||||
|
ToUTF8::Utf8Encoder mEncoder;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding);
|
||||||
|
|
||||||
|
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.
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename RecordType, typename Collection = CSMWorld::IdCollection<RecordType> >
|
||||||
|
class MergeIdCollectionStage : public CSMDoc::Stage
|
||||||
|
{
|
||||||
|
MergeState& mState;
|
||||||
|
Collection& (CSMWorld::Data::*mAccessor)();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)());
|
||||||
|
|
||||||
|
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.
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename RecordType, typename Collection>
|
||||||
|
MergeIdCollectionStage<RecordType, Collection>::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)())
|
||||||
|
: mState (state), mAccessor (accessor)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename RecordType, typename Collection>
|
||||||
|
int MergeIdCollectionStage<RecordType, Collection>::setup()
|
||||||
|
{
|
||||||
|
return (mState.mSource.getData().*mAccessor)().getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename RecordType, typename Collection>
|
||||||
|
void MergeIdCollectionStage<RecordType, Collection>::perform (int stage, CSMDoc::Messages& messages)
|
||||||
|
{
|
||||||
|
const Collection& source = (mState.mSource.getData().*mAccessor)();
|
||||||
|
Collection& target = (mState.mTarget->getData().*mAccessor)();
|
||||||
|
|
||||||
|
const CSMWorld::Record<RecordType>& record = source.getRecord (stage);
|
||||||
|
|
||||||
|
if (!record.isDeleted())
|
||||||
|
target.appendRecord (CSMWorld::Record<RecordType> (CSMWorld::RecordBase::State_ModifiedOnly, 0, &record.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
class MergeRefIdsStage : public CSMDoc::Stage
|
||||||
|
{
|
||||||
|
MergeState& mState;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MergeRefIdsStage (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.
|
||||||
|
};
|
||||||
|
|
||||||
|
class MergeReferencesStage : public CSMDoc::Stage
|
||||||
|
{
|
||||||
|
MergeState& mState;
|
||||||
|
std::map<std::string, int> mIndex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MergeReferencesStage (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.
|
||||||
|
};
|
||||||
|
|
||||||
|
class ListLandTexturesMergeStage : public CSMDoc::Stage
|
||||||
|
{
|
||||||
|
MergeState& mState;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ListLandTexturesMergeStage (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.
|
||||||
|
};
|
||||||
|
|
||||||
|
class MergeLandTexturesStage : public CSMDoc::Stage
|
||||||
|
{
|
||||||
|
MergeState& mState;
|
||||||
|
std::map<std::pair<uint16_t, int>, int>::iterator mNext;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MergeLandTexturesStage (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.
|
||||||
|
};
|
||||||
|
|
||||||
|
class MergeLandStage : public CSMDoc::Stage
|
||||||
|
{
|
||||||
|
MergeState& mState;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MergeLandStage (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
|
24
apps/opencs/model/tools/mergestate.hpp
Normal file
24
apps/opencs/model/tools/mergestate.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef CSM_TOOLS_MERGESTATE_H
|
||||||
|
#define CSM_TOOLS_MERGESTATE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "../doc/document.hpp"
|
||||||
|
|
||||||
|
namespace CSMTools
|
||||||
|
{
|
||||||
|
struct MergeState
|
||||||
|
{
|
||||||
|
std::auto_ptr<CSMDoc::Document> mTarget;
|
||||||
|
CSMDoc::Document& mSource;
|
||||||
|
bool mCompleted;
|
||||||
|
std::map<std::pair<uint16_t, int>, int> mTextureIndices; // (texture, content file) -> new texture
|
||||||
|
|
||||||
|
MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -28,6 +28,7 @@
|
||||||
#include "pathgridcheck.hpp"
|
#include "pathgridcheck.hpp"
|
||||||
#include "soundgencheck.hpp"
|
#include "soundgencheck.hpp"
|
||||||
#include "magiceffectcheck.hpp"
|
#include "magiceffectcheck.hpp"
|
||||||
|
#include "mergeoperation.hpp"
|
||||||
|
|
||||||
CSMDoc::OperationHolder *CSMTools::Tools::get (int type)
|
CSMDoc::OperationHolder *CSMTools::Tools::get (int type)
|
||||||
{
|
{
|
||||||
|
@ -35,6 +36,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::get (int type)
|
||||||
{
|
{
|
||||||
case CSMDoc::State_Verifying: return &mVerifier;
|
case CSMDoc::State_Verifying: return &mVerifier;
|
||||||
case CSMDoc::State_Searching: return &mSearch;
|
case CSMDoc::State_Searching: return &mSearch;
|
||||||
|
case CSMDoc::State_Merging: return &mMerge;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -53,7 +55,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
|
||||||
|
|
||||||
std::vector<QString> settings;
|
std::vector<QString> settings;
|
||||||
settings.push_back ("script-editor/warnings");
|
settings.push_back ("script-editor/warnings");
|
||||||
|
|
||||||
mVerifierOperation->configureSettings (settings);
|
mVerifierOperation->configureSettings (settings);
|
||||||
|
|
||||||
connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
|
connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
|
||||||
|
@ -120,9 +122,9 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
|
||||||
return &mVerifier;
|
return &mVerifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMTools::Tools::Tools (CSMDoc::Document& document)
|
CSMTools::Tools::Tools (CSMDoc::Document& document, ToUTF8::FromType encoding)
|
||||||
: mDocument (document), mData (document.getData()), mVerifierOperation (0),
|
: mDocument (document), mData (document.getData()), mVerifierOperation (0),
|
||||||
mSearchOperation (0), mNextReportNumber (0)
|
mSearchOperation (0), mMergeOperation (0), mNextReportNumber (0), mEncoding (encoding)
|
||||||
{
|
{
|
||||||
// index 0: load error log
|
// index 0: load error log
|
||||||
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel));
|
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel));
|
||||||
|
@ -132,6 +134,10 @@ CSMTools::Tools::Tools (CSMDoc::Document& document)
|
||||||
connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
|
connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
|
||||||
connect (&mSearch, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
|
connect (&mSearch, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
|
||||||
this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
|
this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
|
||||||
|
|
||||||
|
connect (&mMerge, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
|
||||||
|
connect (&mMerge, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
|
||||||
|
// don't need to connect report message, since there are no messages for merge
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMTools::Tools::~Tools()
|
CSMTools::Tools::~Tools()
|
||||||
|
@ -148,6 +154,12 @@ CSMTools::Tools::~Tools()
|
||||||
delete mSearchOperation;
|
delete mSearchOperation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mMergeOperation)
|
||||||
|
{
|
||||||
|
mMerge.abortAndWait();
|
||||||
|
delete mMergeOperation;
|
||||||
|
}
|
||||||
|
|
||||||
for (std::map<int, ReportModel *>::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter)
|
for (std::map<int, ReportModel *>::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter)
|
||||||
delete iter->second;
|
delete iter->second;
|
||||||
}
|
}
|
||||||
|
@ -159,7 +171,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier (const CSMWorld::UniversalId&
|
||||||
|
|
||||||
if (mReports.find (reportNumber)==mReports.end())
|
if (mReports.find (reportNumber)==mReports.end())
|
||||||
mReports.insert (std::make_pair (reportNumber, new ReportModel));
|
mReports.insert (std::make_pair (reportNumber, new ReportModel));
|
||||||
|
|
||||||
mActiveReports[CSMDoc::State_Verifying] = reportNumber;
|
mActiveReports[CSMDoc::State_Verifying] = reportNumber;
|
||||||
|
|
||||||
getVerifier()->start();
|
getVerifier()->start();
|
||||||
|
@ -189,6 +201,25 @@ void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Se
|
||||||
mSearch.start();
|
mSearch.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMTools::Tools::runMerge (std::auto_ptr<CSMDoc::Document> target)
|
||||||
|
{
|
||||||
|
// not setting an active report, because merge does not produce messages
|
||||||
|
|
||||||
|
if (!mMergeOperation)
|
||||||
|
{
|
||||||
|
mMergeOperation = new MergeOperation (mDocument, mEncoding);
|
||||||
|
mMerge.setOperation (mMergeOperation);
|
||||||
|
connect (mMergeOperation, SIGNAL (mergeDone (CSMDoc::Document*)),
|
||||||
|
this, SIGNAL (mergeDone (CSMDoc::Document*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
target->flagAsDirty();
|
||||||
|
|
||||||
|
mMergeOperation->setTarget (target);
|
||||||
|
|
||||||
|
mMerge.start();
|
||||||
|
}
|
||||||
|
|
||||||
void CSMTools::Tools::abortOperation (int type)
|
void CSMTools::Tools::abortOperation (int type)
|
||||||
{
|
{
|
||||||
if (CSMDoc::OperationHolder *operation = get (type))
|
if (CSMDoc::OperationHolder *operation = get (type))
|
||||||
|
@ -201,6 +232,7 @@ int CSMTools::Tools::getRunningOperations() const
|
||||||
{
|
{
|
||||||
CSMDoc::State_Verifying,
|
CSMDoc::State_Verifying,
|
||||||
CSMDoc::State_Searching,
|
CSMDoc::State_Searching,
|
||||||
|
CSMDoc::State_Merging,
|
||||||
-1
|
-1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -231,4 +263,3 @@ void CSMTools::Tools::verifierMessage (const CSMDoc::Message& message, int type)
|
||||||
if (iter!=mActiveReports.end())
|
if (iter!=mActiveReports.end())
|
||||||
mReports[iter->second]->add (message);
|
mReports[iter->second]->add (message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
#ifndef CSM_TOOLS_TOOLS_H
|
#ifndef CSM_TOOLS_TOOLS_H
|
||||||
#define CSM_TOOLS_TOOLS_H
|
#define CSM_TOOLS_TOOLS_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include <map>
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
#include "../doc/operationholder.hpp"
|
#include "../doc/operationholder.hpp"
|
||||||
|
|
||||||
|
@ -24,6 +29,7 @@ namespace CSMTools
|
||||||
class ReportModel;
|
class ReportModel;
|
||||||
class Search;
|
class Search;
|
||||||
class SearchOperation;
|
class SearchOperation;
|
||||||
|
class MergeOperation;
|
||||||
|
|
||||||
class Tools : public QObject
|
class Tools : public QObject
|
||||||
{
|
{
|
||||||
|
@ -35,9 +41,12 @@ namespace CSMTools
|
||||||
CSMDoc::OperationHolder mVerifier;
|
CSMDoc::OperationHolder mVerifier;
|
||||||
SearchOperation *mSearchOperation;
|
SearchOperation *mSearchOperation;
|
||||||
CSMDoc::OperationHolder mSearch;
|
CSMDoc::OperationHolder mSearch;
|
||||||
|
MergeOperation *mMergeOperation;
|
||||||
|
CSMDoc::OperationHolder mMerge;
|
||||||
std::map<int, ReportModel *> mReports;
|
std::map<int, ReportModel *> mReports;
|
||||||
int mNextReportNumber;
|
int mNextReportNumber;
|
||||||
std::map<int, int> mActiveReports; // type, report number
|
std::map<int, int> mActiveReports; // type, report number
|
||||||
|
ToUTF8::FromType mEncoding;
|
||||||
|
|
||||||
// not implemented
|
// not implemented
|
||||||
Tools (const Tools&);
|
Tools (const Tools&);
|
||||||
|
@ -53,7 +62,7 @@ namespace CSMTools
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Tools (CSMDoc::Document& document);
|
Tools (CSMDoc::Document& document, ToUTF8::FromType encoding);
|
||||||
|
|
||||||
virtual ~Tools();
|
virtual ~Tools();
|
||||||
|
|
||||||
|
@ -67,7 +76,9 @@ namespace CSMTools
|
||||||
CSMWorld::UniversalId newSearch();
|
CSMWorld::UniversalId newSearch();
|
||||||
|
|
||||||
void runSearch (const CSMWorld::UniversalId& searchId, const Search& search);
|
void runSearch (const CSMWorld::UniversalId& searchId, const Search& search);
|
||||||
|
|
||||||
|
void runMerge (std::auto_ptr<CSMDoc::Document> target);
|
||||||
|
|
||||||
void abortOperation (int type);
|
void abortOperation (int type);
|
||||||
///< \attention The operation is not aborted immediately.
|
///< \attention The operation is not aborted immediately.
|
||||||
|
|
||||||
|
@ -85,6 +96,10 @@ namespace CSMTools
|
||||||
void progress (int current, int max, int type);
|
void progress (int current, int max, int type);
|
||||||
|
|
||||||
void done (int type, bool failed);
|
void done (int type, bool failed);
|
||||||
|
|
||||||
|
/// \attention When this signal is emitted, *this hands over the ownership of the
|
||||||
|
/// document. This signal must be handled to avoid a leak.
|
||||||
|
void mergeDone (CSMDoc::Document *document);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -485,7 +485,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
||||||
mMetaData.addColumn (new FormatColumn<MetaData>);
|
mMetaData.addColumn (new FormatColumn<MetaData>);
|
||||||
mMetaData.addColumn (new AuthorColumn<MetaData>);
|
mMetaData.addColumn (new AuthorColumn<MetaData>);
|
||||||
mMetaData.addColumn (new FileDescriptionColumn<MetaData>);
|
mMetaData.addColumn (new FileDescriptionColumn<MetaData>);
|
||||||
|
|
||||||
addModel (new IdTable (&mGlobals), UniversalId::Type_Global);
|
addModel (new IdTable (&mGlobals), UniversalId::Type_Global);
|
||||||
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst);
|
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst);
|
||||||
addModel (new IdTable (&mSkills), UniversalId::Type_Skill);
|
addModel (new IdTable (&mSkills), UniversalId::Type_Skill);
|
||||||
|
@ -775,11 +775,21 @@ const CSMWorld::IdCollection<CSMWorld::Land>& CSMWorld::Data::getLand() const
|
||||||
return mLand;
|
return mLand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSMWorld::IdCollection<CSMWorld::Land>& CSMWorld::Data::getLand()
|
||||||
|
{
|
||||||
|
return mLand;
|
||||||
|
}
|
||||||
|
|
||||||
const CSMWorld::IdCollection<CSMWorld::LandTexture>& CSMWorld::Data::getLandTextures() const
|
const CSMWorld::IdCollection<CSMWorld::LandTexture>& CSMWorld::Data::getLandTextures() const
|
||||||
{
|
{
|
||||||
return mLandTextures;
|
return mLandTextures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSMWorld::IdCollection<CSMWorld::LandTexture>& CSMWorld::Data::getLandTextures()
|
||||||
|
{
|
||||||
|
return mLandTextures;
|
||||||
|
}
|
||||||
|
|
||||||
const CSMWorld::IdCollection<ESM::SoundGenerator>& CSMWorld::Data::getSoundGens() const
|
const CSMWorld::IdCollection<ESM::SoundGenerator>& CSMWorld::Data::getSoundGens() const
|
||||||
{
|
{
|
||||||
return mSoundGens;
|
return mSoundGens;
|
||||||
|
@ -830,6 +840,12 @@ const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const
|
||||||
return mMetaData.getRecord (0).get();
|
return mMetaData.getRecord (0).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::Data::setMetaData (const MetaData& metaData)
|
||||||
|
{
|
||||||
|
Record<MetaData> record (RecordBase::State_ModifiedOnly, 0, &metaData);
|
||||||
|
mMetaData.setRecord (0, record);
|
||||||
|
}
|
||||||
|
|
||||||
QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
|
QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
|
||||||
{
|
{
|
||||||
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
|
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
|
||||||
|
@ -882,7 +898,7 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
|
||||||
|
|
||||||
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, 0, &metaData));
|
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, 0, &metaData));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mReader->getRecordCount();
|
return mReader->getRecordCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,8 +957,10 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
|
||||||
{
|
{
|
||||||
int index = mLand.load(*mReader, mBase);
|
int index = mLand.load(*mReader, mBase);
|
||||||
|
|
||||||
if (index!=-1 && !mBase)
|
// Load all land data for now. A future optimisation may only load non-base data
|
||||||
mLand.getRecord (index).mModified.mLand->loadData (
|
// if a suitable mechanism for avoiding race conditions can be established.
|
||||||
|
if (index!=-1/* && !mBase*/)
|
||||||
|
mLand.getRecord (index).get().loadData (
|
||||||
ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR |
|
ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR |
|
||||||
ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);
|
ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);
|
||||||
|
|
||||||
|
|
|
@ -232,8 +232,12 @@ namespace CSMWorld
|
||||||
|
|
||||||
const IdCollection<CSMWorld::Land>& getLand() const;
|
const IdCollection<CSMWorld::Land>& getLand() const;
|
||||||
|
|
||||||
|
IdCollection<CSMWorld::Land>& getLand();
|
||||||
|
|
||||||
const IdCollection<CSMWorld::LandTexture>& getLandTextures() const;
|
const IdCollection<CSMWorld::LandTexture>& getLandTextures() const;
|
||||||
|
|
||||||
|
IdCollection<CSMWorld::LandTexture>& getLandTextures();
|
||||||
|
|
||||||
const IdCollection<ESM::SoundGenerator>& getSoundGens() const;
|
const IdCollection<ESM::SoundGenerator>& getSoundGens() const;
|
||||||
|
|
||||||
IdCollection<ESM::SoundGenerator>& getSoundGens();
|
IdCollection<ESM::SoundGenerator>& getSoundGens();
|
||||||
|
@ -255,6 +259,8 @@ namespace CSMWorld
|
||||||
|
|
||||||
const MetaData& getMetaData() const;
|
const MetaData& getMetaData() const;
|
||||||
|
|
||||||
|
void setMetaData (const MetaData& metaData);
|
||||||
|
|
||||||
QAbstractItemModel *getTableModel (const UniversalId& id);
|
QAbstractItemModel *getTableModel (const UniversalId& id);
|
||||||
///< If no table model is available for \a id, an exception is thrown.
|
///< If no table model is available for \a id, an exception is thrown.
|
||||||
///
|
///
|
||||||
|
|
|
@ -4,25 +4,13 @@
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
|
|
||||||
Land::Land()
|
|
||||||
{
|
|
||||||
mLand.reset(new ESM::Land());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Land::load(ESM::ESMReader &esm)
|
void Land::load(ESM::ESMReader &esm)
|
||||||
{
|
{
|
||||||
mLand->load(esm);
|
ESM::Land::load(esm);
|
||||||
|
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
stream << "#" << mLand->mX << " " << mLand->mY;
|
stream << "#" << mX << " " << mY;
|
||||||
|
|
||||||
mId = stream.str();
|
mId = stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Land::blank()
|
|
||||||
{
|
|
||||||
/// \todo
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define CSM_WORLD_LAND_H
|
#define CSM_WORLD_LAND_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/shared_ptr.hpp>
|
|
||||||
#include <components/esm/loadland.hpp>
|
#include <components/esm/loadland.hpp>
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
|
@ -11,18 +11,12 @@ namespace CSMWorld
|
||||||
///
|
///
|
||||||
/// \todo Add worldspace support to the Land record.
|
/// \todo Add worldspace support to the Land record.
|
||||||
/// \todo Add a proper copy constructor (currently worked around using shared_ptr)
|
/// \todo Add a proper copy constructor (currently worked around using shared_ptr)
|
||||||
struct Land
|
struct Land : public ESM::Land
|
||||||
{
|
{
|
||||||
Land();
|
|
||||||
|
|
||||||
boost::shared_ptr<ESM::Land> mLand;
|
|
||||||
|
|
||||||
std::string mId;
|
std::string mId;
|
||||||
|
|
||||||
/// Loads the metadata and ID
|
/// Loads the metadata and ID
|
||||||
void load (ESM::ESMReader &esm);
|
void load (ESM::ESMReader &esm);
|
||||||
|
|
||||||
void blank();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -913,3 +913,8 @@ const CSMWorld::NestedRefIdAdapterBase& CSMWorld::RefIdCollection::getNestedAdap
|
||||||
}
|
}
|
||||||
throw std::runtime_error("No such column in the nestedadapters");
|
throw std::runtime_error("No such column in the nestedadapters");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RefIdCollection::copyTo (int index, RefIdCollection& target) const
|
||||||
|
{
|
||||||
|
mData.copyTo (index, target.mData);
|
||||||
|
}
|
||||||
|
|
|
@ -138,6 +138,7 @@ namespace CSMWorld
|
||||||
void save (int index, ESM::ESMWriter& writer) const;
|
void save (int index, ESM::ESMWriter& writer) const;
|
||||||
|
|
||||||
const RefIdData& getDataSet() const; //I can't figure out a better name for this one :(
|
const RefIdData& getDataSet() const; //I can't figure out a better name for this one :(
|
||||||
|
void copyTo (int index, RefIdCollection& target) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "refiddata.hpp"
|
#include "refiddata.hpp"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
@ -344,7 +345,7 @@ const CSMWorld::RefIdDataContainer< ESM::Static >& CSMWorld::RefIdData::getStati
|
||||||
return mStatics;
|
return mStatics;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id)
|
void CSMWorld::RefIdData::insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id)
|
||||||
{
|
{
|
||||||
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
|
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
|
||||||
mRecordContainers.find (type);
|
mRecordContainers.find (type);
|
||||||
|
@ -357,3 +358,16 @@ void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::U
|
||||||
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
|
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
|
||||||
LocalIndex (iter->second->getSize()-1, type)));
|
LocalIndex (iter->second->getSize()-1, type)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RefIdData::copyTo (int index, RefIdData& target) const
|
||||||
|
{
|
||||||
|
LocalIndex localIndex = globalToLocalIndex (index);
|
||||||
|
|
||||||
|
RefIdDataContainerBase *source = mRecordContainers.find (localIndex.second)->second;
|
||||||
|
|
||||||
|
std::string id = source->getId (localIndex.first);
|
||||||
|
|
||||||
|
std::auto_ptr<CSMWorld::RecordBase> newRecord (source->getRecord (localIndex.first).modifiedCopy());
|
||||||
|
|
||||||
|
target.insertRecord (*newRecord, localIndex.second, id);
|
||||||
|
}
|
||||||
|
|
|
@ -210,7 +210,8 @@ namespace CSMWorld
|
||||||
|
|
||||||
void erase (int index, int count);
|
void erase (int index, int count);
|
||||||
|
|
||||||
void insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id);
|
void insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type,
|
||||||
|
const std::string& id);
|
||||||
|
|
||||||
const RecordBase& getRecord (const LocalIndex& index) const;
|
const RecordBase& getRecord (const LocalIndex& index) const;
|
||||||
|
|
||||||
|
@ -252,11 +253,9 @@ namespace CSMWorld
|
||||||
const RefIdDataContainer<ESM::Probe >& getProbes() const;
|
const RefIdDataContainer<ESM::Probe >& getProbes() const;
|
||||||
const RefIdDataContainer<ESM::Repair>& getRepairs() const;
|
const RefIdDataContainer<ESM::Repair>& getRepairs() const;
|
||||||
const RefIdDataContainer<ESM::Static>& getStatics() const;
|
const RefIdDataContainer<ESM::Static>& getStatics() const;
|
||||||
|
|
||||||
|
void copyTo (int index, RefIdData& target) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon)
|
||||||
QString message;
|
QString message;
|
||||||
|
|
||||||
mValid = (!name.isEmpty());
|
mValid = (!name.isEmpty());
|
||||||
|
bool warning = false;
|
||||||
|
|
||||||
if (!mValid)
|
if (!mValid)
|
||||||
{
|
{
|
||||||
|
@ -105,13 +106,14 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon)
|
||||||
{
|
{
|
||||||
/// \todo add an user setting to make this an error.
|
/// \todo add an user setting to make this an error.
|
||||||
message += "<p>A file with the same name already exists. If you continue, it will be overwritten.";
|
message += "<p>A file with the same name already exists. If you continue, it will be overwritten.";
|
||||||
|
warning = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mMessage->setText (message);
|
mMessage->setText (message);
|
||||||
mIcon->setPixmap (style()->standardIcon (
|
mIcon->setPixmap (style()->standardIcon (
|
||||||
mValid ? QStyle::SP_MessageBoxInformation : QStyle::SP_MessageBoxWarning).
|
mValid ? (warning ? QStyle::SP_MessageBoxWarning : QStyle::SP_MessageBoxInformation) : QStyle::SP_MessageBoxCritical).
|
||||||
pixmap (QSize (16, 16)));
|
pixmap (QSize (16, 16)));
|
||||||
|
|
||||||
emit stateChanged (mValid);
|
emit stateChanged (mValid);
|
||||||
|
|
|
@ -55,3 +55,11 @@ void CSVDoc::FileWidget::extensionLabelIsVisible(bool visible)
|
||||||
{
|
{
|
||||||
mType->setVisible(visible);
|
mType->setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVDoc::FileWidget::setName (const std::string& text)
|
||||||
|
{
|
||||||
|
QString text2 = QString::fromUtf8 (text.c_str());
|
||||||
|
|
||||||
|
mInput->setText (text2);
|
||||||
|
textChanged (text2);
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QString;
|
class QString;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
|
@ -29,6 +31,8 @@ namespace CSVDoc
|
||||||
|
|
||||||
void extensionLabelIsVisible(bool visible);
|
void extensionLabelIsVisible(bool visible);
|
||||||
|
|
||||||
|
void setName (const std::string& text);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void textChanged (const QString& text);
|
void textChanged (const QString& text);
|
||||||
|
|
|
@ -19,6 +19,7 @@ void CSVDoc::Operation::updateLabel (int threads)
|
||||||
case CSMDoc::State_Saving: name = "saving"; break;
|
case CSMDoc::State_Saving: name = "saving"; break;
|
||||||
case CSMDoc::State_Verifying: name = "verifying"; break;
|
case CSMDoc::State_Verifying: name = "verifying"; break;
|
||||||
case CSMDoc::State_Searching: name = "searching"; break;
|
case CSMDoc::State_Searching: name = "searching"; break;
|
||||||
|
case CSMDoc::State_Merging: name = "merging"; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
|
@ -122,7 +123,7 @@ void CSVDoc::Operation::setBarColor (int type)
|
||||||
bottomColor = "#9ECB2D"; //green gloss
|
bottomColor = "#9ECB2D"; //green gloss
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CSMDoc::State_Compiling:
|
case CSMDoc::State_Merging:
|
||||||
|
|
||||||
topColor = "#F3E2C7";
|
topColor = "#F3E2C7";
|
||||||
midTopColor = "#C19E67";
|
midTopColor = "#C19E67";
|
||||||
|
|
|
@ -66,6 +66,10 @@ void CSVDoc::View::setupFileMenu()
|
||||||
connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
|
connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
|
||||||
file->addAction (mVerify);
|
file->addAction (mVerify);
|
||||||
|
|
||||||
|
mMerge = new QAction (tr ("Merge"), this);
|
||||||
|
connect (mMerge, SIGNAL (triggered()), this, SLOT (merge()));
|
||||||
|
file->addAction (mMerge);
|
||||||
|
|
||||||
QAction *loadErrors = new QAction (tr ("Load Error Log"), this);
|
QAction *loadErrors = new QAction (tr ("Load Error Log"), this);
|
||||||
connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog()));
|
connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog()));
|
||||||
file->addAction (loadErrors);
|
file->addAction (loadErrors);
|
||||||
|
@ -393,6 +397,9 @@ void CSVDoc::View::updateActions()
|
||||||
|
|
||||||
mGlobalDebugProfileMenu->updateActions (running);
|
mGlobalDebugProfileMenu->updateActions (running);
|
||||||
mStopDebug->setEnabled (running);
|
mStopDebug->setEnabled (running);
|
||||||
|
|
||||||
|
mMerge->setEnabled (mDocument->getContentFiles().size()>1 &&
|
||||||
|
!(mDocument->getState() & CSMDoc::State_Merging));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews)
|
CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews)
|
||||||
|
@ -471,6 +478,7 @@ void CSVDoc::View::updateDocumentState()
|
||||||
static const int operations[] =
|
static const int operations[] =
|
||||||
{
|
{
|
||||||
CSMDoc::State_Saving, CSMDoc::State_Verifying, CSMDoc::State_Searching,
|
CSMDoc::State_Saving, CSMDoc::State_Verifying, CSMDoc::State_Searching,
|
||||||
|
CSMDoc::State_Merging,
|
||||||
-1 // end marker
|
-1 // end marker
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -968,3 +976,8 @@ void CSVDoc::View::updateScrollbar()
|
||||||
else
|
else
|
||||||
mSubViewWindow.setMinimumWidth(0);
|
mSubViewWindow.setMinimumWidth(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVDoc::View::merge()
|
||||||
|
{
|
||||||
|
emit mergeDocument (mDocument);
|
||||||
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ namespace CSVDoc
|
||||||
QAction *mVerify;
|
QAction *mVerify;
|
||||||
QAction *mShowStatusBar;
|
QAction *mShowStatusBar;
|
||||||
QAction *mStopDebug;
|
QAction *mStopDebug;
|
||||||
|
QAction *mMerge;
|
||||||
std::vector<QAction *> mEditingActions;
|
std::vector<QAction *> mEditingActions;
|
||||||
Operations *mOperations;
|
Operations *mOperations;
|
||||||
SubViewFactoryManager mSubViewFactory;
|
SubViewFactoryManager mSubViewFactory;
|
||||||
|
@ -129,6 +130,8 @@ namespace CSVDoc
|
||||||
|
|
||||||
void editSettingsRequest();
|
void editSettingsRequest();
|
||||||
|
|
||||||
|
void mergeDocument (CSMDoc::Document *document);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void addSubView (const CSMWorld::UniversalId& id, const std::string& hint = "");
|
void addSubView (const CSMWorld::UniversalId& id, const std::string& hint = "");
|
||||||
|
@ -237,6 +240,8 @@ namespace CSVDoc
|
||||||
void closeRequest (SubView *subView);
|
void closeRequest (SubView *subView);
|
||||||
|
|
||||||
void moveScrollBarToEnd(int min, int max);
|
void moveScrollBarToEnd(int min, int max);
|
||||||
|
|
||||||
|
void merge();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
|
||||||
connect (view, SIGNAL (newAddonRequest ()), this, SIGNAL (newAddonRequest()));
|
connect (view, SIGNAL (newAddonRequest ()), this, SIGNAL (newAddonRequest()));
|
||||||
connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest()));
|
connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest()));
|
||||||
connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest()));
|
connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest()));
|
||||||
|
connect (view, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SIGNAL (mergeDocument (CSMDoc::Document *)));
|
||||||
|
|
||||||
connect (&CSMSettings::UserSettings::instance(),
|
connect (&CSMSettings::UserSettings::instance(),
|
||||||
SIGNAL (userSettingUpdated(const QString &, const QStringList &)),
|
SIGNAL (userSettingUpdated(const QString &, const QStringList &)),
|
||||||
|
|
|
@ -77,6 +77,8 @@ namespace CSVDoc
|
||||||
|
|
||||||
void editSettingsRequest();
|
void editSettingsRequest();
|
||||||
|
|
||||||
|
void mergeDocument (CSMDoc::Document *document);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void exitApplication (CSVDoc::View *view);
|
void exitApplication (CSVDoc::View *view);
|
||||||
|
|
|
@ -31,7 +31,7 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
|
|
||||||
const CSMWorld::RefCollection& collection = mData.getReferences();
|
const CSMWorld::RefCollection& collection = mData.getReferences();
|
||||||
|
|
||||||
for (int i=start; i<=end; ++i)
|
for (int i=start; i<=end; ++i)
|
||||||
{
|
{
|
||||||
std::string cell = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mCell);
|
std::string cell = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mCell);
|
||||||
|
@ -67,15 +67,16 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st
|
||||||
int landIndex = land.searchId(mId);
|
int landIndex = land.searchId(mId);
|
||||||
if (landIndex != -1)
|
if (landIndex != -1)
|
||||||
{
|
{
|
||||||
const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get();
|
const ESM::Land& esmLand = land.getRecord(mId).get();
|
||||||
if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT)
|
|
||||||
|
if (esmLand.getLandData (ESM::Land::DATA_VHGT))
|
||||||
{
|
{
|
||||||
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1));
|
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1));
|
||||||
mTerrain->loadCell(esmLand->mX,
|
mTerrain->loadCell(esmLand.mX,
|
||||||
esmLand->mY);
|
esmLand.mY);
|
||||||
|
|
||||||
mX = esmLand->mX;
|
mX = esmLand.mX;
|
||||||
mY = esmLand->mY;
|
mY = esmLand.mY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace CSVRender
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
|
const ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
|
||||||
{
|
{
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
stream << "#" << cellX << " " << cellY;
|
stream << "#" << cellX << " " << cellY;
|
||||||
|
@ -20,11 +20,10 @@ namespace CSVRender
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ESM::Land* land = mData.getLand().getRecord(index).get().mLand.get();
|
const ESM::Land& land = mData.getLand().getRecord(index).get();
|
||||||
int mask = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX;
|
int mask = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX;
|
||||||
if (!land->isDataLoaded(mask))
|
land.loadData (mask);
|
||||||
land->loadData(mask);
|
return &land;
|
||||||
return land;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin)
|
const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin)
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace CSVRender
|
||||||
private:
|
private:
|
||||||
const CSMWorld::Data& mData;
|
const CSMWorld::Data& mData;
|
||||||
|
|
||||||
virtual ESM::Land* getLand (int cellX, int cellY);
|
virtual const ESM::Land* getLand (int cellX, int cellY);
|
||||||
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
|
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
|
||||||
|
|
||||||
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY);
|
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY);
|
||||||
|
|
142
apps/opencs/view/tools/merge.cpp
Normal file
142
apps/opencs/view/tools/merge.cpp
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
|
||||||
|
#include "merge.hpp"
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
#include "../../model/doc/document.hpp"
|
||||||
|
#include "../../model/doc/documentmanager.hpp"
|
||||||
|
|
||||||
|
#include "../doc/filewidget.hpp"
|
||||||
|
#include "../doc/adjusterwidget.hpp"
|
||||||
|
|
||||||
|
void CSVTools::Merge::keyPressEvent (QKeyEvent *event)
|
||||||
|
{
|
||||||
|
if (event->key()==Qt::Key_Escape)
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
QWidget::keyPressEvent (event);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVTools::Merge::Merge (CSMDoc::DocumentManager& documentManager, QWidget *parent)
|
||||||
|
: QWidget (parent), mDocument (0), mDocumentManager (documentManager)
|
||||||
|
{
|
||||||
|
setWindowTitle ("Merge Content Files into a new Game File");
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
setLayout (mainLayout);
|
||||||
|
|
||||||
|
QSplitter *splitter = new QSplitter (Qt::Horizontal, this);
|
||||||
|
|
||||||
|
mainLayout->addWidget (splitter, 1);
|
||||||
|
|
||||||
|
// left panel (files to be merged)
|
||||||
|
QWidget *left = new QWidget (this);
|
||||||
|
left->setContentsMargins (0, 0, 0, 0);
|
||||||
|
splitter->addWidget (left);
|
||||||
|
|
||||||
|
QVBoxLayout *leftLayout = new QVBoxLayout;
|
||||||
|
left->setLayout (leftLayout);
|
||||||
|
|
||||||
|
leftLayout->addWidget (new QLabel ("Files to be merged", this));
|
||||||
|
|
||||||
|
mFiles = new QListWidget (this);
|
||||||
|
leftLayout->addWidget (mFiles, 1);
|
||||||
|
|
||||||
|
// right panel (new game file)
|
||||||
|
QWidget *right = new QWidget (this);
|
||||||
|
right->setContentsMargins (0, 0, 0, 0);
|
||||||
|
splitter->addWidget (right);
|
||||||
|
|
||||||
|
QVBoxLayout *rightLayout = new QVBoxLayout;
|
||||||
|
rightLayout->setAlignment (Qt::AlignTop);
|
||||||
|
right->setLayout (rightLayout);
|
||||||
|
|
||||||
|
rightLayout->addWidget (new QLabel ("New game file", this));
|
||||||
|
|
||||||
|
mNewFile = new CSVDoc::FileWidget (this);
|
||||||
|
mNewFile->setType (false);
|
||||||
|
mNewFile->extensionLabelIsVisible (true);
|
||||||
|
rightLayout->addWidget (mNewFile);
|
||||||
|
|
||||||
|
mAdjuster = new CSVDoc::AdjusterWidget (this);
|
||||||
|
|
||||||
|
rightLayout->addWidget (mAdjuster);
|
||||||
|
|
||||||
|
connect (mNewFile, SIGNAL (nameChanged (const QString&, bool)),
|
||||||
|
mAdjuster, SLOT (setName (const QString&, bool)));
|
||||||
|
connect (mAdjuster, SIGNAL (stateChanged (bool)), this, SLOT (stateChanged (bool)));
|
||||||
|
|
||||||
|
// buttons
|
||||||
|
QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this);
|
||||||
|
|
||||||
|
connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (cancel()));
|
||||||
|
|
||||||
|
mOkay = new QPushButton ("Merge", this);
|
||||||
|
connect (mOkay, SIGNAL (clicked()), this, SLOT (accept()));
|
||||||
|
mOkay->setDefault (true);
|
||||||
|
buttons->addButton (mOkay, QDialogButtonBox::AcceptRole);
|
||||||
|
|
||||||
|
mainLayout->addWidget (buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVTools::Merge::configure (CSMDoc::Document *document)
|
||||||
|
{
|
||||||
|
mDocument = document;
|
||||||
|
|
||||||
|
mNewFile->setName ("");
|
||||||
|
|
||||||
|
// content files
|
||||||
|
while (mFiles->count())
|
||||||
|
delete mFiles->takeItem (0);
|
||||||
|
|
||||||
|
std::vector<boost::filesystem::path> files = document->getContentFiles();
|
||||||
|
|
||||||
|
for (std::vector<boost::filesystem::path>::const_iterator iter (files.begin());
|
||||||
|
iter!=files.end(); ++iter)
|
||||||
|
mFiles->addItem (QString::fromUtf8 (iter->filename().string().c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVTools::Merge::setLocalData (const boost::filesystem::path& localData)
|
||||||
|
{
|
||||||
|
mAdjuster->setLocalData (localData);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMDoc::Document *CSVTools::Merge::getDocument() const
|
||||||
|
{
|
||||||
|
return mDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVTools::Merge::cancel()
|
||||||
|
{
|
||||||
|
mDocument = 0;
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVTools::Merge::accept()
|
||||||
|
{
|
||||||
|
if ((mDocument->getState() & CSMDoc::State_Merging)==0)
|
||||||
|
{
|
||||||
|
std::vector< boost::filesystem::path > files (1, mAdjuster->getPath());
|
||||||
|
|
||||||
|
std::auto_ptr<CSMDoc::Document> target (
|
||||||
|
mDocumentManager.makeDocument (files, files[0], true));
|
||||||
|
|
||||||
|
mDocument->runMerge (target);
|
||||||
|
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVTools::Merge::stateChanged (bool valid)
|
||||||
|
{
|
||||||
|
mOkay->setEnabled (valid);
|
||||||
|
}
|
61
apps/opencs/view/tools/merge.hpp
Normal file
61
apps/opencs/view/tools/merge.hpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#ifndef CSV_TOOLS_REPORTTABLE_H
|
||||||
|
#define CSV_TOOLS_REPORTTABLE_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
|
class QPushButton;
|
||||||
|
class QListWidget;
|
||||||
|
|
||||||
|
namespace CSMDoc
|
||||||
|
{
|
||||||
|
class Document;
|
||||||
|
class DocumentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSVDoc
|
||||||
|
{
|
||||||
|
class FileWidget;
|
||||||
|
class AdjusterWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSVTools
|
||||||
|
{
|
||||||
|
class Merge : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
CSMDoc::Document *mDocument;
|
||||||
|
QPushButton *mOkay;
|
||||||
|
QListWidget *mFiles;
|
||||||
|
CSVDoc::FileWidget *mNewFile;
|
||||||
|
CSVDoc::AdjusterWidget *mAdjuster;
|
||||||
|
CSMDoc::DocumentManager& mDocumentManager;
|
||||||
|
|
||||||
|
void keyPressEvent (QKeyEvent *event);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Merge (CSMDoc::DocumentManager& documentManager, QWidget *parent = 0);
|
||||||
|
|
||||||
|
/// Configure dialogue for a new merge
|
||||||
|
void configure (CSMDoc::Document *document);
|
||||||
|
|
||||||
|
void setLocalData (const boost::filesystem::path& localData);
|
||||||
|
|
||||||
|
CSMDoc::Document *getDocument() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void cancel();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void accept();
|
||||||
|
|
||||||
|
void stateChanged (bool valid);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -461,7 +461,7 @@ namespace MWPhysics
|
||||||
class HeightField
|
class HeightField
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HeightField(float* heights, int x, int y, float triSize, float sqrtVerts)
|
HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts)
|
||||||
{
|
{
|
||||||
// find the minimum and maximum heights (needed for bullet)
|
// find the minimum and maximum heights (needed for bullet)
|
||||||
float minh = heights[0];
|
float minh = heights[0];
|
||||||
|
@ -928,7 +928,7 @@ namespace MWPhysics
|
||||||
return MovementSolver::traceDown(ptr, found->second, mCollisionWorld, maxHeight);
|
return MovementSolver::traceDown(ptr, found->second, mCollisionWorld, maxHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts)
|
void PhysicsSystem::addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts)
|
||||||
{
|
{
|
||||||
HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts);
|
HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts);
|
||||||
mHeightFields[std::make_pair(x,y)] = heightfield;
|
mHeightFields[std::make_pair(x,y)] = heightfield;
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace MWPhysics
|
||||||
void updatePosition (const MWWorld::Ptr& ptr);
|
void updatePosition (const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
|
|
||||||
void addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts);
|
void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts);
|
||||||
|
|
||||||
void removeHeightField (int x, int y);
|
void removeHeightField (int x, int y);
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,9 @@ namespace MWRender
|
||||||
land->loadData(mask);
|
land->loadData(mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ESM::Land::LandData *landData =
|
||||||
|
land ? land->getLandData (ESM::Land::DATA_WNAM) : 0;
|
||||||
|
|
||||||
for (int cellY=0; cellY<mCellSize; ++cellY)
|
for (int cellY=0; cellY<mCellSize; ++cellY)
|
||||||
{
|
{
|
||||||
for (int cellX=0; cellX<mCellSize; ++cellX)
|
for (int cellX=0; cellX<mCellSize; ++cellX)
|
||||||
|
@ -163,15 +166,14 @@ namespace MWRender
|
||||||
int vertexX = static_cast<int>(float(cellX)/float(mCellSize) * 9);
|
int vertexX = static_cast<int>(float(cellX)/float(mCellSize) * 9);
|
||||||
int vertexY = static_cast<int>(float(cellY) / float(mCellSize) * 9);
|
int vertexY = static_cast<int>(float(cellY) / float(mCellSize) * 9);
|
||||||
|
|
||||||
|
|
||||||
int texelX = (x-mMinX) * mCellSize + cellX;
|
int texelX = (x-mMinX) * mCellSize + cellX;
|
||||||
int texelY = (mHeight-1) - ((y-mMinY) * mCellSize + cellY);
|
int texelY = (mHeight-1) - ((y-mMinY) * mCellSize + cellY);
|
||||||
|
|
||||||
unsigned char r,g,b;
|
unsigned char r,g,b;
|
||||||
|
|
||||||
float y = 0;
|
float y = 0;
|
||||||
if (land && land->mDataTypes & ESM::Land::DATA_WNAM)
|
if (landData)
|
||||||
y = (land->mLandData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f;
|
y = (landData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f;
|
||||||
else
|
else
|
||||||
y = (SCHAR_MIN << 4) / 2048.f;
|
y = (SCHAR_MIN << 4) / 2048.f;
|
||||||
if (y < 0)
|
if (y < 0)
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace MWRender
|
||||||
maxY += 1;
|
maxY += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
|
const ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore &esmStore =
|
const MWWorld::ESMStore &esmStore =
|
||||||
MWBase::Environment::get().getWorld()->getStore();
|
MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace MWRender
|
||||||
class TerrainStorage : public ESMTerrain::Storage
|
class TerrainStorage : public ESMTerrain::Storage
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
virtual ESM::Land* getLand (int cellX, int cellY);
|
virtual const ESM::Land* getLand (int cellX, int cellY);
|
||||||
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
|
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -250,9 +250,9 @@ namespace MWWorld
|
||||||
// Actually only VHGT is needed here, but we'll need the rest for rendering anyway.
|
// Actually only VHGT is needed here, but we'll need the rest for rendering anyway.
|
||||||
// Load everything now to reduce IO overhead.
|
// Load everything now to reduce IO overhead.
|
||||||
const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX;
|
const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX;
|
||||||
if (!land->isDataLoaded(flags))
|
|
||||||
land->loadData(flags);
|
const ESM::Land::LandData *data = land->getLandData (flags);
|
||||||
mPhysics->addHeightField (land->mLandData->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(),
|
mPhysics->addHeightField (data->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(),
|
||||||
worldsize / (verts-1), verts);
|
worldsize / (verts-1), verts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "loadland.hpp"
|
#include "loadland.hpp"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "esmreader.hpp"
|
#include "esmreader.hpp"
|
||||||
#include "esmwriter.hpp"
|
#include "esmwriter.hpp"
|
||||||
#include "defs.hpp"
|
#include "defs.hpp"
|
||||||
|
@ -8,7 +10,7 @@ namespace ESM
|
||||||
{
|
{
|
||||||
unsigned int Land::sRecordId = REC_LAND;
|
unsigned int Land::sRecordId = REC_LAND;
|
||||||
|
|
||||||
void Land::LandData::save(ESMWriter &esm)
|
void Land::LandData::save(ESMWriter &esm) const
|
||||||
{
|
{
|
||||||
if (mDataTypes & Land::DATA_VNML) {
|
if (mDataTypes & Land::DATA_VNML) {
|
||||||
esm.writeHNT("VNML", mNormals, sizeof(mNormals));
|
esm.writeHNT("VNML", mNormals, sizeof(mNormals));
|
||||||
|
@ -53,7 +55,7 @@ void Land::LandData::save(ESMWriter &esm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Land::LandData::transposeTextureData(uint16_t *in, uint16_t *out)
|
void Land::LandData::transposeTextureData(const uint16_t *in, uint16_t *out)
|
||||||
{
|
{
|
||||||
int readPos = 0; //bit ugly, but it works
|
int readPos = 0; //bit ugly, but it works
|
||||||
for ( int y1 = 0; y1 < 4; y1++ )
|
for ( int y1 = 0; y1 < 4; y1++ )
|
||||||
|
@ -137,7 +139,7 @@ void Land::save(ESMWriter &esm) const
|
||||||
esm.writeHNT("DATA", mFlags);
|
esm.writeHNT("DATA", mFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Land::loadData(int flags)
|
void Land::loadData(int flags) const
|
||||||
{
|
{
|
||||||
// Try to load only available data
|
// Try to load only available data
|
||||||
flags = flags & mDataTypes;
|
flags = flags & mDataTypes;
|
||||||
|
@ -199,7 +201,7 @@ void Land::unloadData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size)
|
bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const
|
||||||
{
|
{
|
||||||
if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) {
|
if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) {
|
||||||
mEsm->getHExact(ptr, size);
|
mEsm->getHExact(ptr, size);
|
||||||
|
@ -215,4 +217,69 @@ bool Land::isDataLoaded(int flags) const
|
||||||
return (mDataLoaded & flags) == (flags & mDataTypes);
|
return (mDataLoaded & flags) == (flags & mDataTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Land::Land (const Land& land)
|
||||||
|
: mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin),
|
||||||
|
mEsm (land.mEsm), mContext (land.mContext), mDataTypes (land.mDataTypes),
|
||||||
|
mDataLoaded (land.mDataLoaded),
|
||||||
|
mLandData (land.mLandData ? new LandData (*land.mLandData) : 0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Land& Land::operator= (Land land)
|
||||||
|
{
|
||||||
|
swap (land);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Land::swap (Land& land)
|
||||||
|
{
|
||||||
|
std::swap (mFlags, land.mFlags);
|
||||||
|
std::swap (mX, land.mX);
|
||||||
|
std::swap (mY, land.mY);
|
||||||
|
std::swap (mPlugin, land.mPlugin);
|
||||||
|
std::swap (mEsm, land.mEsm);
|
||||||
|
std::swap (mContext, land.mContext);
|
||||||
|
std::swap (mDataTypes, land.mDataTypes);
|
||||||
|
std::swap (mDataLoaded, land.mDataLoaded);
|
||||||
|
std::swap (mLandData, land.mLandData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Land::LandData *Land::getLandData (int flags) const
|
||||||
|
{
|
||||||
|
if (!(flags & mDataTypes))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
loadData (flags);
|
||||||
|
return mLandData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Land::LandData *Land::getLandData() const
|
||||||
|
{
|
||||||
|
return mLandData;
|
||||||
|
}
|
||||||
|
|
||||||
|
Land::LandData *Land::getLandData()
|
||||||
|
{
|
||||||
|
return mLandData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Land::add (int flags)
|
||||||
|
{
|
||||||
|
if (!mLandData)
|
||||||
|
mLandData = new LandData;
|
||||||
|
|
||||||
|
mDataTypes |= flags;
|
||||||
|
mDataLoaded |= flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Land::remove (int flags)
|
||||||
|
{
|
||||||
|
mDataTypes &= ~flags;
|
||||||
|
mDataLoaded &= ~flags;
|
||||||
|
|
||||||
|
if (!mDataLoaded)
|
||||||
|
{
|
||||||
|
delete mLandData;
|
||||||
|
mLandData = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ struct Land
|
||||||
ESM_Context mContext;
|
ESM_Context mContext;
|
||||||
|
|
||||||
int mDataTypes;
|
int mDataTypes;
|
||||||
int mDataLoaded;
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -91,12 +90,10 @@ struct Land
|
||||||
short mUnk1;
|
short mUnk1;
|
||||||
uint8_t mUnk2;
|
uint8_t mUnk2;
|
||||||
|
|
||||||
void save(ESMWriter &esm);
|
void save(ESMWriter &esm) const;
|
||||||
static void transposeTextureData(uint16_t *in, uint16_t *out);
|
static void transposeTextureData(const uint16_t *in, uint16_t *out);
|
||||||
};
|
};
|
||||||
|
|
||||||
LandData *mLandData;
|
|
||||||
|
|
||||||
void load(ESMReader &esm);
|
void load(ESMReader &esm);
|
||||||
void save(ESMWriter &esm) const;
|
void save(ESMWriter &esm) const;
|
||||||
|
|
||||||
|
@ -105,7 +102,7 @@ struct Land
|
||||||
/**
|
/**
|
||||||
* Actually loads data
|
* Actually loads data
|
||||||
*/
|
*/
|
||||||
void loadData(int flags);
|
void loadData(int flags) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frees memory allocated for land data
|
* Frees memory allocated for land data
|
||||||
|
@ -116,14 +113,41 @@ struct Land
|
||||||
/// @note We only check data types that *can* be loaded (present in mDataTypes)
|
/// @note We only check data types that *can* be loaded (present in mDataTypes)
|
||||||
bool isDataLoaded(int flags) const;
|
bool isDataLoaded(int flags) const;
|
||||||
|
|
||||||
|
Land (const Land& land);
|
||||||
|
|
||||||
|
Land& operator= (Land land);
|
||||||
|
|
||||||
|
void swap (Land& land);
|
||||||
|
|
||||||
|
/// Return land data with at least the data types specified in \a flags loaded (if they
|
||||||
|
/// are available). Will return a 0-pointer if there is no data for any of the
|
||||||
|
/// specified types.
|
||||||
|
const LandData *getLandData (int flags) const;
|
||||||
|
|
||||||
|
/// Return land data without loading first anything. Can return a 0-pointer.
|
||||||
|
const LandData *getLandData() const;
|
||||||
|
|
||||||
|
/// Return land data without loading first anything. Can return a 0-pointer.
|
||||||
|
LandData *getLandData();
|
||||||
|
|
||||||
|
/// \attention Must not be called on objects that aren't fully loaded.
|
||||||
|
///
|
||||||
|
/// \note Added data fields will be uninitialised
|
||||||
|
void add (int flags);
|
||||||
|
|
||||||
|
/// \attention Must not be called on objects that aren't fully loaded.
|
||||||
|
void remove (int flags);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Land(const Land& land);
|
|
||||||
Land& operator=(const Land& land);
|
|
||||||
|
|
||||||
/// Loads data and marks it as loaded
|
/// Loads data and marks it as loaded
|
||||||
/// \return true if data is actually loaded from file, false otherwise
|
/// \return true if data is actually loaded from file, false otherwise
|
||||||
/// including the case when data is already loaded
|
/// including the case when data is already loaded
|
||||||
bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size);
|
bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const;
|
||||||
|
|
||||||
|
mutable int mDataLoaded;
|
||||||
|
|
||||||
|
mutable LandData *mLandData;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,14 @@ namespace ESMTerrain
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ESM::Land::LandData *Storage::getLandData (int cellX, int cellY, int flags)
|
||||||
|
{
|
||||||
|
if (const ESM::Land *land = getLand (cellX, cellY))
|
||||||
|
return land->getLandData (flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool Storage::getMinMaxHeights(float size, const osg::Vec2f ¢er, float &min, float &max)
|
bool Storage::getMinMaxHeights(float size, const osg::Vec2f ¢er, float &min, float &max)
|
||||||
{
|
{
|
||||||
assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell");
|
assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell");
|
||||||
|
@ -32,24 +40,25 @@ namespace ESMTerrain
|
||||||
int cellX = static_cast<int>(origin.x());
|
int cellX = static_cast<int>(origin.x());
|
||||||
int cellY = static_cast<int>(origin.y());
|
int cellY = static_cast<int>(origin.y());
|
||||||
|
|
||||||
const ESM::Land* land = getLand(cellX, cellY);
|
if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VHGT))
|
||||||
if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
min = std::numeric_limits<float>::max();
|
|
||||||
max = -std::numeric_limits<float>::max();
|
|
||||||
for (int row=0; row<ESM::Land::LAND_SIZE; ++row)
|
|
||||||
{
|
{
|
||||||
for (int col=0; col<ESM::Land::LAND_SIZE; ++col)
|
min = std::numeric_limits<float>::max();
|
||||||
|
max = -std::numeric_limits<float>::max();
|
||||||
|
for (int row=0; row<ESM::Land::LAND_SIZE; ++row)
|
||||||
{
|
{
|
||||||
float h = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE+row];
|
for (int col=0; col<ESM::Land::LAND_SIZE; ++col)
|
||||||
if (h > max)
|
{
|
||||||
max = h;
|
float h = data->mHeights[col*ESM::Land::LAND_SIZE+row];
|
||||||
if (h < min)
|
if (h > max)
|
||||||
min = h;
|
max = h;
|
||||||
|
if (h < min)
|
||||||
|
min = h;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Storage::fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row)
|
void Storage::fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row)
|
||||||
|
@ -74,12 +83,12 @@ namespace ESMTerrain
|
||||||
--cellX;
|
--cellX;
|
||||||
row += ESM::Land::LAND_SIZE-1;
|
row += ESM::Land::LAND_SIZE-1;
|
||||||
}
|
}
|
||||||
ESM::Land* land = getLand(cellX, cellY);
|
|
||||||
if (land && land->mDataTypes&ESM::Land::DATA_VNML)
|
if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VNML))
|
||||||
{
|
{
|
||||||
normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3];
|
normal.x() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3];
|
||||||
normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1];
|
normal.y() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1];
|
||||||
normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2];
|
normal.z() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2];
|
||||||
normal.normalize();
|
normal.normalize();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -109,12 +118,12 @@ namespace ESMTerrain
|
||||||
++cellX;
|
++cellX;
|
||||||
row = 0;
|
row = 0;
|
||||||
}
|
}
|
||||||
ESM::Land* land = getLand(cellX, cellY);
|
|
||||||
if (land && land->mDataTypes&ESM::Land::DATA_VCLR)
|
if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VCLR))
|
||||||
{
|
{
|
||||||
color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f;
|
color.r() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f;
|
||||||
color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f;
|
color.g() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f;
|
||||||
color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f;
|
color.b() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -158,9 +167,9 @@ namespace ESMTerrain
|
||||||
float vertX_ = 0; // of current cell corner
|
float vertX_ = 0; // of current cell corner
|
||||||
for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX)
|
for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX)
|
||||||
{
|
{
|
||||||
ESM::Land* land = getLand(cellX, cellY);
|
const ESM::Land::LandData *heightData = getLandData (cellX, cellY, ESM::Land::DATA_VHGT);
|
||||||
if (land && !(land->mDataTypes&ESM::Land::DATA_VHGT))
|
const ESM::Land::LandData *normalData = getLandData (cellX, cellY, ESM::Land::DATA_VNML);
|
||||||
land = NULL;
|
const ESM::Land::LandData *colourData = getLandData (cellX, cellY, ESM::Land::DATA_VCLR);
|
||||||
|
|
||||||
int rowStart = 0;
|
int rowStart = 0;
|
||||||
int colStart = 0;
|
int colStart = 0;
|
||||||
|
@ -177,20 +186,22 @@ namespace ESMTerrain
|
||||||
vertX = vertX_;
|
vertX = vertX_;
|
||||||
for (int row=rowStart; row<ESM::Land::LAND_SIZE; row += increment)
|
for (int row=rowStart; row<ESM::Land::LAND_SIZE; row += increment)
|
||||||
{
|
{
|
||||||
|
int arrayIndex = col*ESM::Land::LAND_SIZE*3+row*3;
|
||||||
|
|
||||||
float height = -2048;
|
float height = -2048;
|
||||||
if (land)
|
if (heightData)
|
||||||
height = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE + row];
|
height = heightData->mHeights[col*ESM::Land::LAND_SIZE + row];
|
||||||
|
|
||||||
(*positions)[static_cast<unsigned int>(vertX*numVerts + vertY)]
|
(*positions)[static_cast<unsigned int>(vertX*numVerts + vertY)]
|
||||||
= osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * 8192,
|
= osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * 8192,
|
||||||
(vertY / float(numVerts - 1) - 0.5f) * size * 8192,
|
(vertY / float(numVerts - 1) - 0.5f) * size * 8192,
|
||||||
height);
|
height);
|
||||||
|
|
||||||
if (land && land->mDataTypes&ESM::Land::DATA_VNML)
|
if (normalData)
|
||||||
{
|
{
|
||||||
normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3];
|
for (int i=0; i<3; ++i)
|
||||||
normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1];
|
normal[i] = normalData->mNormals[arrayIndex+i];
|
||||||
normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2];
|
|
||||||
normal.normalize();
|
normal.normalize();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -208,11 +219,10 @@ namespace ESMTerrain
|
||||||
|
|
||||||
(*normals)[static_cast<unsigned int>(vertX*numVerts + vertY)] = normal;
|
(*normals)[static_cast<unsigned int>(vertX*numVerts + vertY)] = normal;
|
||||||
|
|
||||||
if (land && land->mDataTypes&ESM::Land::DATA_VCLR)
|
if (colourData)
|
||||||
{
|
{
|
||||||
color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f;
|
for (int i=0; i<3; ++i)
|
||||||
color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f;
|
color[i] = colourData->mColours[arrayIndex+i] / 255.f;
|
||||||
color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -262,13 +272,12 @@ namespace ESMTerrain
|
||||||
assert(x<ESM::Land::LAND_TEXTURE_SIZE);
|
assert(x<ESM::Land::LAND_TEXTURE_SIZE);
|
||||||
assert(y<ESM::Land::LAND_TEXTURE_SIZE);
|
assert(y<ESM::Land::LAND_TEXTURE_SIZE);
|
||||||
|
|
||||||
ESM::Land* land = getLand(cellX, cellY);
|
if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VTEX))
|
||||||
if (land && (land->mDataTypes&ESM::Land::DATA_VTEX))
|
|
||||||
{
|
{
|
||||||
int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
|
int tex = data->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
|
||||||
if (tex == 0)
|
if (tex == 0)
|
||||||
return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin
|
return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin
|
||||||
return std::make_pair(tex, land->mPlugin);
|
return std::make_pair(tex, getLand (cellX, cellY)->mPlugin);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return std::make_pair(0,0);
|
return std::make_pair(0,0);
|
||||||
|
@ -368,7 +377,7 @@ namespace ESMTerrain
|
||||||
int cellX = static_cast<int>(std::floor(worldPos.x() / 8192.f));
|
int cellX = static_cast<int>(std::floor(worldPos.x() / 8192.f));
|
||||||
int cellY = static_cast<int>(std::floor(worldPos.y() / 8192.f));
|
int cellY = static_cast<int>(std::floor(worldPos.y() / 8192.f));
|
||||||
|
|
||||||
ESM::Land* land = getLand(cellX, cellY);
|
const ESM::Land* land = getLand(cellX, cellY);
|
||||||
if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT))
|
if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT))
|
||||||
return -2048;
|
return -2048;
|
||||||
|
|
||||||
|
@ -447,7 +456,7 @@ namespace ESMTerrain
|
||||||
{
|
{
|
||||||
assert(x < ESM::Land::LAND_SIZE);
|
assert(x < ESM::Land::LAND_SIZE);
|
||||||
assert(y < ESM::Land::LAND_SIZE);
|
assert(y < ESM::Land::LAND_SIZE);
|
||||||
return land->mLandData->mHeights[y * ESM::Land::LAND_SIZE + x];
|
return land->getLandData()->mHeights[y * ESM::Land::LAND_SIZE + x];
|
||||||
}
|
}
|
||||||
|
|
||||||
Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture)
|
Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture)
|
||||||
|
|
|
@ -21,12 +21,17 @@ namespace ESMTerrain
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Not implemented in this class, because we need different Store implementations for game and editor
|
// Not implemented in this class, because we need different Store implementations for game and editor
|
||||||
virtual ESM::Land* getLand (int cellX, int cellY) = 0;
|
virtual const ESM::Land* getLand (int cellX, int cellY)= 0;
|
||||||
virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0;
|
virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Storage(const VFS::Manager* vfs);
|
Storage(const VFS::Manager* vfs);
|
||||||
|
|
||||||
|
/// Data is loaded first, if necessary. Will return a 0-pointer if there is no data for
|
||||||
|
/// any of the data types specified via \a flags. Will also return a 0-pointer if there
|
||||||
|
/// is no land record for the coordinates \a cellX / \a cellY.
|
||||||
|
const ESM::Land::LandData *getLandData (int cellX, int cellY, int flags);
|
||||||
|
|
||||||
// Not implemented in this class, because we need different Store implementations for game and editor
|
// Not implemented in this class, because we need different Store implementations for game and editor
|
||||||
/// Get bounds of the whole terrain in cell units
|
/// Get bounds of the whole terrain in cell units
|
||||||
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) = 0;
|
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) = 0;
|
||||||
|
|
Loading…
Reference in a new issue