Use a separate storage for groundcover data

pull/3206/head
Andrei Kortunov 3 years ago
parent ca64d7bc18
commit 3275440f0d

@ -74,7 +74,7 @@ add_openmw_dir (mwworld
actionequip timestamp actionalchemy cellstore actionapply actioneat
store esmstore fallback actionrepair actionsoulgem livecellref actiondoor
contentloader esmloader actiontrap cellreflist cellref weather projectilemanager
cellpreloader datetimemanager
cellpreloader datetimemanager groundcoverstore
)
add_openmw_dir (mwphysics

@ -13,22 +13,12 @@
#include <components/terrain/quadtreenode.hpp>
#include <components/shader/shadermanager.hpp>
#include "apps/openmw/mwworld/esmstore.hpp"
#include "apps/openmw/mwbase/environment.hpp"
#include "apps/openmw/mwbase/world.hpp"
#include "../mwworld/groundcoverstore.hpp"
#include "vismask.hpp"
namespace MWRender
{
std::string getGroundcoverModel(const std::string& id, const MWWorld::ESMStore& groundcoverStore, const MWWorld::ESMStore& store)
{
const ESM::Static* stat = groundcoverStore.get<ESM::Static>().searchStatic(id);
if (!stat)
stat = store.get<ESM::Static>().searchStatic(id);
return stat ? stat->mModel : std::string();
}
class InstancingVisitor : public osg::NodeVisitor
{
public:
@ -153,7 +143,7 @@ namespace MWRender
}
}
Groundcover::Groundcover(Resource::SceneManager* sceneManager, float density, float viewDistance, const MWWorld::ESMStore& store)
Groundcover::Groundcover(Resource::SceneManager* sceneManager, float density, float viewDistance, const MWWorld::GroundcoverStore& store)
: GenericResourceManager<GroundcoverChunkId>(nullptr)
, mSceneManager(sceneManager)
, mDensity(density)
@ -183,7 +173,6 @@ namespace MWRender
{
if (mDensity <=0.f) return;
const MWWorld::ESMStore& worldStore = MWBase::Environment::get().getWorld()->getStore();
osg::Vec2f minBound = (center - osg::Vec2f(size/2.f, size/2.f));
osg::Vec2f maxBound = (center + osg::Vec2f(size/2.f, size/2.f));
DensityCalculator calculator(mDensity);
@ -193,21 +182,22 @@ namespace MWRender
{
for (int cellY = startCell.y(); cellY < startCell.y() + size; ++cellY)
{
const ESM::Cell* cell = mGroundcoverStore.get<ESM::Cell>().searchStatic(cellX, cellY);
if (!cell) continue;
ESM::Cell cell;
mGroundcoverStore.initCell(cell, cellX, cellY);
if (cell.mContextList.empty()) continue;
calculator.reset();
std::map<ESM::RefNum, ESM::CellRef> refs;
for (size_t i=0; i<cell->mContextList.size(); ++i)
for (size_t i=0; i<cell.mContextList.size(); ++i)
{
unsigned int index = cell->mContextList[i].index;
unsigned int index = cell.mContextList[i].index;
if (esm.size() <= index)
esm.resize(index+1);
cell->restore(esm[index], i);
cell.restore(esm[index], i);
ESM::CellRef ref;
ref.mRefNum.unset();
bool deleted = false;
while(cell->getNextRef(esm[index], ref, deleted))
while(cell.getNextRef(esm[index], ref, deleted))
{
if (!deleted && refs.find(ref.mRefNum) == refs.end() && !calculator.isInstanceEnabled()) deleted = true;
if (!deleted && !isInChunkBorders(ref, minBound, maxBound)) deleted = true;
@ -220,9 +210,9 @@ namespace MWRender
for (auto& pair : refs)
{
ESM::CellRef& ref = pair.second;
const std::string& model = getGroundcoverModel(ref.mRefID, mGroundcoverStore, worldStore);
const std::string& model = mGroundcoverStore.getGroundcoverModel(ref.mRefID);
if (!model.empty())
instances["meshes\\" + model].emplace_back(std::move(ref));
instances[model].emplace_back(std::move(ref));
}
}
}

@ -8,6 +8,7 @@
namespace MWWorld
{
class ESMStore;
class GroundcoverStore;
}
namespace osg
{
@ -20,7 +21,7 @@ namespace MWRender
class Groundcover : public Resource::GenericResourceManager<GroundcoverChunkId>, public Terrain::QuadTreeWorld::ChunkManager
{
public:
Groundcover(Resource::SceneManager* sceneManager, float density, float viewDistance, const MWWorld::ESMStore& groundcoverStore);
Groundcover(Resource::SceneManager* sceneManager, float density, float viewDistance, const MWWorld::GroundcoverStore& store);
~Groundcover();
osg::ref_ptr<osg::Node> getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile) override;
@ -43,8 +44,7 @@ namespace MWRender
float mDensity;
osg::ref_ptr<osg::StateSet> mStateset;
osg::ref_ptr<osg::Program> mProgramTemplate;
/// @note mGroundcoverStore is separated from World's store because groundcover files must not be allowed to corrupt normal content files.
const MWWorld::ESMStore& mGroundcoverStore;
const MWWorld::GroundcoverStore& mGroundcoverStore;
typedef std::map<std::string, std::vector<GroundcoverEntry>> InstanceMap;
osg::ref_ptr<osg::Node> createChunk(InstanceMap& instances, const osg::Vec2f& center);

@ -49,6 +49,7 @@
#include "../mwworld/cellstore.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/groundcoverstore.hpp"
#include "../mwgui/loadingscreen.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwmechanics/actorutil.hpp"
@ -294,7 +295,7 @@ namespace MWRender
RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode,
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
const std::string& resourcePath, DetourNavigator::Navigator& navigator, const MWWorld::ESMStore& groundcoverStore)
const std::string& resourcePath, DetourNavigator::Navigator& navigator, const MWWorld::GroundcoverStore& groundcoverStore)
: mViewer(viewer)
, mRootNode(rootNode)
, mResourceSystem(resourceSystem)

@ -67,6 +67,11 @@ namespace DetourNavigator
struct Settings;
}
namespace MWWorld
{
class GroundcoverStore;
}
namespace MWRender
{
class StateUpdater;
@ -95,7 +100,7 @@ namespace MWRender
public:
RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode,
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
const std::string& resourcePath, DetourNavigator::Navigator& navigator, const MWWorld::ESMStore& groundcoverStore);
const std::string& resourcePath, DetourNavigator::Navigator& navigator, const MWWorld::GroundcoverStore& groundcoverStore);
~RenderingManager();
osgUtil::IncrementalCompileOperation* getIncrementalCompileOperation();

@ -0,0 +1,54 @@
#include "groundcoverstore.hpp"
#include <components/esmloader/load.hpp>
#include <components/misc/stringops.hpp>
namespace MWWorld
{
void GroundcoverStore::init(const Store<ESM::Static>& statics, const Files::Collections& fileCollections, const std::vector<std::string>& groundcoverFiles, ToUTF8::Utf8Encoder* encoder)
{
EsmLoader::Query query;
query.mLoadStatics = true;
query.mLoadCells = true;
std::vector<ESM::ESMReader> readers(groundcoverFiles.size());
const EsmLoader::EsmData content = EsmLoader::loadEsmData(query, groundcoverFiles, fileCollections, readers, encoder);
for (const ESM::Static& stat : statics)
{
std::string id = Misc::StringUtils::lowerCase(stat.mId);
mMeshCache[id] = "meshes\\" + Misc::StringUtils::lowerCase(stat.mModel);
}
for (const ESM::Static& stat : content.mStatics)
{
std::string id = Misc::StringUtils::lowerCase(stat.mId);
mMeshCache[id] = "meshes\\" + Misc::StringUtils::lowerCase(stat.mModel);
}
for (const ESM::Cell& cell : content.mCells)
{
if (!cell.isExterior()) continue;
auto cellIndex = std::make_pair(cell.getCellId().mIndex.mX, cell.getCellId().mIndex.mY);
mCellContexts[cellIndex] = std::move(cell.mContextList);
}
}
std::string GroundcoverStore::getGroundcoverModel(const std::string& id) const
{
std::string idLower = Misc::StringUtils::lowerCase(id);
auto search = mMeshCache.find(idLower);
if (search == mMeshCache.end()) return std::string();
return search->second;
}
void GroundcoverStore::initCell(ESM::Cell& cell, int cellX, int cellY) const
{
cell.blank();
auto searchCell = mCellContexts.find(std::make_pair(cellX, cellY));
if (searchCell != mCellContexts.end())
cell.mContextList = searchCell->second;
}
}

@ -0,0 +1,29 @@
#ifndef GAME_MWWORLD_GROUNDCOVER_STORE_H
#define GAME_MWWORLD_GROUNDCOVER_STORE_H
#include <vector>
#include <string>
#include <map>
#include <components/esm/esmreader.hpp>
#include <components/esmloader/esmdata.hpp>
#include <components/files/collections.hpp>
#include "esmstore.hpp"
namespace MWWorld
{
class GroundcoverStore
{
private:
std::map<std::string, std::string> mMeshCache;
std::map<std::pair<int, int>, std::vector<ESM::ESM_Context>> mCellContexts;
public:
void init(const Store<ESM::Static>& statics, const Files::Collections& fileCollections, const std::vector<std::string>& groundcoverFiles, ToUTF8::Utf8Encoder* encoder);
std::string getGroundcoverModel(const std::string& id) const;
void initCell(ESM::Cell& cell, int cellX, int cellY) const;
};
}
#endif

@ -155,13 +155,9 @@ namespace MWWorld
mEsm.resize(contentFiles.size());
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
listener->loadingOn();
loadContentFiles(fileCollections, contentFiles, mStore, mEsm, encoder, listener);
if (!groundcoverFiles.empty())
{
std::vector<ESM::ESMReader> tempReaders (groundcoverFiles.size());
loadContentFiles(fileCollections, groundcoverFiles, mGroundcoverStore, tempReaders, encoder, listener, false);
}
loadGroundcoverFiles(fileCollections, groundcoverFiles, encoder);
listener->loadingOff();
@ -2948,12 +2944,11 @@ namespace MWWorld
return mScriptsEnabled;
}
void World::loadContentFiles(const Files::Collections& fileCollections, const std::vector<std::string>& content, ESMStore& store, std::vector<ESM::ESMReader>& readers, ToUTF8::Utf8Encoder* encoder, Loading::Listener* listener, bool validate)
void World::loadContentFiles(const Files::Collections& fileCollections, const std::vector<std::string>& content, ESMStore& store, std::vector<ESM::ESMReader>& readers, ToUTF8::Utf8Encoder* encoder, Loading::Listener* listener)
{
GameContentLoader gameContentLoader(*listener);
EsmLoader esmLoader(store, readers, encoder, *listener);
if (validate)
validateMasterFiles(readers);
validateMasterFiles(readers);
gameContentLoader.addLoader(".esm", &esmLoader);
gameContentLoader.addLoader(".esp", &esmLoader);
@ -2982,6 +2977,15 @@ namespace MWWorld
}
}
void World::loadGroundcoverFiles(const Files::Collections& fileCollections, const std::vector<std::string>& groundcoverFiles, ToUTF8::Utf8Encoder* encoder)
{
if (!Settings::Manager::getBool("enabled", "Groundcover")) return;
Log(Debug::Info) << "Loading groundcover:";
mGroundcoverStore.init(mStore.get<ESM::Static>(), fileCollections, groundcoverFiles, encoder);
}
bool World::startSpellCast(const Ptr &actor)
{
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);

@ -15,6 +15,7 @@
#include "timestamp.hpp"
#include "globals.hpp"
#include "contentloader.hpp"
#include "groundcoverstore.hpp"
namespace osg
{
@ -80,7 +81,7 @@ namespace MWWorld
std::vector<ESM::ESMReader> mEsm;
MWWorld::ESMStore mStore;
MWWorld::ESMStore mGroundcoverStore;
GroundcoverStore mGroundcoverStore;
LocalScripts mLocalScripts;
MWWorld::Globals mGlobalVariables;
@ -164,10 +165,9 @@ namespace MWWorld
void updateSkyDate();
// A helper method called automatically during World construction.
void loadContentFiles(const Files::Collections& fileCollections, const std::vector<std::string>& content,
ESMStore& store, std::vector<ESM::ESMReader>& readers, ToUTF8::Utf8Encoder* encoder, Loading::Listener* listener, bool validateMasterFiles = true);
void loadContentFiles(const Files::Collections& fileCollections, const std::vector<std::string>& content, ESMStore& store, std::vector<ESM::ESMReader>& readers, ToUTF8::Utf8Encoder* encoder, Loading::Listener* listener);
void loadGroundcoverFiles(const Files::Collections& fileCollections, const std::vector<std::string>& groundcoverFiles, ToUTF8::Utf8Encoder* encoder);
float feetToGameUnits(float feet);
float getActivationDistancePlusTelekinesis();

@ -215,6 +215,8 @@ namespace EsmLoader
reader.setEncoder(encoder);
reader.setIndex(static_cast<int>(i));
reader.open(collection.getPath(file).string());
if (query.mLoadCells)
reader.resolveParentFileIndices(readers);
loadEsm(query, readers[i], result);
}

Loading…
Cancel
Save