From c8054424c946ed5433b325d2f1301f16d7d78b64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Feb 2016 22:37:52 +0100 Subject: [PATCH] Preload items equipped by NPCs --- apps/openmw/mwworld/cellpreloader.cpp | 68 ++++++++++++++++++++++++--- apps/openmw/mwworld/cellpreloader.hpp | 2 +- apps/openmw/mwworld/scene.cpp | 7 +++ components/resource/scenemanager.cpp | 3 ++ 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 13ce75d685..6bf28cb48e 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -5,10 +5,14 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwworld/esmstore.hpp" + #include "cellstore.hpp" #include "manualref.hpp" #include "class.hpp" @@ -23,11 +27,54 @@ namespace MWWorld { } - virtual bool operator()(const MWWorld::ConstPtr& ptr) + virtual bool operator()(const MWWorld::Ptr& ptr) { std::string model = ptr.getClass().getModel(ptr); if (!model.empty()) mOut.push_back(model); + + // TODO: preload NPC body parts (mHead / mHair) + + // FIXME: use const version of InventoryStore functions once they are available + if (ptr.getClass().hasInventoryStore(ptr)) + { + MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr); + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator equipped = invStore.getSlot(slot); + if (equipped != invStore.end()) + { + std::vector parts; + if(equipped->getTypeName() == typeid(ESM::Clothing).name()) + { + const ESM::Clothing *clothes = equipped->get()->mBase; + parts = clothes->mParts.mParts; + } + else if(equipped->getTypeName() == typeid(ESM::Armor).name()) + { + const ESM::Armor *armor = equipped->get()->mBase; + parts = armor->mParts.mParts; + } + else + { + model = equipped->getClass().getModel(*equipped); + if (!model.empty()) + mOut.push_back(model); + } + + for (std::vector::const_iterator it = parts.begin(); it != parts.end(); ++it) + { + const ESM::BodyPart* part = MWBase::Environment::get().getWorld()->getStore().get().search(it->mMale); + if (part && !part->mModel.empty()) + mOut.push_back("meshes/"+part->mModel); + part = MWBase::Environment::get().getWorld()->getStore().get().search(it->mFemale); + if (part && !part->mModel.empty()) + mOut.push_back("meshes/"+part->mModel); + } + } + } + } + return true; } @@ -39,14 +86,15 @@ namespace MWWorld { public: /// Constructor to be called from the main thread. - PreloadItem(const MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager) + PreloadItem(MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager) : mSceneManager(sceneManager) , mBulletShapeManager(bulletShapeManager) { + osg::Timer timer; + ListModelsVisitor visitor (mMeshes); if (cell->getState() == MWWorld::CellStore::State_Loaded) { - ListModelsVisitor visitor (mMeshes); - cell->forEachConst(visitor); + cell->forEach(visitor); } else { @@ -61,6 +109,7 @@ namespace MWWorld mMeshes.push_back(model); } } + std::cout << "listed models in " << timer.time_m() << std::endl; } /// Preload work to be called from the worker thread. @@ -73,9 +122,16 @@ namespace MWWorld { try { + std::string mesh = *it; + Misc::ResourceHelpers::correctActorModelPath(mesh, mSceneManager->getVFS()); + + //std::cout << "preloading " << mesh << std::endl; + mPreloadedNodes.push_back(mSceneManager->getTemplate(*it)); mPreloadedShapes.push_back(mBulletShapeManager->getShape(*it)); + // TODO: load .kf + // TODO: do a createInstance() and hold on to it since we can make use of it when the cell goes active } catch (std::exception& e) @@ -84,7 +140,7 @@ namespace MWWorld // error will be shown when visiting the cell } } - std::cout << "preloaded " << mPreloadedNodes.size() << " nodes in " << preloadTimer.time_m() << std::endl; + //std::cout << "preloaded " << mPreloadedNodes.size() << " nodes in " << preloadTimer.time_m() << std::endl; } private: @@ -128,7 +184,7 @@ namespace MWWorld mWorkQueue = new SceneUtil::WorkQueue; } - void CellPreloader::preload(const CellStore *cell, double timestamp) + void CellPreloader::preload(CellStore *cell, double timestamp) { if (!mWorkQueue) { diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index 5a24321795..c7495182b3 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -22,7 +22,7 @@ namespace MWWorld /// Ask a background thread to preload rendering meshes and collision shapes for objects in this cell. /// @note The cell itself must be in State_Loaded or State_Preloaded. - void preload(const MWWorld::CellStore* cell, double timestamp); + void preload(MWWorld::CellStore* cell, double timestamp); /// Removes preloaded cells that have not had a preload request for a while. void updateCache(double timestamp); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 86f40df73e..321c1c622e 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -329,6 +330,7 @@ namespace MWWorld void Scene::changeCellGrid (int X, int Y) { + osg::Timer timer; Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); Loading::ScopedLoad load(loadingListener); @@ -413,6 +415,8 @@ namespace MWWorld mPreloader->updateCache(mRendering.getReferenceTime()); mRendering.clearCache(); + + std::cout << "changeCellGrid took " << timer.time_m() << std::endl; } void Scene::changePlayerCell(CellStore *cell, const ESM::Position &pos, bool adjustPlayerPos) @@ -477,6 +481,7 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { + osg::Timer timer; CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); bool loadcell = (mCurrentCell == NULL); if(!loadcell) @@ -537,6 +542,8 @@ namespace MWWorld mPreloader->updateCache(mRendering.getReferenceTime()); mRendering.clearCache(); + + std::cout << "change to interior took " << timer.time_m() << std::endl; } void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 46d975631e..f083e8175d 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -1,5 +1,6 @@ #include "scenemanager.hpp" +#include #include #include #include @@ -364,6 +365,8 @@ namespace Resource if (mIncrementalCompileOperation) mIncrementalCompileOperation->add(loaded); + //std::cout << "loading " << normalized << std::endl; + mCache->addEntryToObjectCache(normalized, loaded); return loaded; }