From effe022bb2a2e5d15cc03324facd11a145d639dd Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Feb 2016 20:52:32 +0100 Subject: [PATCH] Move preload model list to MWClass, preload NPC head/hair --- apps/openmw/mwclass/creature.cpp | 23 +++++++++ apps/openmw/mwclass/creature.hpp | 3 ++ apps/openmw/mwclass/npc.cpp | 68 +++++++++++++++++++++++++++ apps/openmw/mwclass/npc.hpp | 3 ++ apps/openmw/mwworld/cellpreloader.cpp | 46 +----------------- apps/openmw/mwworld/class.cpp | 7 +++ apps/openmw/mwworld/class.hpp | 3 ++ 7 files changed, 108 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e9502d86b..6e9cfccb9 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -182,6 +182,29 @@ namespace MWClass return ""; } + void Creature::getModelsToPreload(const MWWorld::Ptr &ptr, std::vector &models) const + { + std::string model = getModel(ptr); + if (!model.empty()) + models.push_back(model); + + // 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()) + { + model = equipped->getClass().getModel(*equipped); + if (!model.empty()) + models.push_back(model); + } + } + } + } + std::string Creature::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index cb89a53d6..bea56887a 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -101,6 +101,9 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; + virtual void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector& models) const; + ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: list getModel(). + virtual bool isActor() const { return true; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 57a6d088a..14bd0640c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -429,6 +429,74 @@ namespace MWClass return model; } + void Npc::getModelsToPreload(const MWWorld::Ptr &ptr, std::vector &models) const + { + const MWWorld::LiveCellRef *npc = ptr.get(); + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().search(npc->mBase->mRace); + if(race && race->mData.mFlags & ESM::Race::Beast) + models.push_back("meshes\\base_animkna.nif"); + + // keep these always loaded just in case + models.push_back("meshes/xargonian_swimkna.nif"); + models.push_back("meshes/xbase_anim_female.nif"); + models.push_back("meshes/xbase_anim.nif"); + + if (!npc->mBase->mModel.empty()) + models.push_back("meshes/"+npc->mBase->mModel); + + if (!npc->mBase->mHead.empty()) + { + const ESM::BodyPart* head = MWBase::Environment::get().getWorld()->getStore().get().search(npc->mBase->mHead); + if (head) + models.push_back("meshes/"+head->mModel); + } + if (!npc->mBase->mHair.empty()) + { + const ESM::BodyPart* hair = MWBase::Environment::get().getWorld()->getStore().get().search(npc->mBase->mHair); + if (hair) + models.push_back("meshes/"+hair->mModel); + } + + // 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 + { + std::string model = equipped->getClass().getModel(*equipped); + if (!model.empty()) + models.push_back(model); + } + + for (std::vector::const_iterator it = parts.begin(); it != parts.end(); ++it) + { + const std::string& partname = (npc->mBase->mFlags & ESM::NPC::Female) ? it->mFemale : it->mMale; + const ESM::BodyPart* part = MWBase::Environment::get().getWorld()->getStore().get().search(partname); + if (part && !part->mModel.empty()) + models.push_back("meshes/"+part->mModel); + } + } + } + } + + } + std::string Npc::getName (const MWWorld::ConstPtr& ptr) const { if(ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf()) diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 5df34380a..95edbd408 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -75,6 +75,9 @@ namespace MWClass virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; + virtual void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector& models) const; + ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: list getModel(). + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 4780582c5..1a8ee2709 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -31,51 +31,7 @@ namespace MWWorld 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); - } - } - } - } + ptr.getClass().getModelsToPreload(ptr, mOut); return true; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 7f2d759b9..ecfe7cb7c 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -291,6 +291,13 @@ namespace MWWorld return ""; } + void Class::getModelsToPreload(const Ptr &ptr, std::vector &models) const + { + std::string model = getModel(ptr); + if (!model.empty()) + models.push_back(model); + } + std::string Class::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 85cd9ff7c..0bb3edbee 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -262,6 +262,9 @@ namespace MWWorld virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; + virtual void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector& models) const; + ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: list getModel(). + virtual std::string applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it.