mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:29:55 +00:00
Use a separate storage for groundcover data
This commit is contained in:
parent
ca64d7bc18
commit
3275440f0d
10 changed files with 125 additions and 40 deletions
|
@ -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();
|
||||
|
|
54
apps/openmw/mwworld/groundcoverstore.cpp
Normal file
54
apps/openmw/mwworld/groundcoverstore.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
29
apps/openmw/mwworld/groundcoverstore.hpp
Normal file
29
apps/openmw/mwworld/groundcoverstore.hpp
Normal file
|
@ -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
|
|
@ -157,11 +157,7 @@ namespace MWWorld
|
|||
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…
Reference in a new issue