From bef4bef5d229e7f4f5335f6a4e3a6f83a8fc5d80 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sun, 10 Jun 2012 11:14:46 +0200 Subject: [PATCH 01/92] - Add support for loading multiple esm/esp files. Selection in omwlauncher is recognized and applied. - Quick hack for multiple terrain palettes. Prevents crashes and/or wrong textures in masters/plugins beyond the first. - Support deleting parent entries from the list. --- apps/openmw/engine.cpp | 30 ++++++++++++++----- apps/openmw/engine.hpp | 8 +++-- apps/openmw/main.cpp | 26 +++++++++------- apps/openmw/mwrender/terrain.cpp | 24 +++++++++++---- apps/openmw/mwrender/terrain.hpp | 5 +++- apps/openmw/mwworld/world.cpp | 32 +++++++++++++++----- apps/openmw/mwworld/world.hpp | 3 +- components/esm/esm_reader.hpp | 8 +++++ components/esm/loadland.cpp | 1 + components/esm/loadland.hpp | 1 + components/esm_store/reclists.hpp | 50 ++++++++++++++++++++++++------- components/esm_store/store.cpp | 7 +++++ 12 files changed, 148 insertions(+), 47 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e192b1f88..4fd43fa3f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -228,18 +228,32 @@ void OMW::Engine::setCell (const std::string& cellName) // Set master file (esm) // - If the given name does not have an extension, ".esm" is added automatically -// - Currently OpenMW only supports one master at the same time. void OMW::Engine::addMaster (const std::string& master) { - assert (mMaster.empty()); - mMaster = master; + mMaster.push_back(master); + std::string &str = mMaster.back(); - // Append .esm if not already there - std::string::size_type sep = mMaster.find_last_of ("."); + // Append .esm if not already there + std::string::size_type sep = str.find_last_of ("."); if (sep == std::string::npos) { - mMaster += ".esm"; + str += ".esm"; + } +} + +// Add plugin file (esp) + +void OMW::Engine::addPlugin (const std::string& plugin) +{ + mPlugins.push_back(plugin); + std::string &str = mPlugins.back(); + + // Append .esp if not already there + std::string::size_type sep = str.find_last_of ("."); + if (sep == std::string::npos) + { + str += ".esp"; } } @@ -341,8 +355,8 @@ void OMW::Engine::go() MWGui::CursorReplace replacer; // Create the world - mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, - mResDir, mNewGame, mEncoding, mFallbackMap)); + mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, + mResDir, mNewGame, mEncoding, mFallbackMap) ); // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index cf1ef3b9c..1cbc63609 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -68,7 +68,8 @@ namespace OMW boost::filesystem::path mResDir; OEngine::Render::OgreRenderer *mOgre; std::string mCellName; - std::string mMaster; + std::vector mMaster; + std::vector mPlugins; int mFpsLevel; bool mDebug; bool mVerboseScripts; @@ -124,9 +125,12 @@ namespace OMW /// Set master file (esm) /// - If the given name does not have an extension, ".esm" is added automatically - /// - Currently OpenMW only supports one master at the same time. void addMaster(const std::string& master); + /// Same as "addMaster", but for plugin files (esp) + /// - If the given name does not have an extension, ".esp" is added automatically + void addPlugin(const std::string& plugin); + /// Enable fps counter void showFPS(int level); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 68aa12fb3..3a63361f9 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -239,19 +239,23 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat master.push_back("Morrowind"); } - if (master.size() > 1) - { - std::cout - << "Ignoring all but the first master file (multiple master files not yet supported)." - << std::endl; - } - engine.addMaster(master[0]); - StringsVector plugin = variables["plugin"].as(); - if (!plugin.empty()) - { - std::cout << "Ignoring plugin files (plugins not yet supported)." << std::endl; + int cnt = master.size() + plugin.size(); + if (cnt > 255) + { + std::cerr + << "Error: Trying to load more than 255 master and plugin files! This will break all combaibility and is not supported!" + << std::endl; + return false; } + for (std::vector::size_type i = 0; i < master.size(); i++) + { + engine.addMaster(master[i]); + } + for (std::vector::size_type i = 0; i < plugin.size(); i++) + { + engine.addPlugin(plugin[i]); + } // startup-settings engine.setCell(variables["start"].as()); diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 4dac750c7..9247d42cf 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -156,7 +156,7 @@ namespace MWRender std::map indexes; initTerrainTextures(&terrainData, cellX, cellY, x * numTextures, y * numTextures, - numTextures, indexes); + numTextures, indexes, land->plugin); if (mTerrainGroup.getTerrain(terrainX, terrainY) == NULL) { @@ -218,8 +218,14 @@ namespace MWRender void TerrainManager::initTerrainTextures(Terrain::ImportData* terrainData, int cellX, int cellY, int fromX, int fromY, int size, - std::map& indexes) + std::map& indexes, + size_t plugin) { + // FIXME: In a multiple esm configuration, we have multiple palettes. Since this code + // crosses cell boundaries, we no longer have a unique terrain palette. Instead, we need + // to adopt the following code for a dynamic palette. And this is evil - the current design + // does not work well for this task... + assert(terrainData != NULL && "Must have valid terrain data"); assert(fromX >= 0 && fromY >= 0 && "Can't get a terrain texture on terrain outside the current cell"); @@ -232,12 +238,16 @@ namespace MWRender // //If we don't sort the ltex indexes, the splatting order may differ between //cells which may lead to inconsistent results when shading between cells + int num = MWBase::Environment::get().getWorld()->getStore().landTexts.getSizePlugin(plugin); std::set ltexIndexes; for ( int y = fromY - 1; y < fromY + size + 1; y++ ) { for ( int x = fromX - 1; x < fromX + size + 1; x++ ) { - ltexIndexes.insert(getLtexIndexAt(cellX, cellY, x, y)); + int idx = getLtexIndexAt(cellX, cellY, x, y); + if (idx > num) + idx = 0; + ltexIndexes.insert(idx); } } @@ -249,7 +259,7 @@ namespace MWRender iter != ltexIndexes.end(); ++iter ) { - const uint16_t ltexIndex = *iter; + uint16_t ltexIndex = *iter; //this is the base texture, so we can ignore this at present if ( ltexIndex == baseTexture ) { @@ -262,8 +272,10 @@ namespace MWRender { //NB: All vtex ids are +1 compared to the ltex ids - assert( (int)MWBase::Environment::get().getWorld()->getStore().landTexts.getSize() >= (int)ltexIndex - 1 && + /* + assert( (int)mEnvironment.mWorld->getStore().landTexts.getSizePlugin(plugin) >= (int)ltexIndex - 1 && "LAND.VTEX must be within the bounds of the LTEX array"); + */ std::string texture; if ( ltexIndex == 0 ) @@ -272,7 +284,7 @@ namespace MWRender } else { - texture = MWBase::Environment::get().getWorld()->getStore().landTexts.search(ltexIndex-1)->texture; + texture = MWBase::Environment::get().getWorld()->getStore().landTexts.search(ltexIndex-1, plugin)->texture; //TODO this is needed due to MWs messed up texture handling texture = texture.substr(0, texture.rfind(".")) + ".dds"; } diff --git a/apps/openmw/mwrender/terrain.hpp b/apps/openmw/mwrender/terrain.hpp index 273ede084..5bda71eef 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -63,11 +63,14 @@ namespace MWRender{ * @param size the size (number of splats) to get * @param indexes a mapping of ltex index to the terrain texture layer that * can be used by initTerrainBlendMaps + * @param plugin the index of the plugin providing the texture list for this + * cell data; required because MW uses texture data on a per-plugin base */ void initTerrainTextures(Ogre::Terrain::ImportData* terrainData, int cellX, int cellY, int fromX, int fromY, int size, - std::map& indexes); + std::map& indexes, + size_t plugin = 0); /** * Creates the blend (splatting maps) for the given terrain from the ltex data. diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index e8d555689..fe3ddd5a8 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -176,7 +176,8 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, bool newGame, + const std::vector& master, + const std::vector& plugins, const boost::filesystem::path& resDir, bool newGame, const std::string& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mNextDynamicRecord (0), mCells (mStore, mEsm, *this), @@ -189,15 +190,32 @@ namespace MWWorld mWeatherManager = new MWWorld::WeatherManager(mRendering); - boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master)); + int idx = 0; + for (std::vector::size_type i = 0; i < master.size(); i++, idx++) + { + boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i])); + + std::cout << "Loading ESM " << masterPath.string() << "\n"; - std::cout << "Loading ESM " << masterPath.string() << "\n"; + // This parses the ESM file and loads a sample cell + mEsm.setEncoding(encoding); + mEsm.open (masterPath.string()); + mEsm.setIndex(idx); + mStore.load (mEsm); + } - // This parses the ESM file and loads a sample cell - mEsm.setEncoding(encoding); - mEsm.open (masterPath.string()); - mStore.load (mEsm); + for (std::vector::size_type i = 0; i < plugins.size(); i++, idx++) + { + boost::filesystem::path pluginPath (fileCollections.getCollection (".esp").getPath (plugins[i])); + + std::cout << "Loading ESP " << pluginPath.string() << "\n"; + // This parses the ESP file and loads a sample cell + mEsm.setEncoding(encoding); + mEsm.open (pluginPath.string()); + mEsm.setIndex(idx); + mStore.load (mEsm); + } MWRender::Player* play = &(mRendering->getPlayer()); mPlayer = new MWWorld::Player (play, mStore.npcs.find ("player"), *this); mPhysics->addActor (mPlayer->getPlayer().getRefData().getHandle(), "", Ogre::Vector3 (0, 0, 0)); diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index e8391773b..9e36765ff 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -117,7 +117,8 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, bool newGame, + const std::vector& master, + const std::vector& plugins, const boost::filesystem::path& resDir, bool newGame, const std::string& encoding, std::map fallbackMap); ~World(); diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index 340482891..4d61c3575 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -193,6 +193,14 @@ public: void openRaw(const std::string &file); + // This is a quick hack for multiple esm/esp files. Each plugin introduces its own + // terrain palette, but ESMReader does not pass a reference to the correct plugin + // to the individual load() methods. This hack allows to pass this reference + // indirectly to the load() method. + int idx; + void setIndex(const int index) {idx = index;} + const int getIndex() {return idx;} + /************************************************************************* * * Medium-level reading shortcuts diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 96afdf831..822952c91 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -23,6 +23,7 @@ Land::~Land() void Land::load(ESMReader &esm) { mEsm = &esm; + plugin = mEsm->getIndex(); // Get the grid location esm.getSubNameIs("INTV"); diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index ebc314a28..d03012d38 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -17,6 +17,7 @@ struct Land int flags; // Only first four bits seem to be used, don't know what // they mean. int X, Y; // Map coordinates. + int plugin; // Plugin index, used to reference the correct material palette. // File context. This allows the ESM reader to be 'reset' to this // location later when we are ready to load the full data set. diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index 48bf050cd..dd66d718a 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -26,6 +26,7 @@ namespace ESMS virtual void load(ESMReader &esm, const std::string &id) = 0; virtual int getSize() = 0; + virtual void remove(const std::string &id) {}; virtual void listIdentifier (std::vector& identifier) const = 0; static std::string toLower (const std::string& name) @@ -57,6 +58,14 @@ namespace ESMS list[id2].load(esm); } + // Delete the given object ID + void remove(const std::string &id) + { + std::string id2 = toLower (id); + + list.erase(id2); + } + // Find the given object ID, or return NULL if not found. const X* search(const std::string &id) const { @@ -268,38 +277,57 @@ namespace ESMS { virtual ~LTexList() {} - // TODO: For multiple ESM/ESP files we need one list per file. - std::vector ltex; + // For multiple ESM/ESP files we need one list per file. + typedef std::vector LandTextureList; + std::vector ltex; LTexList() { + ltex.push_back(LandTextureList()); + LandTextureList <exl = ltex[0]; // More than enough to hold Morrowind.esm. - ltex.reserve(128); + ltexl.reserve(128); } - const LandTexture* search(size_t index) const + const LandTexture* search(size_t index, size_t plugin) const { - assert(index < ltex.size()); - return <ex.at(index); + assert(plugin < ltex.size()); + const LandTextureList <exl = ltex[plugin]; + + assert(index < ltexl.size()); + return <exl.at(index); } int getSize() { return ltex.size(); } int getSize() const { return ltex.size(); } - virtual void listIdentifier (std::vector& identifier) const {} + int getSizePlugin(size_t plugin) { assert(plugin < ltex.size()); return ltex[plugin].size(); } + int getSizePlugin(size_t plugin) const { assert(plugin < ltex.size()); return ltex[plugin].size(); } - void load(ESMReader &esm, const std::string &id) + virtual void listIdentifier (std::vector& identifier) const {} + + void load(ESMReader &esm, const std::string &id, size_t plugin) { LandTexture lt; lt.load(esm); lt.id = id; // Make sure we have room for the structure - if(lt.index + 1 > (int)ltex.size()) - ltex.resize(lt.index+1); + if (plugin >= ltex.size()) { + ltex.resize(plugin+1); + } + LandTextureList <exl = ltex[plugin]; + if(lt.index + 1 > (int)ltexl.size()) + ltexl.resize(lt.index+1); // Store it - ltex[lt.index] = lt; + ltexl[lt.index] = lt; + } + + void load(ESMReader &esm, const std::string &id) + { + size_t plugin = esm.getIndex(); + load(esm, id, plugin); } }; diff --git a/components/esm_store/store.cpp b/components/esm_store/store.cpp index c676601e5..b6972355c 100644 --- a/components/esm_store/store.cpp +++ b/components/esm_store/store.cpp @@ -67,6 +67,13 @@ void ESMStore::load(ESMReader &esm) { // Load it std::string id = esm.getHNOString("NAME"); + // ... unless it got deleted! + if (esm.isNextSub("DELE")) { + esm.skipRecord(); + all.erase(id); + it->second->remove(id); + continue; + } it->second->load(esm, id); if (n.val==ESM::REC_DIAL) From 395a7600fd061c73a24007d902c3148a31bb5038 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 10 Jul 2012 23:13:03 -0700 Subject: [PATCH 02/92] Initialize identify transform when declaring the identity object --- components/nif/nif_types.hpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/components/nif/nif_types.hpp b/components/nif/nif_types.hpp index 705ed5994..f364cd2d4 100644 --- a/components/nif/nif_types.hpp +++ b/components/nif/nif_types.hpp @@ -41,17 +41,9 @@ struct Transformation static const Transformation& getIdentity() { - static Transformation identity; - static bool iset = false; - if (!iset) - { - identity.scale = 1.0f; - identity.rotation[0][0] = 1.0f; - identity.rotation[1][1] = 1.0f; - identity.rotation[2][2] = 1.0f; - iset = true; - } - + static const Transformation identity = { + Ogre::Vector3::ZERO, Ogre::Matrix3::IDENTITY, 1.0f, Ogre::Vector3::ZERO + }; return identity; } }; From 8e324c90dcecf5c5655f89aaa37e693587bd4950 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Jul 2012 06:37:17 -0700 Subject: [PATCH 03/92] Constify some RecordPtrT methods --- components/nif/record_ptr.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/components/nif/record_ptr.hpp b/components/nif/record_ptr.hpp index 755094147..7e6a43f53 100644 --- a/components/nif/record_ptr.hpp +++ b/components/nif/record_ptr.hpp @@ -71,18 +71,21 @@ public: } /// Look up the actual object from the index - X* getPtr() + X* getPtr() const { assert(ptr != NULL); return ptr; } - X& get() { return *getPtr(); } + X& get() const + { return *getPtr(); } /// Syntactic sugar - X* operator->() { return getPtr(); } + X* operator->() const + { return getPtr(); } /// Pointers are allowed to be empty - bool empty() { return ptr == NULL; } + bool empty() const + { return ptr == NULL; } }; /** A list of references to other records. These are read as a list, From 7e8c146de629b387d71a9eb5406f9e43a4640c31 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Jul 2012 06:39:03 -0700 Subject: [PATCH 04/92] Constify some RecordListT methods --- components/nif/record_ptr.hpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/components/nif/record_ptr.hpp b/components/nif/record_ptr.hpp index 7e6a43f53..8f8fc244a 100644 --- a/components/nif/record_ptr.hpp +++ b/components/nif/record_ptr.hpp @@ -114,17 +114,13 @@ public: list[i].post(nif); } - X& operator[](size_t index) - { - return list.at(index).get(); - } + X& operator[](size_t index) const + { return list.at(index).get(); } - bool has(size_t index) - { - return !list.at(index).empty(); - } + bool has(size_t index) const + { return !list.at(index).empty(); } - size_t length() + size_t length() const { return list.size(); } }; From 645b507ba06a34be6aaa9a75eb1a6b2cc409da48 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Jul 2012 05:37:56 -0700 Subject: [PATCH 05/92] Return a reference to the RecordPtr from operator[] for consistency RecordListT is supposed to be a list of RecordPtrT objects. --- components/nif/nif_file.cpp | 4 ++-- components/nif/node.hpp | 4 ++-- components/nif/record_ptr.hpp | 7 ++----- components/nifbullet/bullet_nif_loader.cpp | 12 ++++++------ components/nifogre/ogre_nif_loader.cpp | 18 ++++++++---------- 5 files changed, 20 insertions(+), 25 deletions(-) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 36badbf0d..231349302 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -205,8 +205,8 @@ void NiSkinInstance::post(NIFFile *nif) for(size_t i=0; ifail("Oops: Missing bone! Don't know how to handle this."); - bones[i].makeBone(i, data->bones[i]); + bones[i]->makeBone(i, data->bones[i]); } } diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 64ef1e3e9..e7ba03276 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -151,8 +151,8 @@ struct NiNode : Node for(size_t i = 0;i < children.length();i++) { // Why would a unique list of children contain empty refs? - if(children.has(i)) - children[i].parent = this; + if(!children[i].empty()) + children[i]->parent = this; } } }; diff --git a/components/nif/record_ptr.hpp b/components/nif/record_ptr.hpp index 8f8fc244a..ef5bb1dee 100644 --- a/components/nif/record_ptr.hpp +++ b/components/nif/record_ptr.hpp @@ -114,11 +114,8 @@ public: list[i].post(nif); } - X& operator[](size_t index) const - { return list.at(index).get(); } - - bool has(size_t index) const - { return !list.at(index).empty(); } + const Ptr& operator[](size_t index) const + { return list.at(index); } size_t length() const { return list.size(); } diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 4105c4c79..bfcaf36e5 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -138,9 +138,9 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node* node) int n = list.length(); for (int i=0; itrafo,hasCollisionNode,isCollisionNode,raycastingOnly); + handleNode(list[i].getPtr(), flags,&node->trafo,hasCollisionNode,isCollisionNode,raycastingOnly); } } } @@ -239,8 +239,8 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, int n = list.length(); for (int i=0; itrafo, hasCollisionNode,true,raycastingOnly); + if (!list[i].empty()) + handleNode(list[i].getPtr(), flags,&node->trafo, hasCollisionNode,true,raycastingOnly); } } } diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index aca1966b9..643d7acf8 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -649,10 +649,9 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou for (int i=0; irecType == RC_NiTexturingProperty) t = static_cast(pr); else if (pr->recType == RC_NiMaterialProperty) @@ -803,13 +802,13 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou { if(mSkel.isNull()) { - std::cout << "No skeleton for :" << shape->skin->bones[boneIndex].name << std::endl; + std::cout << "No skeleton for :" << shape->skin->bones[boneIndex]->name << std::endl; break; } //get the bone from bones array of skindata - if(!mSkel->hasBone(shape->skin->bones[boneIndex].name)) + if(!mSkel->hasBone(shape->skin->bones[boneIndex]->name)) std::cout << "We don't have this bone"; - bonePtr = mSkel->getBone(shape->skin->bones[boneIndex].name); + bonePtr = mSkel->getBone(shape->skin->bones[boneIndex]->name); // final_vector = old_vector + old_rotation*new_vector*old_scale @@ -817,7 +816,7 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou Nif::NiSkinData::BoneInfoCopy boneinfocopy; boneinfocopy.trafo.rotation = it->trafo.rotation; boneinfocopy.trafo.trans = it->trafo.trans; - boneinfocopy.bonename = shape->skin->bones[boneIndex].name; + boneinfocopy.bonename = shape->skin->bones[boneIndex]->name; boneinfocopy.bonehandle = bonePtr->getHandle(); copy.boneinfo.push_back(boneinfocopy); for (unsigned int i=0; iweights.size(); i++) @@ -1138,9 +1137,8 @@ void NIFLoader::handleNode(Nif::Node *node, int flags, int n = list.length(); for (int i = 0; itrafo, bounds, bone, boneSequence); + if (!list[i].empty()) + handleNode(list[i].getPtr(), flags, &node->trafo, bounds, bone, boneSequence); } } else if (node->recType == RC_NiTriShape && bNiTri) From b7b9f1133305ad05450b3c8e5ed83c523075ebb7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Jul 2012 06:47:38 -0700 Subject: [PATCH 06/92] Add generic classes to help deal with NIF keys --- components/nif/nif_file.hpp | 88 +++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index a21882c6d..9e0f6972b 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -98,6 +100,12 @@ public: throw std::runtime_error(err); } + void warn(const std::string &msg) + { + std::cerr<< "NIFFile Warning: "< +struct KeyT { + float mTime; + T mValue; + T mForwardValue; // Only for Quadratic interpolation + T mBackwardValue; // Only for Quadratic interpolation + float mTension; // Only for TBC interpolation + float mBias; // Only for TBC interpolation + float mContinuity; // Only for TBC interpolation +}; +typedef KeyT FloatKey; +typedef KeyT Vector3Key; +typedef KeyT QuaternionKey; + +template +struct KeyListT { + typedef std::vector< KeyT > VecType; + + static const int sLinearInterpolation = 1; + static const int sQuadraticInterpolation = 2; + static const int sTBCInterpolation = 3; + + int mInterpolationType; + VecType mKeys; + + void read(NIFFile *nif) + { + size_t count = nif->getInt(); + if(count == 0) return; + + mInterpolationType = nif->getInt(); + mKeys.resize(count); + if(mInterpolationType == sLinearInterpolation) + { + for(size_t i = 0;i < count;i++) + { + KeyT &key = mKeys[i]; + key.mTime = nif->getFloat(); + key.mValue = (nif->*getValue)(); + } + } + else if(mInterpolationType == sQuadraticInterpolation) + { + for(size_t i = 0;i < count;i++) + { + KeyT &key = mKeys[i]; + key.mTime = nif->getFloat(); + key.mValue = (nif->*getValue)(); + key.mForwardValue = (nif->*getValue)(); + key.mBackwardValue = (nif->*getValue)(); + } + } + else if(mInterpolationType == sTBCInterpolation) + { + for(size_t i = 0;i < count;i++) + { + KeyT &key = mKeys[i]; + key.mTime = nif->getFloat(); + key.mValue = (nif->*getValue)(); + key.mTension = nif->getFloat(); + key.mBias = nif->getFloat(); + key.mContinuity = nif->getFloat(); + } + } + else + nif->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); + } +}; +typedef KeyListT FloatKeyList; +typedef KeyListT Vector3KeyList; +typedef KeyListT QuaternionKeyList; + } // Namespace #endif From b292665de90d444d69ea9af0750cb117db233859 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Jul 2012 08:00:26 -0700 Subject: [PATCH 07/92] Use key lists to store some NIF data types --- components/nif/data.hpp | 47 +++++++++-------------------------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index ad670bc5e..552e53b68 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -202,61 +202,34 @@ public: class NiPosData : public Record { public: + Vector3KeyList mKeyList; + void read(NIFFile *nif) { - int count = nif->getInt(); - int type = nif->getInt(); - if(type != 1 && type != 2) - nif->fail("Cannot handle NiPosData type"); - - // TODO: Could make structs of these. Seems to be identical to - // translation in NiKeyframeData. - for(int i=0; igetFloat(); - nif->getVector3(); // This isn't really shared between type 1 - // and type 2, most likely - if(type == 2) - { - nif->getVector3(); - nif->getVector3(); - } - } + mKeyList.read(nif); } }; class NiUVData : public Record { public: + FloatKeyList mKeyList[4]; + void read(NIFFile *nif) { - // TODO: This is claimed to be a "float animation key", which is - // also used in FloatData and KeyframeData. We could probably - // reuse and refactor a lot of this if we actually use it at some - // point. - for(int i=0; i<2; i++) - { - int count = nif->getInt(); - if(count) - { - nif->getInt(); // always 2 - nif->skip(count * (sizeof(float) + 3*sizeof(float))); // Really one time float + one vector - } - } - // Always 0 - nif->getInt(); - nif->getInt(); + for(int i = 0;i < 4;i++) + mKeyList[i].read(nif); } }; class NiFloatData : public Record { public: + FloatKeyList mKeyList; + void read(NIFFile *nif) { - int count = nif->getInt(); - nif->getInt(); // always 2 - nif->skip(count * (sizeof(float) + 3*sizeof(float))); // Really one time float + one vector + mKeyList.read(nif); } }; From 86b37c6c11b59ff7a9c6bf7c214b12ef9c53eb66 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Jul 2012 11:21:52 -0700 Subject: [PATCH 08/92] Move the velocity out of the transformation object --- components/nif/nif_file.hpp | 1 - components/nif/nif_types.hpp | 3 +-- components/nif/node.hpp | 2 ++ components/nifbullet/bullet_nif_loader.cpp | 1 - components/nifogre/ogre_nif_loader.cpp | 1 - 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index 9e0f6972b..fa152f14d 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -179,7 +179,6 @@ public: t.pos = getVector3(); t.rotation = getMatrix3(); t.scale = getFloat(); - t.velocity = getVector3(); return t; } diff --git a/components/nif/nif_types.hpp b/components/nif/nif_types.hpp index f364cd2d4..a5fb61361 100644 --- a/components/nif/nif_types.hpp +++ b/components/nif/nif_types.hpp @@ -37,12 +37,11 @@ struct Transformation Ogre::Vector3 pos; Ogre::Matrix3 rotation; float scale; - Ogre::Vector3 velocity; static const Transformation& getIdentity() { static const Transformation identity = { - Ogre::Vector3::ZERO, Ogre::Matrix3::IDENTITY, 1.0f, Ogre::Vector3::ZERO + Ogre::Vector3::ZERO, Ogre::Matrix3::IDENTITY, 1.0f }; return identity; } diff --git a/components/nif/node.hpp b/components/nif/node.hpp index e7ba03276..293793009 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -43,6 +43,7 @@ public: // Node flags. Interpretation depends somewhat on the type of node. int flags; Transformation trafo; + Ogre::Vector3 velocity; // Unused? Might be a run-time game state PropertyList props; // Bounding box info @@ -57,6 +58,7 @@ public: flags = nif->getUShort(); trafo = nif->getTrafo(); + velocity = nif->getVector3(); props.read(nif); hasBounds = !!nif->getInt(); diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index bfcaf36e5..c3b34e039 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -204,7 +204,6 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, // For both position and rotation we have that: // final_vector = old_vector + old_rotation*new_vector*old_scale final.pos = trafo->pos + trafo->rotation*final.pos*trafo->scale; - final.velocity = trafo->velocity + trafo->rotation*final.velocity*trafo->scale; // Merge the rotations together final.rotation = trafo->rotation * final.rotation; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 643d7acf8..36c5d3b1b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1121,7 +1121,6 @@ void NIFLoader::handleNode(Nif::Node *node, int flags, // For both position and rotation we have that: // final_vector = old_vector + old_rotation*new_vector*old_scale final.pos = trafo->pos + trafo->rotation*final.pos*trafo->scale; - final.velocity = trafo->velocity + trafo->rotation*final.velocity*trafo->scale; // Merge the rotations together final.rotation = trafo->rotation * final.rotation; From 3f11b6b1ae961cc745a8624904f1f728b7aea246 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Jul 2012 12:01:11 -0700 Subject: [PATCH 09/92] Cleanup a couple unneeded misc component references --- components/nif/record.hpp | 2 +- components/nifogre/ogre_nif_loader.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 84f253eb8..5c4141fa9 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -24,7 +24,7 @@ #ifndef _NIF_RECORD_H_ #define _NIF_RECORD_H_ -#include +#include namespace Nif { diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 36c5d3b1b..014384dd4 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -40,7 +40,6 @@ typedef unsigned char ubyte; using namespace std; using namespace Nif; -using namespace Misc; using namespace NifOgre; NIFLoader& NIFLoader::getSingleton() From 9995dff943592d85b2d3b9e2bbeaa75a74807dfd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Jul 2012 14:33:50 -0700 Subject: [PATCH 10/92] Use a key list for NiColorData --- components/nif/data.hpp | 12 ++---------- components/nif/nif_file.hpp | 2 ++ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 552e53b68..b7e2f172f 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -275,19 +275,11 @@ public: class NiColorData : public Record { public: - struct ColorData - { - float time; - Ogre::Vector4 rgba; - }; + Vector4KeyList mKeyList; void read(NIFFile *nif) { - int count = nif->getInt(); - nif->getInt(); // always 1 - - // Skip the data - nif->skip(count * 5*sizeof(float)); + mKeyList.read(nif); } }; diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index fa152f14d..c33790742 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -223,6 +223,7 @@ struct KeyT { }; typedef KeyT FloatKey; typedef KeyT Vector3Key; +typedef KeyT Vector4Key; typedef KeyT QuaternionKey; template @@ -281,6 +282,7 @@ struct KeyListT { }; typedef KeyListT FloatKeyList; typedef KeyListT Vector3KeyList; +typedef KeyListT Vector4KeyList; typedef KeyListT QuaternionKeyList; } // Namespace From 386ac56bdab827ef604362787d232d8278ff1d7e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Jul 2012 20:12:18 -0700 Subject: [PATCH 11/92] Remove the NIF loader and code to manually transform the vertices This currently breaks just about everything. They should come back as it's all reimplemented, though. --- apps/openmw/engine.cpp | 7 +- apps/openmw/mwrender/animation.cpp | 660 +++------- apps/openmw/mwrender/animation.hpp | 53 +- apps/openmw/mwrender/creatureanimation.cpp | 56 +- apps/openmw/mwrender/npcanimation.cpp | 1294 +++++++++----------- apps/openmw/mwrender/npcanimation.hpp | 94 +- components/bsa/bsa_archive.cpp | 54 +- components/nif/data.hpp | 20 - components/nif/node.hpp | 36 - components/nifbullet/bullet_nif_loader.cpp | 2 +- components/nifogre/ogre_nif_loader.cpp | 1112 +---------------- components/nifogre/ogre_nif_loader.hpp | 98 +- libs/openengine/bullet/physic.cpp | 2 +- 13 files changed, 873 insertions(+), 2615 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 45b4ab514..fded32560 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -75,11 +75,8 @@ void OMW::Engine::executeLocalScripts() localScripts.setIgnore (MWWorld::Ptr()); } -void OMW::Engine::setAnimationVerbose(bool animverbose){ - if(animverbose){ - NifOgre::NIFLoader::getSingletonPtr()->setOutputAnimFiles(true); - NifOgre::NIFLoader::getSingletonPtr()->setVerbosePath(mCfgMgr.getLogPath().string()); - } +void OMW::Engine::setAnimationVerbose(bool animverbose) +{ } bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f0a6ab683..7e50706f9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -6,498 +6,236 @@ #include #include -namespace MWRender{ - std::map Animation::mUniqueIDs; +namespace MWRender { - Animation::Animation(OEngine::Render::OgreRenderer& _rend) - : insert(NULL) - , mRend(_rend) - , vecRotPos() - , time(0.0f) - , startTime(0.0f) - , stopTime(0.0f) - , animate(0) - , rindexI() - , tindexI() - , shapeNumber(0) - , shapeIndexI() - , shapes(NULL) - , transformations(NULL) - , textmappings(NULL) - , base(NULL) - { - } +std::map Animation::mUniqueIDs; - Animation::~Animation() - { - } - - std::string Animation::getUniqueID(std::string mesh){ - int counter; - std::string copy = mesh; - std::transform(copy.begin(), copy.end(), copy.begin(), ::tolower); - if(mUniqueIDs.find(copy) == mUniqueIDs.end()){ - counter = mUniqueIDs[copy] = 0; - } - else{ - mUniqueIDs[copy] = mUniqueIDs[copy] + 1; - counter = mUniqueIDs[copy]; - } - - std::stringstream out; - if(counter > 99 && counter < 1000) - out << "0"; - else if(counter > 9) - out << "00"; - else - out << "000"; - out << counter; - return out.str(); +Animation::Animation(OEngine::Render::OgreRenderer& _rend) + : insert(NULL) + , mRend(_rend) + , time(0.0f) + , startTime(0.0f) + , stopTime(0.0f) + , animate(0) + , rindexI() + , tindexI() + , shapeNumber(0) + , shapeIndexI() + , transformations(NULL) + , textmappings(NULL) + , base(NULL) +{ } - void Animation::startScript(std::string groupname, int mode, int loops){ - //If groupname is recognized set animate to true - //Set the start time and stop time - //How many times to loop - if(groupname == "all"){ - animate = loops; - time = startTime; - } - else if(textmappings){ - std::string startName = groupname + ": loop start"; - std::string stopName = groupname + ": loop stop"; +Animation::~Animation() +{ +} - bool first = false; - - if(loops > 1){ - startName = groupname + ": loop start"; - stopName = groupname + ": loop stop"; - - for(std::map::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++){ - - std::string current = iter->first.substr(0, startName.size()); - std::transform(current.begin(), current.end(), current.begin(), ::tolower); - std::string current2 = iter->first.substr(0, stopName.size()); - std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower); - - if(current == startName){ - startTime = iter->second; - animate = loops; - time = startTime; - first = true; - } - if(current2 == stopName){ - stopTime = iter->second; - if(first) - break; - } - } - } - if(!first){ - startName = groupname + ": start"; - stopName = groupname + ": stop"; - - for(std::map::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++){ - - std::string current = iter->first.substr(0, startName.size()); - std::transform(current.begin(), current.end(), current.begin(), ::tolower); - std::string current2 = iter->first.substr(0, stopName.size()); - std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower); - - if(current == startName){ - startTime = iter->second; - animate = loops; - time = startTime; - first = true; - } - if(current2 == stopName){ - stopTime = iter->second; - if(first) - break; - } - } - } - - } - - } - void Animation::stopScript(){ - animate = 0; +void Animation::startScript(std::string groupname, int mode, int loops) +{ + //If groupname is recognized set animate to true + //Set the start time and stop time + //How many times to loop + if(groupname == "all") + { + animate = loops; + time = startTime; } + else if(textmappings) + { + std::string startName = groupname + ": loop start"; + std::string stopName = groupname + ": loop stop"; - void Animation::handleShapes(std::vector* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){ - shapeNumber = 0; + bool first = false; - if (allshapes == NULL || creaturemodel == NULL || skel == NULL) + if(loops > 1) { - return; + startName = groupname + ": loop start"; + stopName = groupname + ": loop stop"; + + for(std::map::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++) + { + std::string current = iter->first.substr(0, startName.size()); + std::transform(current.begin(), current.end(), current.begin(), ::tolower); + std::string current2 = iter->first.substr(0, stopName.size()); + std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower); + + if(current == startName) + { + startTime = iter->second; + animate = loops; + time = startTime; + first = true; + } + if(current2 == stopName) + { + stopTime = iter->second; + if(first) + break; + } + } } - std::vector::iterator allshapesiter; - for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++) + if(!first) + { + startName = groupname + ": start"; + stopName = groupname + ": stop"; + for(std::map::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++) + { + std::string current = iter->first.substr(0, startName.size()); + std::transform(current.begin(), current.end(), current.begin(), ::tolower); + std::string current2 = iter->first.substr(0, stopName.size()); + std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower); + + if(current == startName) { - //std::map vecPosRot; - - Nif::NiTriShapeCopy& copy = *allshapesiter; - std::vector* allvertices = ©.vertices; - - - - //std::set vertices; - //std::set normals; - //std::vector boneinfovector = copy.boneinfo; - std::map >* verticesToChange = ©.vertsToWeights; - - //std::cout << "Name " << copy.sname << "\n"; - Ogre::HardwareVertexBufferSharedPtr vbuf = creaturemodel->getMesh()->getSubMesh(copy.sname)->vertexData->vertexBufferBinding->getBuffer(0); - Ogre::Real* pReal = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL)); - - - std::vector initialVertices = copy.morph.getInitialVertices(); - //Each shape has multiple indices - if(initialVertices.size() ) - { - - if(copy.vertices.size() == initialVertices.size()) - { - //Create if it doesn't already exist - if(shapeIndexI.size() == static_cast (shapeNumber)) - { - std::vector vec; - shapeIndexI.push_back(vec); - } - if(time >= copy.morph.getStartTime() && time <= copy.morph.getStopTime()){ - float x; - for (unsigned int i = 0; i < copy.morph.getAdditionalVertices().size(); i++){ - int j = 0; - if(shapeIndexI[shapeNumber].size() <= i) - shapeIndexI[shapeNumber].push_back(0); - - - if(timeIndex(time,copy.morph.getRelevantTimes()[i],(shapeIndexI[shapeNumber])[i], j, x)){ - int indexI = (shapeIndexI[shapeNumber])[i]; - std::vector relevantData = (copy.morph.getRelevantData()[i]); - float v1 = relevantData[indexI].x; - float v2 = relevantData[j].x; - float t = v1 + (v2 - v1) * x; - if ( t < 0 ) t = 0; - if ( t > 1 ) t = 1; - if( t != 0 && initialVertices.size() == copy.morph.getAdditionalVertices()[i].size()) - { - for (unsigned int v = 0; v < initialVertices.size(); v++){ - initialVertices[v] += ((copy.morph.getAdditionalVertices()[i])[v]) * t; - } - } - - } - - - - } - - allvertices = &initialVertices; - } - shapeNumber++; - } - } - - - if(verticesToChange->size() > 0){ - - for(std::map >::iterator iter = verticesToChange->begin(); - iter != verticesToChange->end(); iter++) - { - std::vector inds = iter->second; - int verIndex = iter->first; - Ogre::Vector3 currentVertex = (*allvertices)[verIndex]; - Nif::NiSkinData::BoneInfoCopy* boneinfocopy = &(allshapesiter->boneinfo[inds[0].boneinfocopyindex]); - Ogre::Bone *bonePtr = 0; - - - - Ogre::Vector3 vecPos; - Ogre::Quaternion vecRot; - std::map::iterator result = vecRotPos.find(boneinfocopy); - - if(result == vecRotPos.end()){ - bonePtr = skel->getBone(boneinfocopy->bonename); - - vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans; - vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation; - - - PosAndRot both; - both.vecPos = vecPos; - both.vecRot = vecRot; - vecRotPos[boneinfocopy] = both; - - } - else{ - PosAndRot both = result->second; - vecPos = both.vecPos; - vecRot = both.vecRot; - } - - Ogre::Vector3 absVertPos = (vecPos + vecRot * currentVertex) * inds[0].weight; - - - - for(std::size_t i = 1; i < inds.size(); i++){ - boneinfocopy = &(allshapesiter->boneinfo[inds[i].boneinfocopyindex]); - result = vecRotPos.find(boneinfocopy); - - - if(result == vecRotPos.end()){ - bonePtr = skel->getBone(boneinfocopy->bonename); - vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans; - vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation; - - PosAndRot both; - both.vecPos = vecPos; - both.vecRot = vecRot; - vecRotPos[boneinfocopy] = both; - - } - else{ - PosAndRot both = result->second; - vecPos = both.vecPos; - vecRot = both.vecRot; - } - - - absVertPos += (vecPos + vecRot * currentVertex) * inds[i].weight; - - - } - Ogre::Real* addr = (pReal + 3 * verIndex); - *addr = absVertPos.x; - *(addr+1) = absVertPos.y; - *(addr+2) = absVertPos.z; - + startTime = iter->second; + animate = loops; + time = startTime; + first = true; } - - - - - } - else - { - //Ogre::Bone *bonePtr = creaturemodel->getSkeleton()->getBone(copy.bonename); - Ogre::Quaternion shaperot = copy.trafo.rotation; - Ogre::Vector3 shapetrans = copy.trafo.trans; - float shapescale = copy.trafo.scale; - std::vector boneSequence = copy.boneSequence; - - Ogre::Vector3 transmult; - Ogre::Quaternion rotmult; - float scale; - if(boneSequence.size() > 0){ - std::vector::iterator boneSequenceIter = boneSequence.begin(); - if(skel->hasBone(*boneSequenceIter)){ - Ogre::Bone *bonePtr = skel->getBone(*boneSequenceIter); - - - - - transmult = bonePtr->getPosition(); - rotmult = bonePtr->getOrientation(); - scale = bonePtr->getScale().x; - boneSequenceIter++; - - for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++) - { - if(skel->hasBone(*boneSequenceIter)){ - Ogre::Bone *bonePtr = skel->getBone(*boneSequenceIter); - // Computes C = B + AxC*scale - transmult = transmult + rotmult * bonePtr->getPosition(); - rotmult = rotmult * bonePtr->getOrientation(); - scale = scale * bonePtr->getScale().x; - } - //std::cout << "Bone:" << *boneSequenceIter << " "; - } - transmult = transmult + rotmult * shapetrans; - rotmult = rotmult * shaperot; - scale = shapescale * scale; - - //std::cout << "Position: " << transmult << "Rotation: " << rotmult << "\n"; - } - } - else - { - transmult = shapetrans; - rotmult = shaperot; - scale = shapescale; - } - - - - - // Computes C = B + AxC*scale - // final_vector = old_vector + old_rotation*new_vector*old_scale/ - - for(unsigned int i = 0; i < allvertices->size(); i++){ - Ogre::Vector3 current = transmult + rotmult * (*allvertices)[i]; - Ogre::Real* addr = pReal + i * 3; - *addr = current.x; - *(addr+1) = current.y; - *(addr + 2) = current.z; - - }/* - for(int i = 0; i < allnormals.size(); i++){ - Ogre::Vector3 current =rotmult * allnormals[i]; - Ogre::Real* addr = pRealNormal + i * 3; - *addr = current.x; - *(addr+1) = current.y; - *(addr + 2) = current.z; - - }*/ - - } - vbuf->unlock(); - - } + if(current2 == stopName) + { + stopTime = iter->second; + if(first) + break; + } + } + } } - bool Animation::timeIndex( float time, const std::vector & times, int & i, int & j, float & x ){ - int count; - if ( (count = times.size()) > 0 ) - { - if ( time <= times[0] ) - { - i = j = 0; - x = 0.0; - return true; - } - if ( time >= times[count - 1] ) - { - i = j = count - 1; - x = 0.0; - return true; - } - - if ( i < 0 || i >= count ) - i = 0; - - float tI = times[i]; - if ( time > tI ) - { - j = i + 1; - float tJ; - while ( time >= ( tJ = times[j]) ) - { - i = j++; - tI = tJ; - } - x = ( time - tI ) / ( tJ - tI ); - return true; - } - else if ( time < tI ) - { - j = i - 1; - float tJ; - while ( time <= ( tJ = times[j] ) ) - { - i = j--; - tI = tJ; - } - x = ( time - tI ) / ( tJ - tI ); - return true; - } - else - { - j = i; - x = 0.0; - return true; - } - } - else - return false; } - void Animation::handleAnimationTransforms(){ + +void Animation::stopScript() +{ + animate = 0; +} +bool Animation::timeIndex(float time, const std::vector ×, int &i, int &j, float &x) +{ + size_t count; + if((count=times.size()) == 0) + return false; + + if(time <= times[0]) + { + i = j = 0; + x = 0.0; + return true; + } + if(time >= times[count-1]) + { + i = j = count - 1; + x = 0.0; + return true; + } + + if(i < 0 || (size_t)i >= count) + i = 0; + + float tI = times[i]; + if(time > tI) + { + j = i + 1; + float tJ; + while(time >= (tJ=times[j])) + { + i = j++; + tI = tJ; + } + x = (time-tI) / (tJ-tI); + return true; + } + + if(time < tI) + { + j = i - 1; + float tJ; + while(time <= (tJ=times[j])) + { + i = j--; + tI = tJ; + } + x = (time-tI) / (tJ-tI); + return true; + } + + j = i; + x = 0.0; + return true; +} + +void Animation::handleAnimationTransforms() +{ Ogre::SkeletonInstance* skel = base->getSkeleton(); - Ogre::Bone* b = skel->getRootBone(); - b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3)); //This is a trick - - skel->_updateTransforms(); - //skel->_notifyManualBonesDirty(); - - base->getAllAnimationStates()->_notifyDirty(); - //base->_updateAnimation(); - //base->_notifyMoved(); - + b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3)); //This is a trick + skel->_updateTransforms(); + //skel->_notifyManualBonesDirty(); + base->getAllAnimationStates()->_notifyDirty(); + //base->_updateAnimation(); + //base->_notifyMoved(); std::vector::iterator iter; int slot = 0; - if(transformations){ - for(iter = transformations->begin(); iter != transformations->end(); iter++){ - if(time < iter->getStartTime() || time < startTime || time > iter->getStopTime()) - { + if(transformations) + { + for(iter = transformations->begin(); iter != transformations->end(); iter++) + { + if(time < iter->getStartTime() || time < startTime || time > iter->getStopTime()) + { + slot++; + continue; + } + + float x; + float x2; + + const std::vector &quats = iter->getQuat(); + const std::vector &ttime = iter->gettTime(); + const std::vector &rtime = iter->getrTime(); + const std::vector &translist1 = iter->getTranslist1(); + + int rindexJ = rindexI[slot]; + timeIndex(time, rtime, rindexI[slot], rindexJ, x2); + + int tindexJ = tindexI[slot]; + timeIndex(time, ttime, tindexI[slot], tindexJ, x); + + Ogre::Vector3 t; + Ogre::Quaternion r; + + bool bTrans = translist1.size() > 0; + bool bQuats = quats.size() > 0; + if(skel->hasBone(iter->getBonename())) + { + Ogre::Bone* bone = skel->getBone(iter->getBonename()); + if(bTrans) + { + Ogre::Vector3 v1 = translist1[tindexI[slot]]; + Ogre::Vector3 v2 = translist1[tindexJ]; + t = (v1 + (v2 - v1) * x); + bone->setPosition(t); + } + if(bQuats) + { + r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true); + bone->setOrientation(r); + } + } + slot++; - continue; - } - - float x; - float x2; - - const std::vector & quats = iter->getQuat(); - - const std::vector & ttime = iter->gettTime(); - - - const std::vector & rtime = iter->getrTime(); - int rindexJ = rindexI[slot]; - - timeIndex(time, rtime, rindexI[slot], rindexJ, x2); - int tindexJ = tindexI[slot]; - - - const std::vector & translist1 = iter->getTranslist1(); - - timeIndex(time, ttime, tindexI[slot], tindexJ, x); - - Ogre::Vector3 t; - Ogre::Quaternion r; - - bool bTrans = translist1.size() > 0; - - - bool bQuats = quats.size() > 0; - - if(skel->hasBone(iter->getBonename())){ - Ogre::Bone* bone = skel->getBone(iter->getBonename()); - if(bTrans){ - Ogre::Vector3 v1 = translist1[tindexI[slot]]; - Ogre::Vector3 v2 = translist1[tindexJ]; - t = (v1 + (v2 - v1) * x); - bone->setPosition(t); - - } - if(bQuats){ - r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true); - bone->setOrientation(r); - } - - - - - - } - - - slot++; - } - skel->_updateTransforms(); + } + skel->_updateTransforms(); base->getAllAnimationStates()->_notifyDirty(); -} + } } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 4ab60cff4..9d5404305 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -12,60 +12,47 @@ -namespace MWRender{ +namespace MWRender { -struct PosAndRot{ +struct PosAndRot { Ogre::Quaternion vecRot; Ogre::Vector3 vecPos; }; -class Animation{ - - protected: +class Animation { +protected: Ogre::SceneNode* insert; OEngine::Render::OgreRenderer &mRend; - std::map vecRotPos; static std::map mUniqueIDs; - - - - float time; - float startTime; - float stopTime; - int animate; - //Represents a rotation index for each bone - std::vectorrindexI; + float startTime; + float stopTime; + int animate; + //Represents a rotation index for each bone + std::vectorrindexI; //Represents a translation index for each bone - std::vectortindexI; - - //Only shapes with morphing data will use a shape number - int shapeNumber; - std::vector > shapeIndexI; - - //Ogre::SkeletonInstance* skel; - std::vector* shapes; //All the NiTriShapeData for a creature - + std::vectortindexI; + //Only shapes with morphing data will use a shape number + int shapeNumber; + std::vector > shapeIndexI; std::vector* transformations; std::map* textmappings; Ogre::Entity* base; - void handleShapes(std::vector* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel); void handleAnimationTransforms(); bool timeIndex( float time, const std::vector & times, int & i, int & j, float & x ); - std::string getUniqueID(std::string mesh); - public: - Animation(OEngine::Render::OgreRenderer& _rend); - virtual void runAnimation(float timepassed) = 0; - void startScript(std::string groupname, int mode, int loops); - void stopScript(); +public: + Animation(OEngine::Render::OgreRenderer& _rend); + virtual void runAnimation(float timepassed) = 0; + void startScript(std::string groupname, int mode, int loops); + void stopScript(); - virtual ~Animation(); - + virtual ~Animation(); }; + } #endif diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index e1fa7868c..6bdd58ac3 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -12,20 +12,22 @@ using namespace Ogre; using namespace NifOgre; namespace MWRender{ -CreatureAnimation::~CreatureAnimation(){ - +CreatureAnimation::~CreatureAnimation() +{ } -CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend): Animation(_rend){ + +CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend): Animation(_rend) +{ insert = ptr.getRefData().getBaseNode(); - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = ptr.get(); assert (ref->base != NULL); - if(!ref->base->model.empty()){ - const std::string &mesh = "meshes\\" + ref->base->model; - std::string meshNumbered = mesh + getUniqueID(mesh) + ">|"; - NifOgre::NIFLoader::load(meshNumbered); - base = mRend.getScene()->createEntity(meshNumbered); + if(!ref->base->model.empty()) + { + std::string mesh = "meshes\\" + ref->base->model; + + NifOgre::NIFLoader::load(mesh); + base = mRend.getScene()->createEntity(mesh); base->setVisibilityFlags(RV_Actors); bool transparent = false; @@ -48,33 +50,22 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O } base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - std::string meshZero = mesh + "0000>|"; - - if((transformations = (NIFLoader::getSingletonPtr())->getAnim(meshZero))){ - - for(std::size_t init = 0; init < transformations->size(); init++){ - rindexI.push_back(0); - tindexI.push_back(0); - } - stopTime = transformations->begin()->getStopTime(); - startTime = transformations->begin()->getStartTime(); - shapes = (NIFLoader::getSingletonPtr())->getShapes(meshZero); - } - textmappings = NIFLoader::getSingletonPtr()->getTextIndices(meshZero); insert->attachObject(base); } } -void CreatureAnimation::runAnimation(float timepassed){ - vecRotPos.clear(); - if(animate > 0){ - //Add the amount of time passed to time +void CreatureAnimation::runAnimation(float timepassed) +{ + if(animate > 0) + { + //Add the amount of time passed to time - //Handle the animation transforms dependent on time + //Handle the animation transforms dependent on time - //Handle the shapes dependent on animation transforms + //Handle the shapes dependent on animation transforms time += timepassed; - if(time >= stopTime){ + if(time >= stopTime) + { animate--; //std::cout << "Stopping the animation\n"; if(animate == 0) @@ -84,8 +75,7 @@ void CreatureAnimation::runAnimation(float timepassed){ } handleAnimationTransforms(); - handleShapes(shapes, base, base->getSkeleton()); + } +} - } -} } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index fa88b7277..fa33d18ff 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -13,13 +13,16 @@ using namespace Ogre; using namespace NifOgre; -namespace MWRender{ -NpcAnimation::~NpcAnimation(){ +namespace MWRender{ + +NpcAnimation::~NpcAnimation() +{ } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_rend), mStateID(-1), inv(_inv), timeToChange(0), +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv) + : Animation(_rend), mStateID(-1), inv(_inv), timeToChange(0), robe(inv.end()), helmet(inv.end()), shirt(inv.end()), cuirass(inv.end()), greaves(inv.end()), leftpauldron(inv.end()), rightpauldron(inv.end()), @@ -27,98 +30,59 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere leftglove(inv.end()), rightglove(inv.end()), skirtiter(inv.end()), pants(inv.end()), lclavicle(0), - rclavicle(0), - rupperArm(0), - lupperArm(0), - rUpperLeg(0), - lUpperLeg(0), - lForearm(0), - rForearm(0), - lWrist(0), - rWrist(0), - rKnee(0), - lKnee(0), - neck(0), - rAnkle(0), - lAnkle(0), - groin(0), - lfoot(0), - rfoot(0) + rclavicle(0), + rupperArm(0), + lupperArm(0), + rUpperLeg(0), + lUpperLeg(0), + lForearm(0), + rForearm(0), + lWrist(0), + rWrist(0), + rKnee(0), + lKnee(0), + neck(0), + rAnkle(0), + lAnkle(0), + groin(0), + lfoot(0), + rfoot(0) +{ + MWWorld::LiveCellRef *ref = ptr.get(); + + for (int init = 0; init < 27; init++) { - MWWorld::LiveCellRef *ref = - ptr.get(); - Ogre::Entity* blank = 0; - std::vector* blankshape = 0; - zero = std::make_pair(blank, blankshape); - chest = std::make_pair(blank, blankshape); - tail = std::make_pair(blank, blankshape); - lFreeFoot = std::make_pair(blank, blankshape); - rFreeFoot = std::make_pair(blank, blankshape); - rhand = std::make_pair(blank, blankshape); - lhand = std::make_pair(blank, blankshape); - skirt = std::make_pair(blank, blankshape); - for (int init = 0; init < 27; init++){ - partslots[init] = -1; //each slot is empty - partpriorities[init] = 0; - } + partslots[init] = -1; //each slot is empty + partpriorities[init] = 0; + } + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.races.find(ref->base->race); - //Part selection on last character of the file string - // " Tri Chest - // * Tri Tail - // : Tri Left Foot - // < Tri Right Foot - // > Tri Left Hand - // ? Tri Right Hand - // | Normal + std::string hairID = ref->base->hair; + std::string headID = ref->base->head; + headModel = "meshes\\" + store.bodyParts.find(headID)->model; + hairModel = "meshes\\" + store.bodyParts.find(hairID)->model; + npcName = ref->base->name; - //Mirroring Parts on second to last character - //suffix == '*' - // vector = Ogre::Vector3(-1,1,1); - // suffix == '?' - // vector = Ogre::Vector3(1,-1,1); - // suffix == '<' - // vector = Ogre::Vector3(1,1,-1); + isFemale = !!(ref->base->flags&ESM::NPC::Female); + isBeast = !!(race->data.flags&ESM::Race::Beast); + bodyRaceID = "b_n_"+race->name; + std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower); - std::string hairID = ref->base->hair; - std::string headID = ref->base->head; - headModel = "meshes\\" + - MWBase::Environment::get().getWorld()->getStore().bodyParts.find(headID)->model; + /*std::cout << "Race: " << ref->base->race ; + if(female) + std::cout << " Sex: Female" << " Height: " << race->data.height.female << "\n"; + else + std::cout << " Sex: Male" << " Height: " << race->data.height.male << "\n"; + */ - hairModel = "meshes\\" + - MWBase::Environment::get().getWorld()->getStore().bodyParts.find(hairID)->model; - npcName = ref->base->name; - - //ESMStore::Races r = - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().races.find(ref->base->race); - - - bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4); - char secondtolast = bodyRaceID.at(bodyRaceID.length() - 2); - isFemale = tolower(secondtolast) == 'f'; - std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower); - isBeast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_"; - - /*std::cout << "Race: " << ref->base->race ; - if(female){ - std::cout << " Sex: Female" << " Height: " << race->data.height.female << "\n"; - } - else{ - std::cout << " Sex: Male" << " Height: " << race->data.height.male << "\n"; - }*/ - - - - std::string smodel = "meshes\\base_anim.nif"; - if(isBeast) - smodel = "meshes\\base_animkna.nif"; - - insert = ptr.getRefData().getBaseNode(); - assert(insert); - - NifOgre::NIFLoader::load(smodel); + insert = ptr.getRefData().getBaseNode(); + assert(insert); + std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); + NifOgre::NIFLoader::load(smodel); base = mRend.getScene()->createEntity(smodel); base->setVisibilityFlags(RV_Actors); @@ -134,372 +98,290 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere while (passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if (pass->getDepthWriteEnabled() == false) transparent = true; } } } base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - - base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones //stay in the same place when we skipanim, or open a gui window - - - if((transformations = (NIFLoader::getSingletonPtr())->getAnim(smodel))){ - - for(unsigned int init = 0; init < transformations->size(); init++){ - rindexI.push_back(0); - tindexI.push_back(0); - } - - stopTime = transformations->begin()->getStopTime(); - startTime = transformations->begin()->getStartTime(); - } - textmappings = NIFLoader::getSingletonPtr()->getTextIndices(smodel); insert->attachObject(base); + if(isFemale) + insert->scale(race->data.height.female, race->data.height.female, race->data.height.female); + else + insert->scale(race->data.height.male, race->data.height.male, race->data.height.male); - - if(isFemale) - insert->scale(race->data.height.female, race->data.height.female, race->data.height.female); - else - insert->scale(race->data.height.male, race->data.height.male, race->data.height.male); - updateParts(); - + updateParts(); } -void NpcAnimation::updateParts(){ +void NpcAnimation::updateParts() +{ + bool apparelChanged = false; - bool apparelChanged = false; + //inv.getSlot(MWWorld::InventoryStore::Slot_Robe); + if(robe != inv.getSlot(MWWorld::InventoryStore::Slot_Robe)) + { + // A robe was added or removed + robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe); + removePartGroup(MWWorld::InventoryStore::Slot_Robe); + apparelChanged = true; + } + if(skirtiter != inv.getSlot(MWWorld::InventoryStore::Slot_Skirt)) + { + skirtiter = inv.getSlot(MWWorld::InventoryStore::Slot_Skirt); + removePartGroup(MWWorld::InventoryStore::Slot_Skirt); + apparelChanged = true; + } + if(helmet != inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)) + { + helmet = inv.getSlot(MWWorld::InventoryStore::Slot_Helmet); + removePartGroup(MWWorld::InventoryStore::Slot_Helmet); + apparelChanged = true; + } + if(cuirass != inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)) + { + cuirass = inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass); + removePartGroup(MWWorld::InventoryStore::Slot_Cuirass); + apparelChanged = true; + } + if(greaves != inv.getSlot(MWWorld::InventoryStore::Slot_Greaves)) + { + greaves = inv.getSlot(MWWorld::InventoryStore::Slot_Greaves); + removePartGroup(MWWorld::InventoryStore::Slot_Greaves); + apparelChanged = true; + } + if(leftpauldron != inv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron)) + { + leftpauldron = inv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron); + removePartGroup(MWWorld::InventoryStore::Slot_LeftPauldron); + apparelChanged = true; + } + if(rightpauldron != inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron)) + { + rightpauldron = inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron); + removePartGroup(MWWorld::InventoryStore::Slot_RightPauldron); + apparelChanged = true; + } + if(!isBeast && boots != inv.getSlot(MWWorld::InventoryStore::Slot_Boots)) + { + boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots); + removePartGroup(MWWorld::InventoryStore::Slot_Boots); + apparelChanged = true; + } + if(leftglove != inv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet)) + { + leftglove = inv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet); + removePartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet); + apparelChanged = true; + } + if(rightglove != inv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet)) + { + rightglove = inv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet); + removePartGroup(MWWorld::InventoryStore::Slot_RightGauntlet); + apparelChanged = true; + } + if(shirt != inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)) + { + shirt = inv.getSlot(MWWorld::InventoryStore::Slot_Shirt); + removePartGroup(MWWorld::InventoryStore::Slot_Shirt); + apparelChanged = true; + } + if(pants != inv.getSlot(MWWorld::InventoryStore::Slot_Pants)) + { + pants = inv.getSlot(MWWorld::InventoryStore::Slot_Pants); + removePartGroup(MWWorld::InventoryStore::Slot_Pants); + apparelChanged = true; + } + if(apparelChanged) + { + if(robe != inv.end()) + { + MWWorld::Ptr ptr = *robe; - //inv.getSlot(MWWorld::InventoryStore::Slot_Robe); - if(robe != inv.getSlot(MWWorld::InventoryStore::Slot_Robe)){ - //A robe was added or removed - removePartGroup(MWWorld::InventoryStore::Slot_Robe); - robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe); - apparelChanged = true; - } - if(skirtiter != inv.getSlot(MWWorld::InventoryStore::Slot_Skirt)){ - //A robe was added or removed - removePartGroup(MWWorld::InventoryStore::Slot_Skirt); - skirtiter = inv.getSlot(MWWorld::InventoryStore::Slot_Skirt); - apparelChanged = true; - } - if(helmet != inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)){ - apparelChanged = true; - helmet = inv.getSlot(MWWorld::InventoryStore::Slot_Helmet); - removePartGroup(MWWorld::InventoryStore::Slot_Helmet); - + const ESM::Clothing *clothes = (ptr.get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Robe, 5, parts); + reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_Skirt, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RKnee, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LKnee, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RForearm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LForearm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); } - if(cuirass != inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)){ - cuirass = inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass); - removePartGroup(MWWorld::InventoryStore::Slot_Cuirass); - apparelChanged = true; - - } - if(greaves != inv.getSlot(MWWorld::InventoryStore::Slot_Greaves)){ - greaves = inv.getSlot(MWWorld::InventoryStore::Slot_Greaves); - removePartGroup(MWWorld::InventoryStore::Slot_Greaves); - apparelChanged = true; - } - if(leftpauldron != inv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron)){ - leftpauldron = inv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron); - removePartGroup(MWWorld::InventoryStore::Slot_LeftPauldron); - apparelChanged = true; - - } - if(rightpauldron != inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron)){ - rightpauldron = inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron); - removePartGroup(MWWorld::InventoryStore::Slot_RightPauldron); - apparelChanged = true; - - } - if(!isBeast && boots != inv.getSlot(MWWorld::InventoryStore::Slot_Boots)){ - boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots); - removePartGroup(MWWorld::InventoryStore::Slot_Boots); - apparelChanged = true; - - } - if(leftglove != inv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet)){ - leftglove = inv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet); - removePartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet); - apparelChanged = true; - - } - if(rightglove != inv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet)){ - rightglove = inv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet); - removePartGroup(MWWorld::InventoryStore::Slot_RightGauntlet); - apparelChanged = true; - - } - if(shirt != inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)){ - shirt = inv.getSlot(MWWorld::InventoryStore::Slot_Shirt); - removePartGroup(MWWorld::InventoryStore::Slot_Shirt); - apparelChanged = true; - - } - if(pants != inv.getSlot(MWWorld::InventoryStore::Slot_Pants)){ - pants = inv.getSlot(MWWorld::InventoryStore::Slot_Pants); - removePartGroup(MWWorld::InventoryStore::Slot_Pants); - apparelChanged = true; + if(skirtiter != inv.end()) + { + MWWorld::Ptr ptr = *skirtiter; + const ESM::Clothing *clothes = (ptr.get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Skirt, 4, parts); + reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Skirt, 4); + reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Skirt, 4); + reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); } - if(apparelChanged){ + if(helmet != inv.end()) + { + removeIndividualPart(ESM::PRT_Hair); + const ESM::Armor *armor = (helmet->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); + } + if(cuirass != inv.end()) + { + const ESM::Armor *armor = (cuirass->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); + } + if(greaves != inv.end()) + { + const ESM::Armor *armor = (greaves->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); + } - if(robe != inv.end()) + if(leftpauldron != inv.end()) + { + const ESM::Armor *armor = (leftpauldron->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); + } + if(rightpauldron != inv.end()) + { + const ESM::Armor *armor = (rightpauldron->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); + } + if(!isBeast && boots != inv.end()) + { + if(boots->getTypeName() == typeid(ESM::Clothing).name()) { - MWWorld::Ptr ptr = *robe; - - const ESM::Clothing *clothes = (ptr.get())->base; + const ESM::Clothing *clothes = (boots->get())->base; std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Robe, 5, parts); - reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_Skirt, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RKnee, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LKnee, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RForearm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LForearm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); + addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); } - if(skirtiter != inv.end()) + else if(boots->getTypeName() == typeid(ESM::Armor).name()) { - MWWorld::Ptr ptr = *skirtiter; - - const ESM::Clothing *clothes = (ptr.get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Skirt, 4, parts); - reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Skirt, 4); - reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Skirt, 4); - reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); - } - - if(helmet != inv.end()){ - removeIndividualPart(ESM::PRT_Hair); - const ESM::Armor *armor = (helmet->get())->base; + const ESM::Armor *armor = (boots->get())->base; std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); - - } - if(cuirass != inv.end()){ - const ESM::Armor *armor = (cuirass->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); - - } - if(greaves != inv.end()){ - const ESM::Armor *armor = (greaves->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); - - } - - if(leftpauldron != inv.end()){ - const ESM::Armor *armor = (leftpauldron->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); - - } - if(rightpauldron != inv.end()){ - const ESM::Armor *armor = (rightpauldron->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); - - } - if(!isBeast && boots != inv.end()){ - if(boots->getTypeName() == typeid(ESM::Clothing).name()){ - const ESM::Clothing *clothes = (boots->get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); - } - else if(boots->getTypeName() == typeid(ESM::Armor).name()) - { - const ESM::Armor *armor = (boots->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); - } - - } - if(leftglove != inv.end()){ - if(leftglove->getTypeName() == typeid(ESM::Clothing).name()){ - const ESM::Clothing *clothes = (leftglove->get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); - } - else - { - const ESM::Armor *armor = (leftglove->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); - } - - } - if(rightglove != inv.end()){ - if(rightglove->getTypeName() == typeid(ESM::Clothing).name()){ - const ESM::Clothing *clothes = (rightglove->get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); - } - else - { - const ESM::Armor *armor = (rightglove->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts); - } - - } - - if(shirt != inv.end()){ - const ESM::Clothing *clothes = (shirt->get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); - } - if(pants != inv.end()){ - const ESM::Clothing *clothes = (pants->get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts); + addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); } } + if(leftglove != inv.end()) + { + if(leftglove->getTypeName() == typeid(ESM::Clothing).name()) + { + const ESM::Clothing *clothes = (leftglove->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); + } + else + { + const ESM::Armor *armor = (leftglove->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); + } + } + if(rightglove != inv.end()) + { + if(rightglove->getTypeName() == typeid(ESM::Clothing).name()) + { + const ESM::Clothing *clothes = (rightglove->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); + } + else + { + const ESM::Armor *armor = (rightglove->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts); + } - if(partpriorities[ESM::PRT_Head] < 1){ - addOrReplaceIndividualPart(ESM::PRT_Head, -1,1,headModel); - } - if(partpriorities[ESM::PRT_Hair] < 1 && partpriorities[ESM::PRT_Head] <= 1){ - addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1,hairModel); - } - if(partpriorities[ESM::PRT_Neck] < 1){ - const ESM::BodyPart *neckPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "neck"); - if(neckPart) - addOrReplaceIndividualPart(ESM::PRT_Neck, -1,1,"meshes\\" + neckPart->model); - } - if(partpriorities[ESM::PRT_Cuirass] < 1){ - const ESM::BodyPart *chestPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "chest"); - if(chestPart) - addOrReplaceIndividualPart(ESM::PRT_Cuirass, -1,1,"meshes\\" + chestPart->model); - } - - if(partpriorities[ESM::PRT_Groin] < 1){ - const ESM::BodyPart *groinPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "groin"); - if(groinPart) - addOrReplaceIndividualPart(ESM::PRT_Groin, -1,1,"meshes\\" + groinPart->model); - } - if(partpriorities[ESM::PRT_RHand] < 1){ - const ESM::BodyPart *handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hand"); - if(!handPart) - handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hands"); - if(handPart) - addOrReplaceIndividualPart(ESM::PRT_RHand, -1,1,"meshes\\" + handPart->model); - } - if(partpriorities[ESM::PRT_LHand] < 1){ - const ESM::BodyPart *handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hand"); - if(!handPart) - handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hands"); - if(handPart) - addOrReplaceIndividualPart(ESM::PRT_LHand, -1,1,"meshes\\" + handPart->model); - } - - if(partpriorities[ESM::PRT_RWrist] < 1){ - const ESM::BodyPart *wristPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "wrist"); - if(wristPart) - addOrReplaceIndividualPart(ESM::PRT_RWrist, -1,1,"meshes\\" + wristPart->model); - } - if(partpriorities[ESM::PRT_LWrist] < 1){ - const ESM::BodyPart *wristPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "wrist"); - if(wristPart) - addOrReplaceIndividualPart(ESM::PRT_LWrist, -1,1,"meshes\\" + wristPart->model); - } - if(partpriorities[ESM::PRT_RForearm] < 1){ - const ESM::BodyPart *forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "forearm"); - if(bodyRaceID == "b_n_argonian_f_") - forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search ("b_n_argonian_m_forearm"); - if(forearmPart) - addOrReplaceIndividualPart(ESM::PRT_RForearm, -1,1,"meshes\\" + forearmPart->model); - } - if(partpriorities[ESM::PRT_LForearm] < 1){ - const ESM::BodyPart *forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "forearm"); - if(bodyRaceID == "b_n_argonian_f_") - forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search ("b_n_argonian_m_forearm"); - if(forearmPart) - addOrReplaceIndividualPart(ESM::PRT_LForearm, -1,1,"meshes\\" + forearmPart->model); - } - if(partpriorities[ESM::PRT_RUpperarm] < 1){ - const ESM::BodyPart *armPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper arm"); - if(armPart) - addOrReplaceIndividualPart(ESM::PRT_RUpperarm, -1,1,"meshes\\" + armPart->model); - } - if(partpriorities[ESM::PRT_LUpperarm] < 1){ - const ESM::BodyPart *armPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper arm"); - if(armPart) - addOrReplaceIndividualPart(ESM::PRT_LUpperarm, -1,1,"meshes\\" + armPart->model); - } - if(partpriorities[ESM::PRT_RFoot] < 1){ - const ESM::BodyPart *footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "foot"); - if(isBeast && !footPart) - footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "feet"); - if(footPart) - addOrReplaceIndividualPart(ESM::PRT_RFoot, -1,1,"meshes\\" + footPart->model); - } - if(partpriorities[ESM::PRT_LFoot] < 1){ - const ESM::BodyPart *footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "foot"); - if(isBeast && !footPart) - footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "feet"); - if(footPart) - addOrReplaceIndividualPart(ESM::PRT_LFoot, -1,1,"meshes\\" + footPart->model); - } - if(partpriorities[ESM::PRT_RAnkle] < 1){ - const ESM::BodyPart *anklePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "ankle"); - if(anklePart) - addOrReplaceIndividualPart(ESM::PRT_RAnkle, -1,1,"meshes\\" + anklePart->model); - } - if(partpriorities[ESM::PRT_LAnkle] < 1){ - const ESM::BodyPart *anklePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "ankle"); - if(anklePart) - addOrReplaceIndividualPart(ESM::PRT_LAnkle, -1,1,"meshes\\" + anklePart->model); - } - if(partpriorities[ESM::PRT_RKnee] < 1){ - const ESM::BodyPart *kneePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "knee"); - if(kneePart) - addOrReplaceIndividualPart(ESM::PRT_RKnee, -1,1,"meshes\\" + kneePart->model); - } - if(partpriorities[ESM::PRT_LKnee] < 1){ - const ESM::BodyPart *kneePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "knee"); - if(kneePart) - addOrReplaceIndividualPart(ESM::PRT_LKnee, -1,1,"meshes\\" + kneePart->model); - } - if(partpriorities[ESM::PRT_RLeg] < 1){ - const ESM::BodyPart *legPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper leg"); - if(legPart) - addOrReplaceIndividualPart(ESM::PRT_RLeg, -1,1,"meshes\\" + legPart->model); - } - if(partpriorities[ESM::PRT_LLeg] < 1){ - const ESM::BodyPart *legPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper leg"); - if(legPart) - addOrReplaceIndividualPart(ESM::PRT_LLeg, -1,1,"meshes\\" + legPart->model); - } - if(partpriorities[ESM::PRT_Tail] < 1){ - const ESM::BodyPart *tailPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "tail"); - if(tailPart) - addOrReplaceIndividualPart(ESM::PRT_Tail, -1,1,"meshes\\" + tailPart->model); - } - - + } + if(shirt != inv.end()) + { + const ESM::Clothing *clothes = (shirt->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); + } + if(pants != inv.end()) + { + const ESM::Clothing *clothes = (pants->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts); + } + } + if(partpriorities[ESM::PRT_Head] < 1) + addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, headModel); + if(partpriorities[ESM::PRT_Hair] < 1 && partpriorities[ESM::PRT_Head] <= 1) + addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, hairModel); + static const struct { + ESM::PartReferenceType type; + const char name[2][12]; + } PartTypeList[] = { + { ESM::PRT_Neck, { "neck", "" } }, + { ESM::PRT_Cuirass, { "chest", "" } }, + { ESM::PRT_Groin, { "groin", "" } }, + { ESM::PRT_RHand, { "hand", "hands" } }, + { ESM::PRT_LHand, { "hand", "hands" } }, + { ESM::PRT_RWrist, { "wrist", "" } }, + { ESM::PRT_LWrist, { "wrist", "" } }, + { ESM::PRT_RForearm, { "forearm", "" } }, + { ESM::PRT_LForearm, { "forearm", "" } }, + { ESM::PRT_RUpperarm, { "upper arm", "" } }, + { ESM::PRT_LUpperarm, { "upper arm", "" } }, + { ESM::PRT_RFoot, { "foot", "feet" } }, + { ESM::PRT_LFoot, { "foot", "feet" } }, + { ESM::PRT_RAnkle, { "ankle", "" } }, + { ESM::PRT_LAnkle, { "ankle", "" } }, + { ESM::PRT_RKnee, { "knee", "" } }, + { ESM::PRT_LKnee, { "knee", "" } }, + { ESM::PRT_RLeg, { "upper leg", "" } }, + { ESM::PRT_LLeg, { "upper leg", "" } }, + { ESM::PRT_Tail, { "tail", "" } } + }; + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + for(size_t i = 0;i < sizeof(PartTypeList)/sizeof(PartTypeList[0]);i++) + { + if(partpriorities[PartTypeList[i].type] < 1) + { + const ESM::BodyPart *part = NULL; + bool tryfemale = isFemale; + int ni = 0; + do { + part = store.bodyParts.search(bodyRaceID+(tryfemale?"_f_":"_m_")+PartTypeList[i].name[ni]); + if(part) break; + ni ^= 1; + if(ni == 0) + { + if(!tryfemale) + break; + tryfemale = false; + } + } while(1); + if(part) + addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->model); + } + } } -Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){ +Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, const std::string &bonename) +{ NIFLoader::load(mesh); Ogre::Entity* part = mRend.getScene()->createEntity(mesh); @@ -508,361 +390,275 @@ Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::stri base->attachObjectToBone(bonename, part); return part; } -void NpcAnimation::insertFootPart(int type, const std::string &mesh){ - std::string meshAndSuffix = mesh; - if(type == ESM::PRT_LFoot) - meshAndSuffix += "*|"; - NIFLoader::load(meshAndSuffix); - Ogre::Entity* part = mRend.getScene()->createEntity(meshAndSuffix); - std::vector* shape = ((NIFLoader::getSingletonPtr())->getShapes(meshAndSuffix)); - if(shape == 0){ - if(type == ESM::PRT_LFoot){ - base->attachObjectToBone("Left Foot", part); - lfoot = part; - } - else if (type == ESM::PRT_RFoot){ - base->attachObjectToBone("Right Foot", part); - rfoot = part; - } - } - else{ - if(type == ESM::PRT_LFoot) - lFreeFoot = insertFreePart(mesh, "::"); - else if (type == ESM::PRT_RFoot) - rFreeFoot = insertFreePart(mesh, ":<"); + +void NpcAnimation::runAnimation(float timepassed) +{ + if(timeToChange > .2) + { + timeToChange = 0; + updateParts(); } - - -} -std::pair*> NpcAnimation::insertFreePart(const std::string &mesh, const std::string& suffix){ - - std::string meshNumbered = mesh + getUniqueID(mesh + suffix) + suffix; - NIFLoader::load(meshNumbered); - - Ogre::Entity* part = mRend.getScene()->createEntity(meshNumbered); - part->setVisibilityFlags(RV_Actors); - - insert->attachObject(part); - - std::vector* shape = ((NIFLoader::getSingletonPtr())->getShapes(mesh + "0000" + suffix)); - if(shape){ - handleShapes(shape, part, base->getSkeleton()); - } - std::pair*> pair = std::make_pair(part, shape); - return pair; -} - - - - -void NpcAnimation::runAnimation(float timepassed){ - - if(timeToChange > .2){ - - timeToChange = 0; - - updateParts(); - } - - timeToChange += timepassed; + timeToChange += timepassed; //1. Add the amount of time passed to time - //2. Handle the animation transforms dependent on time + //2. Handle the animation transforms dependent on time - //3. Handle the shapes dependent on animation transforms - if(animate > 0){ + //3. Handle the shapes dependent on animation transforms + if(animate > 0) + { time += timepassed; - - if(time > stopTime){ + if(time > stopTime) + { animate--; - if(animate == 0) time = stopTime; else time = startTime + (time - stopTime); } - handleAnimationTransforms(); - - - vecRotPos.clear(); - - - if(lFreeFoot.first) - handleShapes(lFreeFoot.second, lFreeFoot.first, base->getSkeleton()); - if(rFreeFoot.first) - handleShapes(rFreeFoot.second, rFreeFoot.first, base->getSkeleton()); - - if(chest.first) - handleShapes(chest.second, chest.first, base->getSkeleton()); - if(tail.first) - handleShapes(tail.second, tail.first, base->getSkeleton()); - if(skirt.first){ - handleShapes(skirt.second, skirt.first, base->getSkeleton()); - } - if(lhand.first) - handleShapes(lhand.second, lhand.first, base->getSkeleton()); - if(rhand.first) - handleShapes(rhand.second, rhand.first, base->getSkeleton()); - -} + handleAnimationTransforms(); + } } -void NpcAnimation::removeIndividualPart(int type){ +void NpcAnimation::removeIndividualPart(int type) +{ partpriorities[type] = 0; partslots[type] = -1; - if(type == ESM::PRT_Head && head){ //0 - base->detachObjectFromBone(head); - head = 0; - } - else if(type == ESM::PRT_Hair && hair){//1 - base->detachObjectFromBone(hair); - hair = 0; - } - else if(type == ESM::PRT_Neck && neck){//2 - base->detachObjectFromBone(neck); - neck = 0; - } - else if(type == ESM::PRT_Cuirass && chest.first){//3 - insert->detachObject(chest.first); - chest = zero; - } - else if(type == ESM::PRT_Groin && groin){//4 - base->detachObjectFromBone(groin); - groin = 0; - } - else if(type == ESM::PRT_Skirt && skirt.first){//5 - insert->detachObject(skirt.first); - skirt = zero; - } - else if(type == ESM::PRT_RHand && rhand.first){//6 - insert->detachObject(rhand.first); - rhand = zero; - } - else if(type == ESM::PRT_LHand && lhand.first){//7 - insert->detachObject(lhand.first); - lhand = zero; - } - else if(type == ESM::PRT_RWrist && rWrist){//8 - base->detachObjectFromBone(rWrist); - rWrist = 0; - } - else if(type == ESM::PRT_LWrist && lWrist){//9 - base->detachObjectFromBone(lWrist); - lWrist = 0; - } - else if(type == ESM::PRT_Shield){//10 - - } - else if(type == ESM::PRT_RForearm && rForearm){//11 - base->detachObjectFromBone(rForearm); - rForearm = 0; - } - else if(type == ESM::PRT_LForearm && lForearm){//12 - base->detachObjectFromBone(lForearm); - lForearm = 0; - } - else if(type == ESM::PRT_RUpperarm && rupperArm){//13 - base->detachObjectFromBone(rupperArm); - rupperArm = 0; - } - else if(type == ESM::PRT_LUpperarm && lupperArm){//14 - base->detachObjectFromBone(lupperArm); - lupperArm = 0; - } - else if(type == ESM::PRT_RFoot){ //15 - if(rfoot){ - base->detachObjectFromBone(rfoot); - rfoot = 0; - } - else if(rFreeFoot.first){ - insert->detachObject(rFreeFoot.first); - rFreeFoot = zero; - } - } - else if(type == ESM::PRT_LFoot){ //16 - if(lfoot){ - base->detachObjectFromBone(lfoot); - lfoot = 0; - } - else if(lFreeFoot.first){ - insert->detachObject(lFreeFoot.first); - lFreeFoot = zero; - } - } - else if(type == ESM::PRT_RAnkle && rAnkle){ //17 - base->detachObjectFromBone(rAnkle); - rAnkle = 0; - } - else if(type == ESM::PRT_LAnkle && lAnkle){ //18 - base->detachObjectFromBone(lAnkle); - lAnkle = 0; - } - else if(type == ESM::PRT_RKnee && rKnee){ //19 - base->detachObjectFromBone(rKnee); - rKnee = 0; - } - else if(type == ESM::PRT_LKnee && lKnee){ //20 - base->detachObjectFromBone(lKnee); - lKnee = 0; - } - else if(type == ESM::PRT_RLeg && rUpperLeg){ //21 - base->detachObjectFromBone(rUpperLeg); - rUpperLeg = 0; - } - else if(type == ESM::PRT_LLeg && lUpperLeg){ //22 - base->detachObjectFromBone(lUpperLeg); - lUpperLeg = 0; - } - else if(type == ESM::PRT_RPauldron && rclavicle){ //23 - base->detachObjectFromBone(rclavicle); - rclavicle = 0; - } - else if(type == ESM::PRT_LPauldron && lclavicle){ //24 - base->detachObjectFromBone(lclavicle); - lclavicle = 0; - } - else if(type == ESM::PRT_Weapon){ //25 - - } - else if(type == ESM::PRT_Tail && tail.first){ //26 - insert->detachObject(tail.first); - tail = zero; - } - - - - + if(type == ESM::PRT_Head && head) //0 + { + base->detachObjectFromBone(head); + head = 0; } - - void NpcAnimation::reserveIndividualPart(int type, int group, int priority){ - if(priority > partpriorities[type]){ - removeIndividualPart(type); - partpriorities[type] = priority; - partslots[type] = group; - } + else if(type == ESM::PRT_Hair && hair) //1 + { + base->detachObjectFromBone(hair); + hair = 0; } - - void NpcAnimation::removePartGroup(int group){ - for(int i = 0; i < 27; i++){ - if(partslots[i] == group){ - removeIndividualPart(i); - } - } + else if(type == ESM::PRT_Neck && neck) //2 + { + base->detachObjectFromBone(neck); + neck = 0; } - bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh){ - if(priority > partpriorities[type]){ - removeIndividualPart(type); - partslots[type] = group; - partpriorities[type] = priority; - switch(type){ - case ESM::PRT_Head: //0 - head = insertBoundedPart(mesh, "Head"); - break; - case ESM::PRT_Hair: //1 - hair = insertBoundedPart(mesh, "Head"); - break; - case ESM::PRT_Neck: //2 - neck = insertBoundedPart(mesh, "Neck"); - break; - case ESM::PRT_Cuirass: //3 - chest = insertFreePart(mesh, ":\""); - break; - case ESM::PRT_Groin: //4 - groin = insertBoundedPart(mesh, "Groin"); - break; - case ESM::PRT_Skirt: //5 - skirt = insertFreePart(mesh, ":|"); - break; - case ESM::PRT_RHand: //6 - rhand = insertFreePart(mesh, ":?"); - break; - case ESM::PRT_LHand: //7 - lhand = insertFreePart(mesh, ":>"); - break; - case ESM::PRT_RWrist: //8 - rWrist = insertBoundedPart(mesh, "Right Wrist"); - break; - case ESM::PRT_LWrist: //9 - lWrist = insertBoundedPart(mesh + "*|", "Left Wrist"); - break; - case ESM::PRT_Shield: //10 - break; - case ESM::PRT_RForearm: //11 - rForearm = insertBoundedPart(mesh, "Right Forearm"); - break; - case ESM::PRT_LForearm: //12 - lForearm = insertBoundedPart(mesh + "*|", "Left Forearm"); - break; - case ESM::PRT_RUpperarm: //13 - rupperArm = insertBoundedPart(mesh, "Right Upper Arm"); - break; - case ESM::PRT_LUpperarm: //14 - lupperArm = insertBoundedPart(mesh + "*|", "Left Upper Arm"); - break; - case ESM::PRT_RFoot: //15 - insertFootPart(type, mesh); - break; - case ESM::PRT_LFoot: //16 - insertFootPart(type, mesh); - break; - case ESM::PRT_RAnkle: //17 - rAnkle = insertBoundedPart(mesh , "Right Ankle"); - break; - case ESM::PRT_LAnkle: //18 - lAnkle = insertBoundedPart(mesh + "*|", "Left Ankle"); - break; - case ESM::PRT_RKnee: //19 - rKnee = insertBoundedPart(mesh , "Right Knee"); - break; - case ESM::PRT_LKnee: //20 - lKnee = insertBoundedPart(mesh + "*|", "Left Knee"); - break; - case ESM::PRT_RLeg: //21 - rUpperLeg = insertBoundedPart(mesh, "Right Upper Leg"); - break; - case ESM::PRT_LLeg: //22 - lUpperLeg = insertBoundedPart(mesh + "*|", "Left Upper Leg"); - break; - case ESM::PRT_RPauldron: //23 - rclavicle = insertBoundedPart(mesh , "Right Clavicle"); - break; - case ESM::PRT_LPauldron: //24 - lclavicle = insertBoundedPart(mesh + "*|", "Left Clavicle"); - break; - case ESM::PRT_Weapon: //25 - break; - case ESM::PRT_Tail: //26 - tail = insertFreePart(mesh, ":*"); - break; - - - } - return true; - } - return false; + else if(type == ESM::PRT_Groin && groin)//4 + { + base->detachObjectFromBone(groin); + groin = 0; } - - void NpcAnimation::addPartGroup(int group, int priority, std::vector& parts){ - for(std::size_t i = 0; i < parts.size(); i++) - { - ESM::PartReference part = parts[i]; - - const ESM::BodyPart *bodypart = 0; - - if(isFemale) - bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (part.female); - if(!bodypart) - bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (part.male); - if(bodypart){ - addOrReplaceIndividualPart(part.part, group,priority,"meshes\\" + bodypart->model); - } - else - reserveIndividualPart(part.part, group, priority); - - } + else if(type == ESM::PRT_RWrist && rWrist)//8 + { + base->detachObjectFromBone(rWrist); + rWrist = 0; + } + else if(type == ESM::PRT_LWrist && lWrist) //9 + { + base->detachObjectFromBone(lWrist); + lWrist = 0; + } + else if(type == ESM::PRT_Shield) //10 + { + } + else if(type == ESM::PRT_RForearm && rForearm) //11 + { + base->detachObjectFromBone(rForearm); + rForearm = 0; + } + else if(type == ESM::PRT_LForearm && lForearm) //12 + { + base->detachObjectFromBone(lForearm); + lForearm = 0; + } + else if(type == ESM::PRT_RUpperarm && rupperArm) //13 + { + base->detachObjectFromBone(rupperArm); + rupperArm = 0; + } + else if(type == ESM::PRT_LUpperarm && lupperArm) //14 + { + base->detachObjectFromBone(lupperArm); + lupperArm = 0; + } + else if(type == ESM::PRT_RFoot && rfoot) //15 + { + base->detachObjectFromBone(rfoot); + rfoot = 0; + } + else if(type == ESM::PRT_LFoot && lfoot) //16 + { + base->detachObjectFromBone(lfoot); + lfoot = 0; + } + else if(type == ESM::PRT_RAnkle && rAnkle) //17 + { + base->detachObjectFromBone(rAnkle); + rAnkle = 0; + } + else if(type == ESM::PRT_LAnkle && lAnkle) //18 + { + base->detachObjectFromBone(lAnkle); + lAnkle = 0; + } + else if(type == ESM::PRT_RKnee && rKnee) //19 + { + base->detachObjectFromBone(rKnee); + rKnee = 0; + } + else if(type == ESM::PRT_LKnee && lKnee) //20 + { + base->detachObjectFromBone(lKnee); + lKnee = 0; + } + else if(type == ESM::PRT_RLeg && rUpperLeg) //21 + { + base->detachObjectFromBone(rUpperLeg); + rUpperLeg = 0; + } + else if(type == ESM::PRT_LLeg && lUpperLeg) //22 + { + base->detachObjectFromBone(lUpperLeg); + lUpperLeg = 0; + } + else if(type == ESM::PRT_RPauldron && rclavicle) //23 + { + base->detachObjectFromBone(rclavicle); + rclavicle = 0; + } + else if(type == ESM::PRT_LPauldron && lclavicle) //24 + { + base->detachObjectFromBone(lclavicle); + lclavicle = 0; + } + else if(type == ESM::PRT_Weapon) //25 + { } } + +void NpcAnimation::reserveIndividualPart(int type, int group, int priority) +{ + if(priority > partpriorities[type]) + { + removeIndividualPart(type); + partpriorities[type] = priority; + partslots[type] = group; + } +} + +void NpcAnimation::removePartGroup(int group) +{ + for(int i = 0; i < 27; i++) + { + if(partslots[i] == group) + removeIndividualPart(i); + } +} + +bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh) +{ + if(priority <= partpriorities[type]) + return false; + + removeIndividualPart(type); + partslots[type] = group; + partpriorities[type] = priority; + switch(type) + { + case ESM::PRT_Head: //0 + head = insertBoundedPart(mesh, "Head"); + break; + case ESM::PRT_Hair: //1 + hair = insertBoundedPart(mesh, "Head"); + break; + case ESM::PRT_Neck: //2 + neck = insertBoundedPart(mesh, "Neck"); + break; + case ESM::PRT_Cuirass: //3 + break; + case ESM::PRT_Groin: //4 + groin = insertBoundedPart(mesh, "Groin"); + break; + case ESM::PRT_Skirt: //5 + break; + case ESM::PRT_RHand: //6 + break; + case ESM::PRT_LHand: //7 + break; + case ESM::PRT_RWrist: //8 + rWrist = insertBoundedPart(mesh, "Right Wrist"); + break; + case ESM::PRT_LWrist: //9 + lWrist = insertBoundedPart(mesh, "Left Wrist"); + break; + case ESM::PRT_Shield: //10 + break; + case ESM::PRT_RForearm: //11 + rForearm = insertBoundedPart(mesh, "Right Forearm"); + break; + case ESM::PRT_LForearm: //12 + lForearm = insertBoundedPart(mesh, "Left Forearm"); + break; + case ESM::PRT_RUpperarm: //13 + rupperArm = insertBoundedPart(mesh, "Right Upper Arm"); + break; + case ESM::PRT_LUpperarm: //14 + lupperArm = insertBoundedPart(mesh, "Left Upper Arm"); + break; + case ESM::PRT_RFoot: //15 + lupperArm = insertBoundedPart(mesh, "Right Foot"); + break; + case ESM::PRT_LFoot: //16 + lupperArm = insertBoundedPart(mesh, "Left Foot"); + break; + case ESM::PRT_RAnkle: //17 + rAnkle = insertBoundedPart(mesh, "Right Ankle"); + break; + case ESM::PRT_LAnkle: //18 + lAnkle = insertBoundedPart(mesh, "Left Ankle"); + break; + case ESM::PRT_RKnee: //19 + rKnee = insertBoundedPart(mesh, "Right Knee"); + break; + case ESM::PRT_LKnee: //20 + lKnee = insertBoundedPart(mesh, "Left Knee"); + break; + case ESM::PRT_RLeg: //21 + rUpperLeg = insertBoundedPart(mesh, "Right Upper Leg"); + break; + case ESM::PRT_LLeg: //22 + lUpperLeg = insertBoundedPart(mesh, "Left Upper Leg"); + break; + case ESM::PRT_RPauldron: //23 + rclavicle = insertBoundedPart(mesh , "Right Clavicle"); + break; + case ESM::PRT_LPauldron: //24 + lclavicle = insertBoundedPart(mesh, "Left Clavicle"); + break; + case ESM::PRT_Weapon: //25 + break; + case ESM::PRT_Tail: //26 + break; + } + return true; +} + +void NpcAnimation::addPartGroup(int group, int priority, std::vector &parts) +{ + for(std::size_t i = 0; i < parts.size(); i++) + { + ESM::PartReference &part = parts[i]; + + const ESM::BodyPart *bodypart = 0; + if(isFemale) + bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search(part.female); + if(!bodypart) + bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search(part.male); + + if(bodypart) + addOrReplaceIndividualPart(part.part, group,priority,"meshes\\" + bodypart->model); + else + reserveIndividualPart(part.part, group, priority); + } +} + +} diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 8f4f8181d..151af4163 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -20,54 +20,43 @@ namespace MWRender{ class NpcAnimation: public Animation{ private: - MWWorld::InventoryStore& inv; - int mStateID; - //Free Parts - std::pair*> chest; - std::pair*> skirt; - std::pair*> lhand; - std::pair*> rhand; - std::pair*> tail; - std::pair*> lFreeFoot; - std::pair*> rFreeFoot; + MWWorld::InventoryStore& inv; + int mStateID; - int partslots[27]; //Each part slot is taken by clothing, armor, or is empty - int partpriorities[27]; - std::pair*> zero; + int partslots[27]; //Each part slot is taken by clothing, armor, or is empty + int partpriorities[27]; + //Bounded Parts + Ogre::Entity* lclavicle; + Ogre::Entity* rclavicle; + Ogre::Entity* rupperArm; + Ogre::Entity* lupperArm; + Ogre::Entity* rUpperLeg; + Ogre::Entity* lUpperLeg; + Ogre::Entity* lForearm; + Ogre::Entity* rForearm; + Ogre::Entity* lWrist; + Ogre::Entity* rWrist; + Ogre::Entity* rKnee; + Ogre::Entity* lKnee; + Ogre::Entity* neck; + Ogre::Entity* rAnkle; + Ogre::Entity* lAnkle; + Ogre::Entity* groin; + Ogre::Entity* lfoot; + Ogre::Entity* rfoot; + Ogre::Entity* hair; + Ogre::Entity* head; - - //Bounded Parts - Ogre::Entity* lclavicle; - Ogre::Entity* rclavicle; - Ogre::Entity* rupperArm; - Ogre::Entity* lupperArm; - Ogre::Entity* rUpperLeg; - Ogre::Entity* lUpperLeg; - Ogre::Entity* lForearm; - Ogre::Entity* rForearm; - Ogre::Entity* lWrist; - Ogre::Entity* rWrist; - Ogre::Entity* rKnee; - Ogre::Entity* lKnee; - Ogre::Entity* neck; - Ogre::Entity* rAnkle; - Ogre::Entity* lAnkle; - Ogre::Entity* groin; - Ogre::Entity* lfoot; - Ogre::Entity* rfoot; - Ogre::Entity* hair; - Ogre::Entity* head; - - Ogre::SceneNode* insert; + Ogre::SceneNode* insert; bool isBeast; bool isFemale; - std::string headModel; - std::string hairModel; - std::string npcName; - std::string bodyRaceID; - float timeToChange; - MWWorld::ContainerStoreIterator robe; + std::string headModel; + std::string hairModel; + std::string npcName; + std::string bodyRaceID; + float timeToChange; + MWWorld::ContainerStoreIterator robe; MWWorld::ContainerStoreIterator helmet; MWWorld::ContainerStoreIterator shirt; MWWorld::ContainerStoreIterator cuirass; @@ -80,22 +69,19 @@ private: MWWorld::ContainerStoreIterator rightglove; MWWorld::ContainerStoreIterator skirtiter; - public: - NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); - virtual ~NpcAnimation(); - Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename); - std::pair*> insertFreePart(const std::string &mesh, const std::string& suffix); - void insertFootPart(int type, const std::string &mesh); - virtual void runAnimation(float timepassed); - void updateParts(); +public: + NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); + virtual ~NpcAnimation(); + Ogre::Entity* insertBoundedPart(const std::string &mesh, const std::string &bonename); + virtual void runAnimation(float timepassed); + void updateParts(); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); - void removePartGroup(int group); + void removePartGroup(int group); void addPartGroup(int group, int priority, std::vector& parts); - - }; + } #endif diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index e9ce3f615..dd12a53ff 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -64,28 +64,13 @@ static bool fsstrict = false; /// An OGRE Archive wrapping a BSAFile archive class DirArchive: public Ogre::FileSystemArchive { - boost::filesystem::path currentdir; std::map, ciLessBoost> m; unsigned int cutoff; bool findFile(const String& filename, std::string& copy) const { - { - String passed = filename; - if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':') - passed = filename.substr(0, filename.length() - 6); - else if(filename.at(filename.length() - 2) == '"') - passed = filename.substr(0, filename.length() - 9); - else if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<' - || filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':' - || filename.at(filename.length() - 1) == '|') - passed = filename.substr(0, filename.length() - 2); - - - copy = passed; - } - + copy = filename; std::replace(copy.begin(), copy.end(), '\\', '/'); if(copy.at(0) == '/') @@ -225,46 +210,23 @@ public: // OGRE's fault. You should NOT expect an open() command not to // have any side effects on the archive, and hence this function // should not have been declared const in the first place. - BSAFile *narc = (BSAFile*)&arc; + BSAFile *narc = const_cast(&arc); - String passed = filename; - if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':') - passed = filename.substr(0, filename.length() - 6); - else if(filename.at(filename.length() - 2) == '"') - passed = filename.substr(0, filename.length() - 9); - else if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<' - || filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':' - || filename.at(filename.length() - 1) == '|') - passed = filename.substr(0, filename.length() - 2); - - // Open the file - StreamPtr strm = narc->getFile(passed.c_str()); + StreamPtr strm = narc->getFile(filename.c_str()); // Wrap it into an Ogre::DataStream. return DataStreamPtr(new Mangle2OgreStream(strm)); } -bool exists(const String& filename) { - return cexists(filename); -} + bool exists(const String& filename) { + return arc.exists(filename.c_str()); + } - // Check if the file exists. bool cexists(const String& filename) const { - String passed = filename; - if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':') - passed = filename.substr(0, filename.length() - 6); - else if(filename.at(filename.length() - 2) == '"') - passed = filename.substr(0, filename.length() - 9); - else if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<' - || filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':' - || filename.at(filename.length() - 1) == '|') - passed = filename.substr(0, filename.length() - 2); - - + return arc.exists(filename.c_str()); + } -return arc.exists(passed.c_str()); -} time_t getModifiedTime(const String&) { return 0; } // This is never called as far as I can see. diff --git a/components/nif/data.hpp b/components/nif/data.hpp index b7e2f172f..2d1e8bd3b 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -326,12 +326,6 @@ public: Ogre::Vector3 trans; // Translation float scale; // Probably scale (always 1) }; - struct BoneTrafoCopy - { - Ogre::Quaternion rotation; - Ogre::Vector3 trans; - float scale; - }; struct VertWeight { @@ -339,26 +333,12 @@ public: float weight; }; - struct BoneInfo { BoneTrafo trafo; Ogre::Vector4 unknown; std::vector weights; }; - struct BoneInfoCopy - { - std::string bonename; - unsigned short bonehandle; - BoneTrafoCopy trafo; - Ogre::Vector4 unknown; - //std::vector weights; - }; - struct IndividualWeight - { - float weight; - unsigned int boneinfocopyindex; - }; BoneTrafo trafo; std::vector bones; diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 293793009..1f1b91a46 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -110,20 +110,6 @@ public: } }; -struct NiTriShapeCopy -{ - std::string sname; - std::vector boneSequence; - Nif::NiSkinData::BoneTrafoCopy trafo; - //Ogre::Quaternion initialBoneRotation; - //Ogre::Vector3 initialBoneTranslation; - std::vector vertices; - std::vector normals; - std::vector boneinfo; - std::map > vertsToWeights; - Nif::NiMorphData morph; -}; - struct NiNode : Node { NodeList children; @@ -184,28 +170,6 @@ struct NiTriShape : Node data.post(nif); skin.post(nif); } - - NiTriShapeCopy clone() - { - NiTriShapeCopy copy; - copy.sname = name; - float *ptr = (float*)&data->vertices[0]; - float *ptrNormals = (float*)&data->normals[0]; - int numVerts = data->vertices.size() / 3; - for(int i = 0; i < numVerts; i++) - { - float *current = (float*) (ptr + i * 3); - copy.vertices.push_back(Ogre::Vector3(*current, *(current + 1), *(current + 2))); - - if(ptrNormals) - { - float *currentNormals = (float*) (ptrNormals + i * 3); - copy.normals.push_back(Ogre::Vector3(*currentNormals, *(currentNormals + 1), *(currentNormals + 2))); - } - } - - return copy; - } }; struct NiCamera : Node diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index c3b34e039..5f562504b 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -79,7 +79,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) // of the early stages of development. Right now we WANT to catch // every error as early and intrusively as possible, as it's most // likely a sign of incomplete code rather than faulty input. - Nif::NIFFile nif(resourceName); + Nif::NIFFile nif(resourceName.substr(0, resourceName.length()-7)); if (nif.numRecords() < 1) { warn("Found no records in NIF."); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 014384dd4..883cf7fce 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -42,28 +42,6 @@ using namespace std; using namespace Nif; using namespace NifOgre; -NIFLoader& NIFLoader::getSingleton() -{ - static NIFLoader instance; - return instance; -} - -NIFLoader* NIFLoader::getSingletonPtr() -{ - return &getSingleton(); -} - -void NIFLoader::warn(string msg) -{ - std::cerr << "NIFLoader: Warn:" << msg << "\n"; -} - -void NIFLoader::fail(string msg) -{ - std::cerr << "NIFLoader: Fail: "<< msg << std::endl; - assert(1); -} - // Helper class that computes the bounding box and of a mesh class BoundsFinder @@ -149,6 +127,19 @@ public: } }; + +void NIFLoader::warn(const std::string &msg) +{ + std::cerr << "NIFLoader: Warn:" << msg << "\n"; +} + +void NIFLoader::fail(const std::string &msg) +{ + std::cerr << "NIFLoader: Fail: "<< msg << std::endl; + assert(1); +} + + // Conversion of blend / test mode from NIF -> OGRE. // Not in use yet, so let's comment it out. /* @@ -193,12 +184,7 @@ static CompareFunction getTestMode(int mode) } */ -void NIFLoader::setOutputAnimFiles(bool output){ - mOutputAnimFiles = output; -} -void NIFLoader::setVerbosePath(std::string path){ - verbosePath = path; -} +#if 0 void NIFLoader::createMaterial(const Ogre::String &name, const Ogre::Vector3 &ambient, const Ogre::Vector3 &diffuse, @@ -211,17 +197,6 @@ void NIFLoader::createMaterial(const Ogre::String &name, Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create(name, resourceGroup); - //Hardware Skinning code, textures may be the wrong color if enabled - - /* if(!mSkel.isNull()){ - material->removeAllTechniques(); - - Ogre::Technique* tech = material->createTechnique(); - //tech->setSchemeName("blahblah"); - Pass* pass = tech->createPass(); - pass->setVertexProgram("Ogre/BasicVertexPrograms/AmbientOneTexture");*/ - - // This assigns the texture to this material. If the texture name is // a file name, and this file exists (in a resource directory), it // will automatically be loaded when needed. If not (such as for @@ -302,14 +277,14 @@ void NIFLoader::createMaterial(const Ogre::String &name, { bool split = Settings::Manager::getBool("split", "Shadows"); const int numsplits = 3; - for (int i = 0; i < (split ? numsplits : 1); ++i) - { + for (int i = 0; i < (split ? numsplits : 1); ++i) + { Ogre::TextureUnitState* tu = material->getTechnique(0)->getPass(0)->createTextureUnitState(); tu->setName("shadowMap" + Ogre::StringConverter::toString(i)); tu->setContentType(Ogre::TextureUnitState::CONTENT_SHADOW); tu->setTextureAddressingMode(Ogre::TextureUnitState::TAM_BORDER); tu->setTextureBorderColour(Ogre::ColourValue::White); - } + } } if (Settings::Manager::getBool("shaders", "Objects")) @@ -340,1067 +315,28 @@ void NIFLoader::createMaterial(const Ogre::String &name, material->setSelfIllumination(emissive[0], emissive[1], emissive[2]); material->setShininess(glossiness); } +#endif -// Takes a name and adds a unique part to it. This is just used to -// make sure that all materials are given unique names. -Ogre::String NIFLoader::getUniqueName(const Ogre::String &input) -{ - static int addon = 0; - static char buf[8]; - snprintf(buf, 8, "_%d", addon++); - - // Don't overflow the buffer - if (addon > 999999) addon = 0; - - return input + buf; -} - -// Check if the given texture name exists in the real world. If it -// does not, change the string IN PLACE to say .dds instead and try -// that. The texture may still not exist, but no information of value -// is lost in that case. -void NIFLoader::findRealTexture(Ogre::String &texName) -{ - if(Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - return; - - // Change texture extension to .dds - Ogre::String::size_type pos = texName.rfind('.'); - texName.replace(pos, texName.length(), ".dds"); -} - -//Handle node at top - -// Convert Nif::NiTriShape to Ogre::SubMesh, attached to the given -// mesh. -void NIFLoader::createOgreSubMesh(NiTriShape *shape, const Ogre::String &material, std::list &vertexBoneAssignments) -{ - // cout << "s:" << shape << "\n"; - NiTriShapeData *data = shape->data.getPtr(); - Ogre::SubMesh *sub = mesh->createSubMesh(shape->name); - - int nextBuf = 0; - - // This function is just one long stream of Ogre-barf, but it works - // great. - - // Add vertices - int numVerts = data->vertices.size() / 3; - sub->vertexData = new Ogre::VertexData(); - sub->vertexData->vertexCount = numVerts; - sub->useSharedVertices = false; - - Ogre::VertexDeclaration *decl = sub->vertexData->vertexDeclaration; - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); - - Ogre::HardwareVertexBufferSharedPtr vbuf = - Ogre::HardwareBufferManager::getSingleton().createVertexBuffer( - Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - numVerts, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false); - - if(flip) - { - float *datamod = new float[data->vertices.size()]; - //std::cout << "Shape" << shape->name.toString() << "\n"; - for(int i = 0; i < numVerts; i++) - { - int index = i * 3; - const float *pos = &data->vertices[index]; - Ogre::Vector3 original = Ogre::Vector3(*pos ,*(pos+1), *(pos+2)); - original = mTransform * original; - mBoundingBox.merge(original); - datamod[index] = original.x; - datamod[index+1] = original.y; - datamod[index+2] = original.z; - } - vbuf->writeData(0, vbuf->getSizeInBytes(), datamod, false); - delete [] datamod; - } - else - { - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->vertices[0], false); - } - - - Ogre::VertexBufferBinding* bind = sub->vertexData->vertexBufferBinding; - bind->setBinding(nextBuf++, vbuf); - - if (data->normals.size()) - { - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); - vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer( - Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - numVerts, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); - - if(flip) - { - Ogre::Quaternion rotation = mTransform.extractQuaternion(); - rotation.normalise(); - - float *datamod = new float[data->normals.size()]; - for(int i = 0; i < numVerts; i++) - { - int index = i * 3; - const float *pos = &data->normals[index]; - Ogre::Vector3 original = Ogre::Vector3(*pos ,*(pos+1), *(pos+2)); - original = rotation * original; - if (mNormaliseNormals) - { - original.normalise(); - } - - - datamod[index] = original.x; - datamod[index+1] = original.y; - datamod[index+2] = original.z; - } - vbuf->writeData(0, vbuf->getSizeInBytes(), datamod, false); - delete [] datamod; - } - else - { - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->normals[0], false); - } - bind->setBinding(nextBuf++, vbuf); - } - - - // Vertex colors - if (data->colors.size()) - { - const float *colors = &data->colors[0]; - Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); - std::vector colorsRGB(numVerts); - Ogre::RGBA *pColour = &colorsRGB.front(); - for (int i=0; iconvertColourValue(Ogre::ColourValue(colors[0],colors[1],colors[2], - colors[3]),pColour++); - colors += 4; - } - decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); - vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer( - Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), - numVerts, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); - vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB.front(), true); - bind->setBinding(nextBuf++, vbuf); - } - - if (data->uvlist.size()) - { - - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES); - vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer( - Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - numVerts, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,false); - - if(flip) - { - float *datamod = new float[data->uvlist.size()]; - - for(unsigned int i = 0; i < data->uvlist.size(); i+=2){ - float x = data->uvlist[i]; - - float y = data->uvlist[i + 1]; - - datamod[i] =x; - datamod[i + 1] =y; - } - vbuf->writeData(0, vbuf->getSizeInBytes(), datamod, false); - delete [] datamod; - } - else - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[0], false); - bind->setBinding(nextBuf++, vbuf); - } - - // Triangle faces - The total number of triangle points - int numFaces = data->triangles.size(); - if (numFaces) - { - - sub->indexData->indexCount = numFaces; - sub->indexData->indexStart = 0; - Ogre::HardwareIndexBufferSharedPtr ibuf = Ogre::HardwareBufferManager::getSingleton(). - createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, numFaces, - Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true); - - if(flip && mFlipVertexWinding && sub->indexData->indexCount % 3 == 0){ - - sub->indexData->indexBuffer = ibuf; - - uint16_t *datamod = new uint16_t[numFaces]; - int index = 0; - for (size_t i = 0; i < sub->indexData->indexCount; i+=3) - { - - const short *pos = &data->triangles[index]; - uint16_t i0 = (uint16_t) *(pos+0); - uint16_t i1 = (uint16_t) *(pos+1); - uint16_t i2 = (uint16_t) *(pos+2); - - //std::cout << "i0: " << i0 << "i1: " << i1 << "i2: " << i2 << "\n"; - - - datamod[index] = i2; - datamod[index+1] = i1; - datamod[index+2] = i0; - - index += 3; - } - - ibuf->writeData(0, ibuf->getSizeInBytes(), datamod, false); - delete [] datamod; - - } - else - ibuf->writeData(0, ibuf->getSizeInBytes(), &data->triangles[0], false); - sub->indexData->indexBuffer = ibuf; - } - - // Set material if one was given - if (!material.empty()) sub->setMaterialName(material); - - //add vertex bone assignments - - for (std::list::iterator it = vertexBoneAssignments.begin(); - it != vertexBoneAssignments.end(); it++) - { - sub->addBoneAssignment(*it); - } - if(mSkel.isNull()) - needBoneAssignments.push_back(sub); -} - -// Helper math functions. Reinventing linear algebra for the win! - -// Computes C = B + AxC*scale -static void vectorMulAdd(const Ogre::Matrix3 &A, const Ogre::Vector3 &B, float *C, float scale) -{ - // Keep the original values - float a = C[0]; - float b = C[1]; - float c = C[2]; - - // Perform matrix multiplication, scaling and addition - for (int i=0;i<3;i++) - C[i] = B[i] + (a*A[i][0] + b*A[i][1] + c*A[i][2])*scale; -} - -// Computes B = AxB (matrix*vector) -static void vectorMul(const Ogre::Matrix3 &A, float *C) -{ - // Keep the original values - float a = C[0]; - float b = C[1]; - float c = C[2]; - - // Perform matrix multiplication, scaling and addition - for (int i=0;i<3;i++) - C[i] = a*A[i][0] + b*A[i][1] + c*A[i][2]; -} - - -void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bounds, Transformation original, std::vector boneSequence) -{ - assert(shape != NULL); - - bool saveTheShape = inTheSkeletonTree; - // Interpret flags - bool hidden = (flags & 0x01) != 0; // Not displayed - bool collide = (flags & 0x02) != 0; // Use mesh for collision - bool bbcollide = (flags & 0x04) != 0; // Use bounding box for collision - - // Bounding box collision isn't implemented, always use mesh for now. - if (bbcollide) - { - collide = true; - bbcollide = false; - } - - // If the object was marked "NCO" earlier, it shouldn't collide with - // anything. - if (flags & 0x800) - { - collide = false; - bbcollide = false; - } - - if (!collide && !bbcollide && hidden) - // This mesh apparently isn't being used for anything, so don't - // bother setting it up. - return; - - // Material name for this submesh, if any - Ogre::String material; - - // Skip the entire material phase for hidden nodes - if (!hidden) - { - // These are set below if present - NiTexturingProperty *t = NULL; - NiMaterialProperty *m = NULL; - NiAlphaProperty *a = NULL; - - // Scan the property list for material information - PropertyList &list = shape->props; - int n = list.length(); - for (int i=0; irecType == RC_NiTexturingProperty) - t = static_cast(pr); - else if (pr->recType == RC_NiMaterialProperty) - m = static_cast(pr); - else if (pr->recType == RC_NiAlphaProperty) - a = static_cast(pr); - } - - // Texture - Ogre::String texName; - if (t && t->textures[0].inUse) - { - NiSourceTexture *st = t->textures[0].texture.getPtr(); - if (st->external) - { - /* findRealTexture checks if the file actually - exists. If it doesn't, and the name ends in .tga, it - will try replacing the extension with .dds instead - and search for that. Bethesda at some at some point - converted all their BSA textures from tga to dds for - increased load speed, but all texture file name - references were kept as .tga. - - The function replaces the name in place (that's why - we cast away the const modifier), but this is no - problem since all the nif data is stored in a local - throwaway buffer. - */ - texName = "textures\\" + st->filename; - findRealTexture(texName); - } - else warn("Found internal texture, ignoring."); - } - - // Alpha modifiers - int alphaFlags = -1; - ubyte alphaTest = 0; - if (a) - { - alphaFlags = a->flags; - alphaTest = a->data.threshold; - } - - // Material - if (m || !texName.empty()) - { - // If we're here, then this mesh has a material. Thus we - // need to calculate a snappy material name. It should - // contain the mesh name (mesh->getName()) but also has to - // be unique. One mesh may use many materials. - material = getUniqueName(mesh->getName()); - - if (m) - { - // Use NiMaterialProperty data to create the data - const S_MaterialProperty *d = &m->data; - - std::multimap::iterator itr = MaterialMap.find(texName); - std::multimap::iterator lastElement; - lastElement = MaterialMap.upper_bound(texName); - if (itr != MaterialMap.end()) - { - for ( ; itr != lastElement; ++itr) - { - //std::cout << "OK!"; - //MaterialPtr mat = MaterialManager::getSingleton().getByName(itr->second,recourceGroup); - material = itr->second; - //if( mat->getA - } - } - else - { - //std::cout << "new"; - createMaterial(material, d->ambient, d->diffuse, d->specular, d->emissive, - d->glossiness, d->alpha, alphaFlags, alphaTest, texName); - MaterialMap.insert(std::make_pair(texName,material)); - } - } - else - { - // We only have a texture name. Create a default - // material for it. - const Ogre::Vector3 zero(0.0f), one(1.0f); - createMaterial(material, one, one, zero, zero, 0.0f, 1.0f, - alphaFlags, alphaTest, texName); - } - } - } // End of material block, if(!hidden) ... - - /* Do in-place transformation of all the vertices and normals. This - is pretty messy stuff, but we need it to make the sub-meshes - appear in the correct place. Neither Ogre nor Bullet support - nested levels of sub-meshes with transformations applied to each - level. - */ - NiTriShapeData *data = shape->data.getPtr(); - int numVerts = data->vertices.size() / 3; - - float *ptr = (float*)&data->vertices[0]; - float *optr = ptr; - - std::list vertexBoneAssignments; - - Nif::NiTriShapeCopy copy = shape->clone(); - - if(!shape->controller.empty()) - { - Nif::Controller* cont = shape->controller.getPtr(); - if(cont->recType == RC_NiGeomMorpherController) - { - Nif::NiGeomMorpherController* morph = dynamic_cast (cont); - copy.morph = morph->data.get(); - copy.morph.setStartTime(morph->timeStart); - copy.morph.setStopTime(morph->timeStop); - saveTheShape = true; - } - - } - //use niskindata for the position of vertices. - if (!shape->skin.empty()) - { - - - - // vector that stores if the position of a vertex is absolute - std::vector vertexPosAbsolut(numVerts,false); - std::vector vertexPosOriginal(numVerts, Ogre::Vector3::ZERO); - std::vector vertexNormalOriginal(numVerts, Ogre::Vector3::ZERO); - - float *ptrNormals = (float*)&data->normals[0]; - //the bone from skin->bones[boneIndex] is linked to skin->data->bones[boneIndex] - //the first one contains a link to the bone, the second vertex transformation - //relative to the bone - int boneIndex = 0; - Ogre::Bone *bonePtr; - Ogre::Vector3 vecPos; - Ogre::Quaternion vecRot; - - std::vector boneList = shape->skin->data->bones; - - /* - Iterate through the boneList which contains what vertices are linked to - the bone (it->weights array) and at what position (it->trafo) - That position is added to every vertex. - */ - for (std::vector::iterator it = boneList.begin(); - it != boneList.end(); it++) - { - if(mSkel.isNull()) - { - std::cout << "No skeleton for :" << shape->skin->bones[boneIndex]->name << std::endl; - break; - } - //get the bone from bones array of skindata - if(!mSkel->hasBone(shape->skin->bones[boneIndex]->name)) - std::cout << "We don't have this bone"; - bonePtr = mSkel->getBone(shape->skin->bones[boneIndex]->name); - - // final_vector = old_vector + old_rotation*new_vector*old_scale - - - Nif::NiSkinData::BoneInfoCopy boneinfocopy; - boneinfocopy.trafo.rotation = it->trafo.rotation; - boneinfocopy.trafo.trans = it->trafo.trans; - boneinfocopy.bonename = shape->skin->bones[boneIndex]->name; - boneinfocopy.bonehandle = bonePtr->getHandle(); - copy.boneinfo.push_back(boneinfocopy); - for (unsigned int i=0; iweights.size(); i++) - { - vecPos = bonePtr->_getDerivedPosition() + - bonePtr->_getDerivedOrientation() * it->trafo.trans; - - vecRot = bonePtr->_getDerivedOrientation() * it->trafo.rotation; - unsigned int verIndex = it->weights[i].vertex; - //boneinfo.weights.push_back(*(it->weights.ptr + i)); - Nif::NiSkinData::IndividualWeight ind; - ind.weight = it->weights[i].weight; - ind.boneinfocopyindex = copy.boneinfo.size() - 1; - if(copy.vertsToWeights.find(verIndex) == copy.vertsToWeights.end()) - { - std::vector blank; - blank.push_back(ind); - copy.vertsToWeights[verIndex] = blank; - } - else - { - copy.vertsToWeights[verIndex].push_back(ind); - } - - //Check if the vertex is relativ, FIXME: Is there a better solution? - if (vertexPosAbsolut[verIndex] == false) - { - //apply transformation to the vertices - Ogre::Vector3 absVertPos = vecPos + vecRot * Ogre::Vector3(ptr + verIndex *3); - absVertPos = absVertPos * it->weights[i].weight; - vertexPosOriginal[verIndex] = Ogre::Vector3(ptr + verIndex *3); - - mBoundingBox.merge(absVertPos); - //convert it back to float * - for (int j=0; j<3; j++) - (ptr + verIndex*3)[j] = absVertPos[j]; - - //apply rotation to the normals (not every vertex has a normal) - //FIXME: I guessed that vertex[i] = normal[i], is that true? - if (verIndex < data->normals.size()) - { - Ogre::Vector3 absNormalsPos = vecRot * Ogre::Vector3(ptrNormals + verIndex *3); - absNormalsPos = absNormalsPos * it->weights[i].weight; - vertexNormalOriginal[verIndex] = Ogre::Vector3(ptrNormals + verIndex *3); - - for (int j=0; j<3; j++) - (ptrNormals + verIndex*3)[j] = absNormalsPos[j]; - } - - vertexPosAbsolut[verIndex] = true; - } - else - { - Ogre::Vector3 absVertPos = vecPos + vecRot * vertexPosOriginal[verIndex]; - absVertPos = absVertPos * it->weights[i].weight; - Ogre::Vector3 old = Ogre::Vector3(ptr + verIndex *3); - absVertPos = absVertPos + old; - - mBoundingBox.merge(absVertPos); - //convert it back to float * - for (int j=0; j<3; j++) - (ptr + verIndex*3)[j] = absVertPos[j]; - - //apply rotation to the normals (not every vertex has a normal) - //FIXME: I guessed that vertex[i] = normal[i], is that true? - if (verIndex < data->normals.size()) - { - Ogre::Vector3 absNormalsPos = vecRot * vertexNormalOriginal[verIndex]; - absNormalsPos = absNormalsPos * it->weights[i].weight; - Ogre::Vector3 oldNormal = Ogre::Vector3(ptrNormals + verIndex *3); - absNormalsPos = absNormalsPos + oldNormal; - - for (int j=0; j<3; j++) - (ptrNormals + verIndex*3)[j] = absNormalsPos[j]; - } - } - - - Ogre::VertexBoneAssignment vba; - vba.boneIndex = bonePtr->getHandle(); - vba.vertexIndex = verIndex; - vba.weight = it->weights[i].weight; - - - vertexBoneAssignments.push_back(vba); - } - - - boneIndex++; - } - - - } - else - { - - copy.boneSequence = boneSequence; - // Rotate, scale and translate all the vertices, - const Ogre::Matrix3 &rot = shape->trafo.rotation; - const Ogre::Vector3 &pos = shape->trafo.pos; - float scale = shape->trafo.scale; - - copy.trafo.trans = original.pos; - copy.trafo.rotation = original.rotation; - copy.trafo.scale = original.scale; - //We don't use velocity for anything yet, so it does not need to be saved - - // Computes C = B + AxC*scale - for (int i=0; inormals.size()) - { - ptr = (float*)&data->normals[0]; - for (int i=0; igetNumBones() - 1; - for(int i = 0; i < numVerts; i++){ - Ogre::VertexBoneAssignment vba; - vba.boneIndex = boneIndex; - vba.vertexIndex = i; - vba.weight = 1; - vertexBoneAssignments.push_back(vba); - } - } - } - - if (!hidden) - { - // Add this vertex set to the bounding box - bounds.add(optr, numVerts); - if(saveTheShape) - shapes.push_back(copy); - - // Create the submesh - createOgreSubMesh(shape, material, vertexBoneAssignments); - } -} - -void NIFLoader::calculateTransform() -{ - // Calculate transform - Ogre::Matrix4 transform = Ogre::Matrix4::IDENTITY; - transform = Ogre::Matrix4::getScale(vector) * transform; - - // Check whether we have to flip vertex winding. - // We do have to, if we changed our right hand base. - // We can test it by using the cross product from X and Y and see, if it is a non-negative - // projection on Z. Actually it should be exactly Z, as we don't do non-uniform scaling yet, - // but the test is cheap either way. - Ogre::Matrix3 m3; - transform.extract3x3Matrix(m3); - - if (m3.GetColumn(0).crossProduct(m3.GetColumn(1)).dotProduct(m3.GetColumn(2)) < 0) - { - mFlipVertexWinding = true; - } - - mTransform = transform; -} -void NIFLoader::handleNode(Nif::Node *node, int flags, - const Transformation *trafo, BoundsFinder &bounds, Ogre::Bone *parentBone, std::vector boneSequence) -{ - // Accumulate the flags from all the child nodes. This works for all - // the flags we currently use, at least. - flags |= node->flags; - - // Check for extra data - Extra *e = node; - while (!e->extra.empty()) - { - // Get the next extra data in the list - e = e->extra.getPtr(); - assert(e != NULL); - - if (e->recType == RC_NiStringExtraData) - { - // String markers may contain important information - // affecting the entire subtree of this node - NiStringExtraData *sd = (NiStringExtraData*)e; - - if (sd->string == "NCO") - // No collision. Use an internal flag setting to mark this. - flags |= 0x800; - else if (sd->string == "MRK") - // Marker objects. These are only visible in the - // editor. Until and unless we add an editor component to - // the engine, just skip this entire node. - return; - } - - if (e->recType == RC_NiTextKeyExtraData){ - Nif::NiTextKeyExtraData* extra = dynamic_cast (e); - - std::ofstream file; - - if(mOutputAnimFiles){ - std::string cut = ""; - for(unsigned int i = 0; i < name.length(); i++) - { - if(!(name.at(i) == '\\' || name.at(i) == '/' || name.at(i) == '>' || name.at(i) == '<' || name.at(i) == '?' || name.at(i) == '*' || name.at(i) == '|' || name.at(i) == ':' || name.at(i) == '"')) - { - cut += name.at(i); - } - } - - std::cout << "Outputting " << cut << "\n"; - - file.open((verbosePath + "/Indices" + cut + ".txt").c_str()); - } - - for(std::vector::iterator textiter = extra->list.begin(); textiter != extra->list.end(); textiter++) - { - std::string text = textiter->text; - - replace(text.begin(), text.end(), '\n', '/'); - - text.erase(std::remove(text.begin(), text.end(), '\r'), text.end()); - std::size_t i = 0; - while(i < text.length()){ - while(i < text.length() && text.at(i) == '/' ){ - i++; - } - std::size_t first = i; - int length = 0; - while(i < text.length() && text.at(i) != '/' ){ - i++; - length++; - } - if(first < text.length()){ - //length = text.length() - first; - std::string sub = text.substr(first, length); - - if(mOutputAnimFiles) - file << "Time: " << textiter->time << "|" << sub << "\n"; - - textmappings[sub] = textiter->time; - } - } - } - file.close(); - } - } - - Ogre::Bone *bone = 0; - - // create skeleton or add bones - if (node->recType == RC_NiNode) - { - //FIXME: "Bip01" isn't every time the root bone - if (node->name == "Bip01" || node->name == "Root Bone") //root node, create a skeleton - { - inTheSkeletonTree = true; - - mSkel = Ogre::SkeletonManager::getSingleton().create(getSkeletonName(), resourceGroup, true); - } - else if (!mSkel.isNull() && !parentBone) - inTheSkeletonTree = false; - - if (!mSkel.isNull()) //if there is a skeleton - { - std::string name = node->name; - - // Quick-n-dirty workaround for the fact that several - // bones may have the same name. - if(!mSkel->hasBone(name)) - { - boneSequence.push_back(name); - bone = mSkel->createBone(name); - - if (parentBone) - parentBone->addChild(bone); - - bone->setInheritOrientation(true); - bone->setPosition(node->trafo.pos); - bone->setOrientation(node->trafo.rotation); - } - } - } - Transformation original = node->trafo; - // Apply the parent transformation to this node. We overwrite the - // existing data with the final transformation. - if (trafo) - { - // Get a non-const reference to the node's data, since we're - // overwriting it. TODO: Is this necessary? - Transformation &final = node->trafo; - - // For both position and rotation we have that: - // final_vector = old_vector + old_rotation*new_vector*old_scale - final.pos = trafo->pos + trafo->rotation*final.pos*trafo->scale; - - // Merge the rotations together - final.rotation = trafo->rotation * final.rotation; - - // Scale - final.scale *= trafo->scale; - } - - // For NiNodes, loop through children - if (node->recType == RC_NiNode) - { - NodeList &list = ((NiNode*)node)->children; - int n = list.length(); - for (int i = 0; itrafo, bounds, bone, boneSequence); - } - } - else if (node->recType == RC_NiTriShape && bNiTri) - { - std::string nodename = node->name; - - if (triname == "") - { - handleNiTriShape(dynamic_cast(node), flags, bounds, original, boneSequence); - } - else if(nodename.length() >= triname.length()) - { - std::transform(nodename.begin(), nodename.end(), nodename.begin(), ::tolower); - if(triname == nodename.substr(0, triname.length())) - handleNiTriShape(dynamic_cast(node), flags, bounds, original, boneSequence); - } - } -} void NIFLoader::loadResource(Ogre::Resource *resource) { - inTheSkeletonTree = false; - allanim.clear(); - shapes.clear(); - needBoneAssignments.clear(); - // needBoneAssignments.clear(); - mBoundingBox.setNull(); - mesh = 0; - mSkel.setNull(); - flip = false; - name = resource->getName(); - char suffix = name.at(name.length() - 2); - bool addAnim = true; - bool hasAnim = false; - bool linkSkeleton = true; - //bool baddin = false; - bNiTri = true; - if(name == "meshes\\base_anim.nif" || name == "meshes\\base_animkna.nif") - { - bNiTri = false; - } - - if(suffix == '*') - { - vector = Ogre::Vector3(-1,1,1); - flip = true; - } - else if(suffix == '?'){ - vector = Ogre::Vector3(1,-1,1); - flip = true; - } - else if(suffix == '<'){ - vector = Ogre::Vector3(1,1,-1); - flip = true; - } - else if(suffix == '>') - { - //baddin = true; - bNiTri = true; - std::string sub = name.substr(name.length() - 6, 4); - - if(sub.compare("0000") != 0) - addAnim = false; - - } - else if(suffix == ':') - { - //baddin = true; - linkSkeleton = false; - bNiTri = true; - std::string sub = name.substr(name.length() - 6, 4); - - if(sub.compare("0000") != 0) - addAnim = false; - - } - - switch(name.at(name.length() - 1)) - { - case '"': - triname = "tri chest"; - break; - case '*': - triname = "tri tail"; - break; - case ':': - triname = "tri left foot"; - break; - case '<': - triname = "tri right foot"; - break; - case '>': - triname = "tri left hand"; - break; - case '?': - triname = "tri right hand"; - break; - default: - triname = ""; - break; - } - if(flip) - { - calculateTransform(); - } - // Get the mesh - mesh = dynamic_cast(resource); - assert(mesh); - - // Look it up - resourceName = mesh->getName(); - - - // Helper that computes bounding boxes for us. - BoundsFinder bounds; - - // Load the NIF. TODO: Wrap this in a try-catch block once we're out - // of the early stages of development. Right now we WANT to catch - // every error as early and intrusively as possible, as it's most - // likely a sign of incomplete code rather than faulty input. - NIFFile nif(resourceName); - if (nif.numRecords() < 1) - { - warn("Found no records in NIF."); - return; - } - - // The first record is assumed to be the root node - Record *r = nif.getRecord(0); - assert(r != NULL); - - Nif::Node *node = dynamic_cast(r); - - if (node == NULL) - { - warn("First record in file was not a node, but a " + - r->recName + ". Skipping file."); - return; - } - - // Handle the node - std::vector boneSequence; - - - - handleNode(node, 0, NULL, bounds, 0, boneSequence); - if(addAnim) - { - for(int i = 0; i < nif.numRecords(); i++) - { - Nif::NiKeyframeController *f = dynamic_cast(nif.getRecord(i)); - - if(f != NULL) - { - hasAnim = true; - Nif::Node *o = dynamic_cast(f->target.getPtr()); - Nif::NiKeyframeDataPtr data = f->data; - - if (f->timeStart >= 10000000000000000.0f) - continue; - data->setBonename(o->name); - data->setStartTime(f->timeStart); - data->setStopTime(f->timeStop); - - allanim.push_back(data.get()); - } - } - } - // set the bounding value. - if (bounds.isValid()) - { - mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX(), bounds.minY(), bounds.minZ(), - bounds.maxX(), bounds.maxY(), bounds.maxZ())); - mesh->_setBoundingSphereRadius(bounds.getRadius()); - } - if(hasAnim && addAnim){ - allanimmap[name] = allanim; - alltextmappings[name] = textmappings; - } - if(!mSkel.isNull() && shapes.size() > 0 && addAnim) - { - allshapesmap[name] = shapes; - - } - - if(flip){ - mesh->_setBounds(mBoundingBox, false); - } - - if (!mSkel.isNull() ) - { - for(std::vector::iterator iter = needBoneAssignments.begin(); iter != needBoneAssignments.end(); iter++) - { - int boneIndex = mSkel->getNumBones() - 1; - Ogre::VertexBoneAssignment vba; - vba.boneIndex = boneIndex; - vba.vertexIndex = 0; - vba.weight = 1; - - - (*iter)->addBoneAssignment(vba); - } - //Don't link on npc parts to eliminate redundant skeletons - //Will have to be changed later slightly for robes/skirts - if(linkSkeleton) - mesh->_notifySkeleton(mSkel); - } + warn("Found no records in NIF."); } - - - - Ogre::MeshPtr NIFLoader::load(const std::string &name, const std::string &group) { + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - Ogre::MeshManager *m = Ogre::MeshManager::getSingletonPtr(); // Check if the resource already exists - Ogre::ResourcePtr ptr = m->getByName(name, group); - Ogre::MeshPtr themesh; - if (!ptr.isNull()){ - themesh = Ogre::MeshPtr(ptr); - } - else // Nope, create a new one. + Ogre::MeshPtr themesh = meshMgr.getByName(name, group); + if(themesh.isNull()) { - themesh = Ogre::MeshManager::getSingleton().createManual(name, group, NIFLoader::getSingletonPtr()); + static NIFLoader loader; + themesh = meshMgr.createManual(name, group, &loader); } return themesh; } -/* -This function shares much of the same code handleShapes() in MWRender::Animation -This function also creates new position and normal buffers for submeshes. -This function points to existing texture and IndexData buffers -*/ - -std::vector* NIFLoader::getAnim(std::string lowername){ - - std::map,ciLessBoost>::iterator iter = allanimmap.find(lowername); - std::vector* pass = 0; - if(iter != allanimmap.end()) - pass = &(iter->second); - return pass; - -} -std::vector* NIFLoader::getShapes(std::string lowername){ - - std::map,ciLessBoost>::iterator iter = allshapesmap.find(lowername); - std::vector* pass = 0; - if(iter != allshapesmap.end()) - pass = &(iter->second); - return pass; -} - -std::map* NIFLoader::getTextIndices(std::string lowername){ - std::map, ciLessBoost>::iterator iter = alltextmappings.find(lowername); - std::map* pass = 0; - if(iter != alltextmappings.end()) - pass = &(iter->second); - return pass; -} - - - /* More code currently not in use, from the old D source. This was used in the first attempt at loading NIF meshes, where each submesh diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 64efc70c7..bc1ef304c 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -67,12 +67,9 @@ namespace Nif namespace NifOgre { - - /** Manual resource loader for NIF meshes. This is the main class responsible for translating the internal NIF mesh structure into - something Ogre can use. Later it will also handle the insertion of - collision meshes into Bullet / OgreBullet. + something Ogre can use. You have to insert meshes manually into Ogre like this: @@ -86,93 +83,18 @@ namespace NifOgre */ class NIFLoader : Ogre::ManualResourceLoader { - public: - static int numberOfMeshes; - static NIFLoader& getSingleton(); - static NIFLoader* getSingletonPtr(); +public: + virtual void loadResource(Ogre::Resource *resource); - virtual void loadResource(Ogre::Resource *resource); - - static Ogre::MeshPtr load(const std::string &name, - const std::string &group="General"); - //void insertMeshInsideBase(Ogre::Mesh* mesh); - std::vector* getAnim(std::string name); - std::vector* getShapes(std::string name); - std::map* getTextIndices(std::string name); - - - void setOutputAnimFiles(bool output); - void setVerbosePath(std::string path); - - private: - - NIFLoader() : resourceName(""), resourceGroup("General"), flip(false), mNormaliseNormals(false), - mFlipVertexWinding(false), mOutputAnimFiles(false), inTheSkeletonTree(false) {} - NIFLoader(NIFLoader& n) {} - - void calculateTransform(); - - - void warn(std::string msg); - void fail(std::string msg); - - void handleNode( Nif::Node *node, int flags, - const Nif::Transformation *trafo, BoundsFinder &bounds, Ogre::Bone *parentBone, std::vector boneSequence); - - void handleNiTriShape(Nif::NiTriShape *shape, int flags, BoundsFinder &bounds, Nif::Transformation original, std::vector boneSequence); - - void createOgreSubMesh(Nif::NiTriShape *shape, const Ogre::String &material, std::list &vertexBoneAssignments); - - void createMaterial(const Ogre::String &name, - const Ogre::Vector3 &ambient, - const Ogre::Vector3 &diffuse, - const Ogre::Vector3 &specular, - const Ogre::Vector3 &emissive, - float glossiness, float alpha, - int alphaFlags, float alphaTest, - const Ogre::String &texName); - - void findRealTexture(Ogre::String &texName); - - Ogre::String getUniqueName(const Ogre::String &input); - - //returns the skeleton name of this mesh - std::string getSkeletonName() - { - return resourceName + ".skel"; - } - - std::string verbosePath; - std::string resourceName; - std::string resourceGroup; - Ogre::Matrix4 mTransform; - Ogre::AxisAlignedBox mBoundingBox; - bool flip; - bool mNormaliseNormals; - bool mFlipVertexWinding; - bool bNiTri; - bool mOutputAnimFiles; - std::multimap MaterialMap; - - // pointer to the ogre mesh which is currently build - Ogre::Mesh *mesh; - Ogre::SkeletonPtr mSkel; - Ogre::Vector3 vector; - std::vector shapes; - std::string name; - std::string triname; - std::vector allanim; - - std::map textmappings; - std::map,ciLessBoost> alltextmappings; - std::map,ciLessBoost> allanimmap; - std::map,ciLessBoost> allshapesmap; - std::vector mAnim; - std::vector mS; - std::vector needBoneAssignments; - bool inTheSkeletonTree; + static Ogre::MeshPtr load(const std::string &name, + const std::string &group="General"); +private: + NIFLoader() {} + NIFLoader(NIFLoader& n) {} + void warn(const std::string &msg); + void fail(const std::string &msg); }; } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 11c18010e..61d0c7b0e 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -336,7 +336,7 @@ namespace Physic char uniqueID[8]; sprintf( uniqueID, "%07.3f", scale ); std::string sid = uniqueID; - std::string outputstring = mesh + uniqueID + "\"|"; + std::string outputstring = mesh + uniqueID; //std::cout << "The string" << outputstring << "\n"; //get the shape from the .nif From ecdd4ee23f329cce4d48796f5a27a9af2eb22d5f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Jul 2012 20:55:11 -0700 Subject: [PATCH 12/92] Load NiMorphData and NiKeyframeData using proper key lists --- apps/openmw/mwrender/animation.cpp | 65 ----- components/nif/data.hpp | 371 ++--------------------------- 2 files changed, 19 insertions(+), 417 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 7e50706f9..13b797734 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -171,71 +171,6 @@ bool Animation::timeIndex(float time, const std::vector ×, int &i, i void Animation::handleAnimationTransforms() { - Ogre::SkeletonInstance* skel = base->getSkeleton(); - - Ogre::Bone* b = skel->getRootBone(); - b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3)); //This is a trick - - skel->_updateTransforms(); - //skel->_notifyManualBonesDirty(); - - base->getAllAnimationStates()->_notifyDirty(); - //base->_updateAnimation(); - //base->_notifyMoved(); - - std::vector::iterator iter; - int slot = 0; - if(transformations) - { - for(iter = transformations->begin(); iter != transformations->end(); iter++) - { - if(time < iter->getStartTime() || time < startTime || time > iter->getStopTime()) - { - slot++; - continue; - } - - float x; - float x2; - - const std::vector &quats = iter->getQuat(); - const std::vector &ttime = iter->gettTime(); - const std::vector &rtime = iter->getrTime(); - const std::vector &translist1 = iter->getTranslist1(); - - int rindexJ = rindexI[slot]; - timeIndex(time, rtime, rindexI[slot], rindexJ, x2); - - int tindexJ = tindexI[slot]; - timeIndex(time, ttime, tindexI[slot], tindexJ, x); - - Ogre::Vector3 t; - Ogre::Quaternion r; - - bool bTrans = translist1.size() > 0; - bool bQuats = quats.size() > 0; - if(skel->hasBone(iter->getBonename())) - { - Ogre::Bone* bone = skel->getBone(iter->getBonename()); - if(bTrans) - { - Ogre::Vector3 v1 = translist1[tindexI[slot]]; - Ogre::Vector3 v2 = translist1[tindexJ]; - t = (v1 + (v2 - v1) * x); - bone->setPosition(t); - } - if(bQuats) - { - r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true); - bone->setOrientation(r); - } - } - - slot++; - } - skel->_updateTransforms(); - base->getAllAnimationStates()->_notifyDirty(); - } } } diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 2d1e8bd3b..208337f35 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -373,378 +373,45 @@ public: } }; -class NiMorphData : public Record +struct NiMorphData : public Record { - float startTime; - float stopTime; - std::vector initialVertices; - std::vector > relevantTimes; - std::vector > relevantData; - std::vector > additionalVertices; - -public: - float getStartTime() const - { return startTime; } - float getStopTime() const - { return stopTime; } - - void setStartTime(float time) - { startTime = time; } - void setStopTime(float time) - { stopTime = time; } - - const std::vector& getInitialVertices() const - { return initialVertices; } - const std::vector >& getRelevantData() const - { return relevantData; } - const std::vector >& getRelevantTimes() const - { return relevantTimes; } - const std::vector >& getAdditionalVertices() const - { return additionalVertices; } + struct MorphData { + FloatKeyList mData; + std::vector mVertices; + }; + std::vector mMorphs; void read(NIFFile *nif) { int morphCount = nif->getInt(); int vertCount = nif->getInt(); nif->getChar(); - int magic = nif->getInt(); - /*int type =*/ nif->getInt(); - for(int i = 0; i < vertCount; i++) + mMorphs.resize(morphCount); + for(int i=0; igetFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - initialVertices.push_back(Ogre::Vector3(x, y, z)); - } + mMorphs[i].mData.read(nif); - for(int i=1; igetInt(); - /*type =*/ nif->getInt(); - std::vector current; - std::vector currentTime; - for(int i = 0; i < magic; i++) - { - // Time, data, forward, backward tangents - float time = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - current.push_back(Ogre::Vector3(x,y,z)); - currentTime.push_back(time); - //nif->getFloatLen(4*magic); - } - - if(magic) - { - relevantData.push_back(current); - relevantTimes.push_back(currentTime); - } - - std::vector verts; - for(int i = 0; i < vertCount; i++) - { - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - verts.push_back(Ogre::Vector3(x, y, z)); - } - additionalVertices.push_back(verts); + mMorphs[i].mVertices.resize(vertCount); + for(int j = 0;j < vertCount;j++) + mMorphs[i].mVertices[j] = nif->getVector3(); } } }; -class NiKeyframeData : public Record +struct NiKeyframeData : public Record { - std::string bonename; - //Rotations - std::vector quats; - std::vector tbc; - std::vector rottime; - float startTime; - float stopTime; - int rtype; - - //Translations - std::vector translist1; - std::vector translist2; - std::vector translist3; - std::vector transtbc; - std::vector transtime; - int ttype; - - //Scalings - std::vector scalefactor; - std::vector scaletime; - std::vector forwards; - std::vector backwards; - std::vector tbcscale; - int stype; - -public: - void clone(const NiKeyframeData &c) - { - quats = c.getQuat(); - tbc = c.getrTbc(); - rottime = c.getrTime(); - - //types - ttype = c.getTtype(); - rtype = c.getRtype(); - stype = c.getStype(); - - - translist1 = c.getTranslist1(); - translist2 = c.getTranslist2(); - translist3 = c.getTranslist3(); - - transtime = c.gettTime(); - - bonename = c.getBonename(); - } - - void setBonename(std::string bone) - { bonename = bone; } - void setStartTime(float start) - { startTime = start; } - void setStopTime(float end) - { stopTime = end; } + QuaternionKeyList mRotations; + Vector3KeyList mTranslations; + FloatKeyList mScales; void read(NIFFile *nif) { - // Rotations first - int count = nif->getInt(); - //std::vector quat(count); - //std::vector rottime(count); - if(count) - { - //TYPE1 LINEAR_KEY - //TYPE2 QUADRATIC_KEY - //TYPE3 TBC_KEY - //TYPE4 XYZ_ROTATION_KEY - //TYPE5 UNKNOWN_KEY - rtype = nif->getInt(); - //std::cout << "Count: " << count << "Type: " << type << "\n"; - - if(rtype == 1) - { - //We need to actually read in these values instead of skipping them - //nif->skip(count*4*5); // time + quaternion - for (int i = 0; i < count; i++) - { - float time = nif->getFloat(); - float w = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - Ogre::Quaternion quat = Ogre::Quaternion(Ogre::Real(w), Ogre::Real(x), Ogre::Real(y), Ogre::Real(z)); - quats.push_back(quat); - rottime.push_back(time); - //if(time == 0.0 || time > 355.5) - // std::cout <<"Time:" << time << "W:" << w <<"X:" << x << "Y:" << y << "Z:" << z << "\n"; - } - } - else if(rtype == 3) - { - //Example - node 116 in base_anim.nif - for (int i = 0; i < count; i++) - { - float time = nif->getFloat(); - float w = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - - float tbcx = nif->getFloat(); - float tbcy = nif->getFloat(); - float tbcz = nif->getFloat(); - - Ogre::Quaternion quat = Ogre::Quaternion(Ogre::Real(w), Ogre::Real(x), Ogre::Real(y), Ogre::Real(z)); - Ogre::Vector3 vec = Ogre::Vector3(tbcx, tbcy, tbcz); - quats.push_back(quat); - rottime.push_back(time); - tbc.push_back(vec); - //if(time == 0.0 || time > 355.5) - // std::cout <<"Time:" << time << "W:" << w <<"X:" << x << "Y:" << y << "Z:" << z << "\n"; - } - } - else if(rtype == 4) - { - for(int j=0;jgetFloat(); // time - for(int i=0; i<3; i++) - { - int cnt = nif->getInt(); - int type = nif->getInt(); - if(type == 1) - nif->skip(cnt*4*2); // time + unknown - else if(type == 2) - nif->skip(cnt*4*4); // time + unknown vector - else - nif->fail("Unknown sub-rotation type"); - } - } - } - else - nif->fail("Unknown rotation type in NiKeyframeData"); - } - //first = false; - - // Then translation - count = nif->getInt(); - if(count) - { - ttype = nif->getInt(); - - //std::cout << "TransCount:" << count << " Type: " << type << "\n"; - if(ttype == 1) - { - for(int i = 0; i < count; i++) - { - float time = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - - Ogre::Vector3 trans = Ogre::Vector3(x, y, z); - translist1.push_back(trans); - transtime.push_back(time); - } - //nif->getFloatLen(count*4); // time + translation - } - else if(ttype == 2) - { - //Example - node 116 in base_anim.nif - for(int i = 0; i < count; i++) - { - float time = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - float x2 = nif->getFloat(); - float y2 = nif->getFloat(); - float z2 = nif->getFloat(); - float x3 = nif->getFloat(); - float y3 = nif->getFloat(); - float z3 = nif->getFloat(); - - Ogre::Vector3 trans = Ogre::Vector3(x, y, z); - Ogre::Vector3 trans2 = Ogre::Vector3(x2, y2, z2); - Ogre::Vector3 trans3 = Ogre::Vector3(x3, y3, z3); - transtime.push_back(time); - translist1.push_back(trans); - translist2.push_back(trans2); - translist3.push_back(trans3); - } - - //nif->getFloatLen(count*10); // trans1 + forward + backward - } - else if(ttype == 3) - { - for(int i = 0; i < count; i++) - { - float time = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - float t = nif->getFloat(); - float b = nif->getFloat(); - float c = nif->getFloat(); - Ogre::Vector3 trans = Ogre::Vector3(x, y, z); - Ogre::Vector3 tbc = Ogre::Vector3(t, b, c); - translist1.push_back(trans); - transtbc.push_back(tbc); - transtime.push_back(time); - } - //nif->getFloatLen(count*7); // trans1 + tension,bias,continuity - } - else nif->fail("Unknown translation type"); - } - - // Finally, scalings - count = nif->getInt(); - if(count) - { - stype = nif->getInt(); - - for(int i = 0; i < count; i++) - { - //int size = 0; - if(stype >= 1 && stype < 4) - { - float time = nif->getFloat(); - float scale = nif->getFloat(); - scaletime.push_back(time); - scalefactor.push_back(scale); - //size = 2; // time+scale - } - else - nif->fail("Unknown scaling type"); - - if(stype == 2) - { - //size = 4; // 1 + forward + backward (floats) - float forward = nif->getFloat(); - float backward = nif->getFloat(); - forwards.push_back(forward); - backwards.push_back(backward); - } - else if(stype == 3) - { - //size = 5; // 1 + tbc - float tbcx = nif->getFloat(); - float tbcy = nif->getFloat(); - float tbcz = nif->getFloat(); - Ogre::Vector3 vec = Ogre::Vector3(tbcx, tbcy, tbcz); - tbcscale.push_back(vec); - } - } - } - else - stype = 0; + mRotations.read(nif); + mTranslations.read(nif); + mScales.read(nif); } - - int getRtype() const - { return rtype; } - int getStype() const - { return stype; } - int getTtype() const - { return ttype; } - float getStartTime() const - { return startTime; } - float getStopTime() const - { return stopTime; } - const std::vector& getQuat() const - { return quats; } - const std::vector& getrTbc() const - { return tbc; } - const std::vector& getrTime() const - { return rottime; } - - const std::vector& getTranslist1() const - { return translist1; } - const std::vector& getTranslist2() const - { return translist2; } - const std::vector& getTranslist3() const - { return translist3; } - const std::vector& gettTime() const - { return transtime; } - const std::vector& getScalefactor() const - { return scalefactor; } - const std::vector& getForwards() const - { return forwards; } - const std::vector& getBackwards() const - { return backwards; } - const std::vector& getScaleTbc() const - { return tbcscale; } - - const std::vector& getsTime() const - { return scaletime; } - const std::string& getBonename() const - { return bonename; } }; } // Namespace From 9436ca4b0cea93fcd53cba5884d360518cfe1bf9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Jul 2012 09:32:58 -0700 Subject: [PATCH 13/92] Use vectors for ShapeData properties --- components/nif/data.hpp | 16 ++++++++----- components/nif/nif_file.hpp | 26 ++++++++++++++++++++++ components/nifbullet/bullet_nif_loader.cpp | 17 ++++++-------- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 208337f35..d08ba7b32 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -96,7 +96,9 @@ public: class ShapeData : public Record { public: - std::vector vertices, normals, colors, uvlist; + std::vector vertices, normals; + std::vector colors; + std::vector< std::vector > uvlist; Ogre::Vector3 center; float radius; @@ -105,16 +107,16 @@ public: int verts = nif->getUShort(); if(nif->getInt()) - nif->getFloats(vertices, verts*3); + nif->getVector3s(vertices, verts); if(nif->getInt()) - nif->getFloats(normals, verts*3); + nif->getVector3s(normals, verts); center = nif->getVector3(); radius = nif->getFloat(); if(nif->getInt()) - nif->getFloats(colors, verts*4); + nif->getVector4s(colors, verts); // Only the first 6 bits are used as a count. I think the rest are // flags of some sort. @@ -122,7 +124,11 @@ public: uvs &= 0x3f; if(nif->getInt()) - nif->getFloats(uvlist, uvs*verts*2); + { + uvlist.resize(uvs); + for(int i = 0;i < uvs;i++) + nif->getVector2s(uvlist[i], verts); + } } }; diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index c33790742..f6c23ec9a 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -142,6 +143,13 @@ public: unsigned short getUShort() { return read_le16(); } int getInt() { return read_le32(); } float getFloat() { return read_le32f(); } + Ogre::Vector2 getVector2() + { + float a[2]; + for(size_t i = 0;i < 2;i++) + a[i] = getFloat(); + return Ogre::Vector2(a); + } Ogre::Vector3 getVector3() { float a[3]; @@ -208,6 +216,24 @@ public: for(size_t i = 0;i < vec.size();i++) vec[i] = getFloat(); } + void getVector2s(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector2(); + } + void getVector3s(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector3(); + } + void getVector4s(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector4(); + } }; diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 5f562504b..bdf508f6c 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -271,19 +271,16 @@ void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape *shape, int flags Nif::NiTriShapeData *data = shape->data.getPtr(); - float* vertices = &data->vertices[0]; - short* triangles = &data->triangles[0]; + const std::vector &vertices = data->vertices; const Ogre::Matrix3 &rot = shape->trafo.rotation; const Ogre::Vector3 &pos = shape->trafo.pos; - float scale = shape->trafo.scale; - for(unsigned int i=0; i < data->triangles.size(); i = i+3) + float scale = shape->trafo.scale * parentScale; + short* triangles = &data->triangles[0]; + for(size_t i = 0;i < data->triangles.size();i+=3) { - Ogre::Vector3 b1(vertices[triangles[i+0]*3]*parentScale,vertices[triangles[i+0]*3+1]*parentScale,vertices[triangles[i+0]*3+2]*parentScale); - Ogre::Vector3 b2(vertices[triangles[i+1]*3]*parentScale,vertices[triangles[i+1]*3+1]*parentScale,vertices[triangles[i+1]*3+2]*parentScale); - Ogre::Vector3 b3(vertices[triangles[i+2]*3]*parentScale,vertices[triangles[i+2]*3+1]*parentScale,vertices[triangles[i+2]*3+2]*parentScale); - b1 = pos + rot*b1*scale; - b2 = pos + rot*b2*scale; - b3 = pos + rot*b3*scale; + Ogre::Vector3 b1 = pos + rot*vertices[triangles[i+0]]*scale; + Ogre::Vector3 b2 = pos + rot*vertices[triangles[i+1]]*scale; + Ogre::Vector3 b3 = pos + rot*vertices[triangles[i+2]]*scale; mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); } } From fdfe40a55a3bf0744cb7fb3a6d548c0eb35e34e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Jul 2012 13:41:08 -0700 Subject: [PATCH 14/92] Use a different loader object for each NIF mesh --- components/nifogre/ogre_nif_loader.cpp | 6 ++++-- components/nifogre/ogre_nif_loader.hpp | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 883cf7fce..efe9ddea6 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -128,6 +128,8 @@ public: }; +NIFLoader::LoaderMap NIFLoader::sLoaders; + void NIFLoader::warn(const std::string &msg) { std::cerr << "NIFLoader: Warn:" << msg << "\n"; @@ -331,8 +333,8 @@ Ogre::MeshPtr NIFLoader::load(const std::string &name, const std::string &group) Ogre::MeshPtr themesh = meshMgr.getByName(name, group); if(themesh.isNull()) { - static NIFLoader loader; - themesh = meshMgr.createManual(name, group, &loader); + NIFLoader *loader = &sLoaders[name]; + themesh = meshMgr.createManual(name, group, loader); } return themesh; } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index bc1ef304c..985c64e0d 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -41,7 +41,7 @@ #include #include -#include +#include // For warning messages #include using namespace boost::algorithm; @@ -90,11 +90,11 @@ public: const std::string &group="General"); private: - NIFLoader() {} - NIFLoader(NIFLoader& n) {} - void warn(const std::string &msg); void fail(const std::string &msg); + + typedef std::map LoaderMap; + static LoaderMap sLoaders; }; } From 939d0d2fc5b4a1a8d78e708ed7c519a2ca5416e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Jul 2012 18:25:35 -0700 Subject: [PATCH 15/92] Return a list of meshes and the skeleton from NIFLoader::load --- apps/openmw/mwrender/creatureanimation.cpp | 5 +- apps/openmw/mwrender/npcanimation.cpp | 12 +- apps/openmw/mwrender/objects.cpp | 5 +- apps/openmw/mwrender/sky.cpp | 206 +++++++++++---------- apps/openmw/mwrender/sky.hpp | 5 +- components/nifogre/ogre_nif_loader.cpp | 12 +- components/nifogre/ogre_nif_loader.hpp | 20 +- 7 files changed, 146 insertions(+), 119 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 6bdd58ac3..0690a7be7 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,8 +26,9 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O { std::string mesh = "meshes\\" + ref->base->model; - NifOgre::NIFLoader::load(mesh); - base = mRend.getScene()->createEntity(mesh); + // FIXME: There can be more than one! + NifOgre::MeshPairList meshes = NifOgre::NIFLoader::load(mesh); + base = mRend.getScene()->createEntity(meshes[0].first->getName()); base->setVisibilityFlags(RV_Actors); bool transparent = false; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index fa33d18ff..d6600bc1b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -82,8 +82,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere assert(insert); std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - NifOgre::NIFLoader::load(smodel); - base = mRend.getScene()->createEntity(smodel); + + // FIXME: There can be more than one! + NifOgre::MeshPairList meshes = NifOgre::NIFLoader::load(smodel); + base = mRend.getScene()->createEntity(meshes[0].first->getName()); base->setVisibilityFlags(RV_Actors); bool transparent = false; @@ -382,9 +384,9 @@ void NpcAnimation::updateParts() Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, const std::string &bonename) { - - NIFLoader::load(mesh); - Ogre::Entity* part = mRend.getScene()->createEntity(mesh); + // FIXME: There can be more than one! + NifOgre::MeshPairList meshes = NIFLoader::load(mesh); + Ogre::Entity* part = mRend.getScene()->createEntity(meshes[0].first->getName()); part->setVisibilityFlags(RV_Actors); base->attachObjectToBone(bonename, part); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index fb2bfb3c5..ea58ec716 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -92,8 +92,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) Ogre::SceneNode* insert = ptr.getRefData().getBaseNode(); assert(insert); - NifOgre::NIFLoader::load(mesh); - Ogre::Entity *ent = mRenderer.getScene()->createEntity(mesh); + // FIXME: There can be more than one! + NifOgre::MeshPairList meshes = NifOgre::NIFLoader::load(mesh); + Ogre::Entity *ent = mRenderer.getScene()->createEntity(meshes[0].first->getName()); Ogre::Vector3 extents = ent->getBoundingBox().getSize(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 45e48240b..8f49e03df 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -453,16 +453,6 @@ void SkyManager::create() HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); // Stars - /// \todo sky_night_02.nif (available in Bloodmoon) - MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif"); - Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif"); - night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); - night1_ent->setVisibilityFlags(RV_Sky); - night1_ent->setCastShadows(false); - - mAtmosphereNight = mRootNode->createChildSceneNode(); - mAtmosphereNight->attachObject(night1_ent); - // Stars vertex shader HighLevelGpuProgramPtr stars_vp = mgr.createProgram("Stars_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM); @@ -517,35 +507,35 @@ void SkyManager::create() stars_fp->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); stars_fp->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR); - for (unsigned int i=0; igetNumSubEntities(); ++i) + /// \todo sky_night_02.nif (available in Bloodmoon) + mAtmosphereNight = mRootNode->createChildSceneNode(); + NifOgre::MeshPairList meshes = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif"); + for(size_t i = 0;i < meshes.size();i++) { - MaterialPtr mp = night1_ent->getSubEntity(i)->getMaterial(); - mp->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0); - mp->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0); - mp->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 1.0); - mp->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - mp->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - mp->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); - mp->getTechnique(0)->getPass(0)->setVertexProgram(stars_vp->getName()); - mp->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName()); - mp->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); - mStarsMaterials[i] = mp; + Entity* night1_ent = mSceneMgr->createEntity(meshes[i].first->getName()); + night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); + night1_ent->setVisibilityFlags(RV_Sky); + night1_ent->setCastShadows(false); + + mAtmosphereNight->attachObject(night1_ent); + + for (unsigned int i=0; igetNumSubEntities(); ++i) + { + MaterialPtr mp = night1_ent->getSubEntity(i)->getMaterial(); + mp->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0); + mp->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0); + mp->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 1.0); + mp->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); + mp->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); + mp->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); + mp->getTechnique(0)->getPass(0)->setVertexProgram(stars_vp->getName()); + mp->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName()); + mp->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); + mStarsMaterials.push_back(mp); + } } // Atmosphere (day) - mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif"); - Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif"); - atmosphere_ent->setCastShadows(false); - - ModVertexAlpha(atmosphere_ent, 0); - - atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); - atmosphere_ent->setVisibilityFlags(RV_Sky); - mAtmosphereDay = mRootNode->createChildSceneNode(); - mAtmosphereDay->attachObject(atmosphere_ent); - mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial(); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); - // Atmosphere shader HighLevelGpuProgramPtr vshader = mgr.createProgram("Atmosphere_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM); @@ -555,22 +545,21 @@ void SkyManager::create() StringUtil::StrStreamType outStream; outStream << - "void main_vp( \n" - " float4 position : POSITION, \n" - " in float4 color : COLOR, \n" - " out float4 oPosition : POSITION, \n" - " out float4 oVertexColor : TEXCOORD0, \n" - " uniform float4x4 worldViewProj \n" - ") \n" - "{ \n" - " oPosition = mul( worldViewProj, position ); \n" + "void main_vp( \n" + " float4 position : POSITION, \n" + " in float4 color : COLOR, \n" + " out float4 oPosition : POSITION, \n" + " out float4 oVertexColor : TEXCOORD0, \n" + " uniform float4x4 worldViewProj \n" + ") \n" + "{ \n" + " oPosition = mul( worldViewProj, position ); \n" " oVertexColor = color; \n" "}"; vshader->setSource(outStream.str()); vshader->load(); vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName()); HighLevelGpuProgramPtr fshader = mgr.createProgram("Atmosphere_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_FRAGMENT_PROGRAM); @@ -580,15 +569,15 @@ void SkyManager::create() StringUtil::StrStreamType _outStream; _outStream << - "void main_fp( \n" - " in float4 iVertexColor : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n"; + "void main_fp( \n" + " in float4 iVertexColor : TEXCOORD0, \n" + " out float4 oColor : COLOR, \n"; if (RenderingManager::useMRT()) _outStream << " out float4 oColor1 : COLOR1, \n"; _outStream << " uniform float4 emissive \n" - ") \n" - "{ \n" + ") \n" + "{ \n" " oColor = iVertexColor * emissive; \n"; if (RenderingManager::useMRT()) _outStream << " oColor1 = float4(1, 0, 0, 1); \n"; @@ -598,19 +587,36 @@ void SkyManager::create() fshader->load(); fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName()); + + mAtmosphereDay = mRootNode->createChildSceneNode(); + meshes = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif"); + for(size_t i = 0;i < meshes.size();i++) + { + Entity* atmosphere_ent = mSceneMgr->createEntity(meshes[i].first->getName()); + atmosphere_ent->setCastShadows(false); + + ModVertexAlpha(atmosphere_ent, 0); + + atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); + atmosphere_ent->setVisibilityFlags(RV_Sky); + mAtmosphereDay->attachObject(atmosphere_ent); + + mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial(); + mAtmosphereMaterial = mAtmosphereMaterial->clone("Atmosphere"); + atmosphere_ent->getSubEntity(0)->setMaterial(mAtmosphereMaterial); + + mAtmosphereMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName()); + mAtmosphereMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName()); + + mAtmosphereMaterial->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); + mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0); + mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 0.0); + mAtmosphereMaterial->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0); + mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); + mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); + } // Clouds - NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif"); - Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif"); - clouds_ent->setVisibilityFlags(RV_Sky); - clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); - SceneNode* clouds_node = mRootNode->createChildSceneNode(); - clouds_node->attachObject(clouds_ent); - mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial(); - mCloudMaterial->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); - clouds_ent->setCastShadows(false); - // Clouds vertex shader HighLevelGpuProgramPtr vshader2 = mgr.createProgram("Clouds_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM); @@ -618,24 +624,23 @@ void SkyManager::create() vshader2->setParameter("entry_point", "main_vp"); StringUtil::StrStreamType outStream3; outStream3 << - "void main_vp( \n" - " float4 position : POSITION, \n" - " in float4 color : COLOR, \n" + "void main_vp( \n" + " float4 position : POSITION, \n" + " in float4 color : COLOR, \n" " out float4 oColor : TEXCOORD1, \n" " in float2 uv : TEXCOORD0, \n" " out float2 oUV : TEXCOORD0, \n" - " out float4 oPosition : POSITION, \n" - " uniform float4x4 worldViewProj \n" - ") \n" - "{ \n" + " out float4 oPosition : POSITION, \n" + " uniform float4x4 worldViewProj \n" + ") \n" + "{ \n" " oUV = uv; \n" " oColor = color; \n" - " oPosition = mul( worldViewProj, position ); \n" + " oPosition = mul( worldViewProj, position ); \n" "}"; vshader2->setSource(outStream3.str()); vshader2->load(); vshader2->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - mCloudMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader2->getName()); // Clouds fragment shader mCloudFragmentShader = mgr.createProgram("Clouds_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, @@ -644,10 +649,10 @@ void SkyManager::create() mCloudFragmentShader->setParameter("entry_point", "main_fp"); StringUtil::StrStreamType outStream2; outStream2 << - "void main_fp( \n" + "void main_fp( \n" " in float2 uv : TEXCOORD0, \n" " in float4 color : TEXCOORD1, \n" - " out float4 oColor : COLOR, \n"; + " out float4 oColor : COLOR, \n"; if (RenderingManager::useMRT()) outStream2 << " out float4 oColor1 : COLOR1, \n"; outStream2 << @@ -658,8 +663,8 @@ void SkyManager::create() " uniform float speed, \n" " uniform float opacity, \n" " uniform float4 emissive \n" - ") \n" - "{ \n" + ") \n" + "{ \n" " uv += float2(0,1) * time * speed * 0.003; \n" // Scroll in y direction " float4 tex = lerp(tex2D(texture, uv), tex2D(secondTexture, uv), transitionFactor); \n" " oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n"; @@ -670,31 +675,36 @@ void SkyManager::create() mCloudFragmentShader->setSource(outStream2.str()); mCloudFragmentShader->load(); mCloudFragmentShader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); - mCloudMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(mCloudFragmentShader->getName()); + + SceneNode* clouds_node = mRootNode->createChildSceneNode(); + meshes = NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif"); + for(size_t i = 0;i < meshes.size();i++) + { + Entity* clouds_ent = mSceneMgr->createEntity(meshes[i].first->getName()); + clouds_ent->setVisibilityFlags(RV_Sky); + clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); + clouds_node->attachObject(clouds_ent); + + mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial(); + mCloudMaterial = mCloudMaterial->clone("Clouds"); + clouds_ent->getSubEntity(0)->setMaterial(mCloudMaterial); + + mCloudMaterial->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); + clouds_ent->setCastShadows(false); + + mCloudMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader2->getName()); + mCloudMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(mCloudFragmentShader->getName()); + ModVertexAlpha(clouds_ent, 1); + + mCloudMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0); + mCloudMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); + mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); + mCloudMaterial->getTechnique(0)->getPass(0)->removeAllTextureUnitStates(); + mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("textures\\tx_sky_cloudy.dds"); + mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(""); + } setCloudsOpacity(0.75); - ModVertexAlpha(clouds_ent, 1); - - // I'm not sure if the materials are being used by any other objects - // Make a unique "modifiable" copy of the materials to be sure - mCloudMaterial = mCloudMaterial->clone("Clouds"); - clouds_ent->getSubEntity(0)->setMaterial(mCloudMaterial); - mAtmosphereMaterial = mAtmosphereMaterial->clone("Atmosphere"); - atmosphere_ent->getSubEntity(0)->setMaterial(mAtmosphereMaterial); - - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 0.0); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0); - mCloudMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0); - mCloudMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); - mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); - - mCloudMaterial->getTechnique(0)->getPass(0)->removeAllTextureUnitStates(); - mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("textures\\tx_sky_cloudy.dds"); - mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(""); - mCreated = true; } @@ -851,7 +861,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) else { mAtmosphereNight->setVisible(true); - for (int i=0; i<7; ++i) + for (size_t i=0; igetTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, weather.mNightFade); mStarsOpacity = weather.mNightFade; } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index e11745e82..7b7cc2d16 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -1,13 +1,14 @@ #ifndef _GAME_RENDER_SKY_H #define _GAME_RENDER_SKY_H +#include + #include #include #include #include #include -#include "sky.hpp" #include "../mwworld/weather.hpp" namespace Ogre @@ -195,7 +196,7 @@ namespace MWRender Ogre::MaterialPtr mCloudMaterial; Ogre::MaterialPtr mAtmosphereMaterial; - Ogre::MaterialPtr mStarsMaterials[7]; + std::vector mStarsMaterials; Ogre::HighLevelGpuProgramPtr mCloudFragmentShader; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index efe9ddea6..a479e78a5 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -322,12 +322,16 @@ void NIFLoader::createMaterial(const Ogre::String &name, void NIFLoader::loadResource(Ogre::Resource *resource) { - warn("Found no records in NIF."); + warn("Found no records in NIF for "+resource->getName()); } -Ogre::MeshPtr NIFLoader::load(const std::string &name, const std::string &group) +MeshPairList NIFLoader::load(const std::string &name, Ogre::SkeletonPtr *skel, const std::string &group) { Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + MeshPairList ret; + + if(skel != NULL) + skel->setNull(); // Check if the resource already exists Ogre::MeshPtr themesh = meshMgr.getByName(name, group); @@ -336,7 +340,9 @@ Ogre::MeshPtr NIFLoader::load(const std::string &name, const std::string &group) NIFLoader *loader = &sLoaders[name]; themesh = meshMgr.createManual(name, group, loader); } - return themesh; + ret.push_back(std::make_pair(themesh, std::string())); + + return ret; } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 985c64e0d..1eef7eb37 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -67,6 +68,12 @@ namespace Nif namespace NifOgre { + +/** This holds a list of meshes along with the names of their parent nodes + */ +typedef std::vector< std::pair > MeshPairList; + + /** Manual resource loader for NIF meshes. This is the main class responsible for translating the internal NIF mesh structure into something Ogre can use. @@ -75,19 +82,18 @@ namespace NifOgre NIFLoader::load("somemesh.nif"); - Afterwards, you can use the mesh name "somemesh.nif" normally to - create entities and so on. The mesh isn't loaded from disk until - OGRE needs it for rendering. Thus the above load() command is not - very resource intensive, and can safely be done for a large number - of meshes at load time. + This returns a list of meshes used by the model, as well as the names of + their parent nodes (as they pertain to the skeleton, which is optionally + returned in the second argument if it exists). */ class NIFLoader : Ogre::ManualResourceLoader { public: virtual void loadResource(Ogre::Resource *resource); - static Ogre::MeshPtr load(const std::string &name, - const std::string &group="General"); + static MeshPairList load(const std::string &name, + Ogre::SkeletonPtr *skel=NULL, + const std::string &group="General"); private: void warn(const std::string &msg); From 5a381006e52e6815f4f86f8eeec09f6c1e8c15eb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Jul 2012 09:20:09 -0700 Subject: [PATCH 16/92] Fix parsing of some key lists It seems some still want you to read the interpolation type even when there's no keys. --- components/nif/data.hpp | 4 ++-- components/nif/nif_file.hpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index d08ba7b32..63df23b27 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -394,9 +394,9 @@ struct NiMorphData : public Record nif->getChar(); mMorphs.resize(morphCount); - for(int i=0; igetInt(); - if(count == 0) return; + if(count == 0 && !force) + return; mInterpolationType = nif->getInt(); mKeys.resize(count); From 6a447c88fb8349e17846dde2ef0d83c2fe24be58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jul 2012 06:45:21 -0700 Subject: [PATCH 17/92] Create meshes from the NiTriShapes in the NIF. This doesn't actually load them yet. It's also very slow for certain NIFs. --- components/nifogre/ogre_nif_loader.cpp | 72 ++++++++++++++++++++++---- components/nifogre/ogre_nif_loader.hpp | 9 +++- 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index a479e78a5..40740ac56 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -132,13 +132,13 @@ NIFLoader::LoaderMap NIFLoader::sLoaders; void NIFLoader::warn(const std::string &msg) { - std::cerr << "NIFLoader: Warn:" << msg << "\n"; + std::cerr << "NIFLoader: Warn: " << msg << std::endl; } void NIFLoader::fail(const std::string &msg) { std::cerr << "NIFLoader: Fail: "<< msg << std::endl; - assert(1); + abort(); } @@ -325,24 +325,74 @@ void NIFLoader::loadResource(Ogre::Resource *resource) warn("Found no records in NIF for "+resource->getName()); } +void NIFLoader::createMeshes(const std::string &name, const std::string &group, Nif::Node *node, MeshPairList &meshes, int flags) +{ + flags |= node->flags; + + // TODO: Check for extra data + + if(node->recType == Nif::RC_NiTriShape) + { + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + std::string fullname = name+"@"+node->name; + + Ogre::MeshPtr mesh = meshMgr.getByName(fullname); + if(mesh.isNull()) + { + NIFLoader *loader = &sLoaders[fullname]; + loader->mName = name; + loader->mShapeName = node->name; + + mesh = meshMgr.createManual(fullname, group, loader); + } + + meshes.push_back(std::make_pair(mesh, (node->parent ? node->parent->name : std::string()))); + } + else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && + node->recType != Nif::RC_NiRotatingParticles) + warn("Unhandled mesh node type: "+node->recName); + + Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + createMeshes(name, group, children[i].getPtr(), meshes, flags); + } + } +} + MeshPairList NIFLoader::load(const std::string &name, Ogre::SkeletonPtr *skel, const std::string &group) { - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - MeshPairList ret; + MeshPairList meshes; if(skel != NULL) skel->setNull(); - // Check if the resource already exists - Ogre::MeshPtr themesh = meshMgr.getByName(name, group); - if(themesh.isNull()) + Nif::NIFFile nif(name); + if (nif.numRecords() < 1) { - NIFLoader *loader = &sLoaders[name]; - themesh = meshMgr.createManual(name, group, loader); + nif.warn("Found no records in NIF."); + return meshes; } - ret.push_back(std::make_pair(themesh, std::string())); - return ret; + // The first record is assumed to be the root node + Nif::Record *r = nif.getRecord(0); + assert(r != NULL); + + Nif::Node *node = dynamic_cast(r); + if(node == NULL) + { + nif.warn("First record in file was not a node, but a "+ + r->recName+". Skipping file."); + return meshes; + } + + createMeshes(name, group, node, meshes); + + return meshes; } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 1eef7eb37..092cc23a8 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -96,8 +96,13 @@ public: const std::string &group="General"); private: - void warn(const std::string &msg); - void fail(const std::string &msg); + std::string mName; + std::string mShapeName; + + static void warn(const std::string &msg); + static void fail(const std::string &msg); + + static void createMeshes(const std::string &name, const std::string &group, Nif::Node *node, MeshPairList &meshes, int flags=0); typedef std::map LoaderMap; static LoaderMap sLoaders; From 300730a834d49b25f52d7002b737062070e88b93 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jul 2012 11:11:49 -0700 Subject: [PATCH 18/92] Create the skeleton resource from NIFs Note they are not loaded yet. --- components/nifogre/ogre_nif_loader.cpp | 64 ++++++++++++++++++++++++-- components/nifogre/ogre_nif_loader.hpp | 4 +- 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 40740ac56..99ccb7fb1 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -128,6 +128,60 @@ public: }; +struct NIFSkeletonLoader : public Ogre::ManualResourceLoader { + +static void warn(const std::string &msg) +{ + std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; +} + +static void fail(const std::string &msg) +{ + std::cerr << "NIFSkeletonLoader: Fail: "<< msg << std::endl; + abort(); +} + +void loadResource(Ogre::Resource *resource) +{ + warn("Found no records in NIF for "+resource->getName()); +} + +static bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node, Ogre::SkeletonPtr *skel) +{ + if(node->boneTrafo != NULL) + { + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + + Ogre::SkeletonPtr tmp = skelMgr.getByName(name); + if(tmp.isNull()) + { + static NIFSkeletonLoader loader; + tmp = skelMgr.create(name, group, true, &loader); + } + + if(skel) *skel = tmp; + return true; + } + + Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + { + if(createSkeleton(name, group, children[i].getPtr(), skel)) + return true; + } + } + } + return false; +} + +}; + + NIFLoader::LoaderMap NIFLoader::sLoaders; void NIFLoader::warn(const std::string &msg) @@ -325,7 +379,8 @@ void NIFLoader::loadResource(Ogre::Resource *resource) warn("Found no records in NIF for "+resource->getName()); } -void NIFLoader::createMeshes(const std::string &name, const std::string &group, Nif::Node *node, MeshPairList &meshes, int flags) + +void NIFLoader::createMeshes(const std::string &name, const std::string &group, bool hasSkel, Nif::Node *node, MeshPairList &meshes, int flags) { flags |= node->flags; @@ -342,6 +397,7 @@ void NIFLoader::createMeshes(const std::string &name, const std::string &group, NIFLoader *loader = &sLoaders[fullname]; loader->mName = name; loader->mShapeName = node->name; + loader->mHasSkel = hasSkel; mesh = meshMgr.createManual(fullname, group, loader); } @@ -359,11 +415,12 @@ void NIFLoader::createMeshes(const std::string &name, const std::string &group, for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createMeshes(name, group, children[i].getPtr(), meshes, flags); + createMeshes(name, group, hasSkel, children[i].getPtr(), meshes, flags); } } } + MeshPairList NIFLoader::load(const std::string &name, Ogre::SkeletonPtr *skel, const std::string &group) { MeshPairList meshes; @@ -390,7 +447,8 @@ MeshPairList NIFLoader::load(const std::string &name, Ogre::SkeletonPtr *skel, c return meshes; } - createMeshes(name, group, node, meshes); + bool hasSkel = NIFSkeletonLoader::createSkeleton(name, group, node, skel); + createMeshes(name, group, hasSkel, node, meshes); return meshes; } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 092cc23a8..c90d65395 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -98,11 +98,13 @@ public: private: std::string mName; std::string mShapeName; + bool mHasSkel; static void warn(const std::string &msg); static void fail(const std::string &msg); - static void createMeshes(const std::string &name, const std::string &group, Nif::Node *node, MeshPairList &meshes, int flags=0); + static void createMeshes(const std::string &name, const std::string &group, bool hasSkel, + Nif::Node *node, MeshPairList &meshes, int flags=0); typedef std::map LoaderMap; static LoaderMap sLoaders; From 69ed73399ab367c445372d6a1610785e3e122502 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jul 2012 11:37:36 -0700 Subject: [PATCH 19/92] Avoid exposing the NIF mesh resource loading class --- components/nifogre/ogre_nif_loader.cpp | 120 ++++++++++++++----------- components/nifogre/ogre_nif_loader.hpp | 18 +--- 2 files changed, 70 insertions(+), 68 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 99ccb7fb1..079e6425b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -182,20 +182,6 @@ static bool createSkeleton(const std::string &name, const std::string &group, Ni }; -NIFLoader::LoaderMap NIFLoader::sLoaders; - -void NIFLoader::warn(const std::string &msg) -{ - std::cerr << "NIFLoader: Warn: " << msg << std::endl; -} - -void NIFLoader::fail(const std::string &msg) -{ - std::cerr << "NIFLoader: Fail: "<< msg << std::endl; - abort(); -} - - // Conversion of blend / test mode from NIF -> OGRE. // Not in use yet, so let's comment it out. /* @@ -374,51 +360,81 @@ void NIFLoader::createMaterial(const Ogre::String &name, #endif -void NIFLoader::loadResource(Ogre::Resource *resource) +class NIFMeshLoader : Ogre::ManualResourceLoader { - warn("Found no records in NIF for "+resource->getName()); -} + std::string mName; + std::string mGroup; + std::string mShapeName; + bool mHasSkel; - -void NIFLoader::createMeshes(const std::string &name, const std::string &group, bool hasSkel, Nif::Node *node, MeshPairList &meshes, int flags) -{ - flags |= node->flags; - - // TODO: Check for extra data - - if(node->recType == Nif::RC_NiTriShape) + void warn(const std::string &msg) { - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - std::string fullname = name+"@"+node->name; - - Ogre::MeshPtr mesh = meshMgr.getByName(fullname); - if(mesh.isNull()) - { - NIFLoader *loader = &sLoaders[fullname]; - loader->mName = name; - loader->mShapeName = node->name; - loader->mHasSkel = hasSkel; - - mesh = meshMgr.createManual(fullname, group, loader); - } - - meshes.push_back(std::make_pair(mesh, (node->parent ? node->parent->name : std::string()))); + std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; } - else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && - node->recType != Nif::RC_NiRotatingParticles) - warn("Unhandled mesh node type: "+node->recName); - Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) + void fail(const std::string &msg) { - Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) + std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + abort(); + } + + + typedef std::map LoaderMap; + static LoaderMap sLoaders; + +public: + NIFMeshLoader() + : mHasSkel(false) + { } + NIFMeshLoader(const std::string &name, const std::string &group, bool hasSkel) + : mName(name), mGroup(group), mHasSkel(hasSkel) + { } + + virtual void loadResource(Ogre::Resource *resource) + { + warn("Found no records in NIF for "+resource->getName()); + } + + void createMeshes(Nif::Node *node, MeshPairList &meshes, int flags=0) + { + flags |= node->flags; + + // TODO: Check for extra data + + if(node->recType == Nif::RC_NiTriShape) { - if(!children[i].empty()) - createMeshes(name, group, hasSkel, children[i].getPtr(), meshes, flags); + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + std::string fullname = mName+"@"+node->name; + + Ogre::MeshPtr mesh = meshMgr.getByName(fullname); + if(mesh.isNull()) + { + NIFMeshLoader *loader = &sLoaders[fullname]; + *loader = *this; + loader->mShapeName = node->name; + + mesh = meshMgr.createManual(fullname, mGroup, loader); + } + + meshes.push_back(std::make_pair(mesh, (node->parent ? node->parent->name : std::string()))); + } + else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && + node->recType != Nif::RC_NiRotatingParticles) + warn("Unhandled mesh node type: "+node->recName); + + Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + createMeshes(children[i].getPtr(), meshes, flags); + } } } -} +}; +NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; MeshPairList NIFLoader::load(const std::string &name, Ogre::SkeletonPtr *skel, const std::string &group) @@ -448,7 +464,9 @@ MeshPairList NIFLoader::load(const std::string &name, Ogre::SkeletonPtr *skel, c } bool hasSkel = NIFSkeletonLoader::createSkeleton(name, group, node, skel); - createMeshes(name, group, hasSkel, node, meshes); + + NIFMeshLoader meshldr(name, group, hasSkel); + meshldr.createMeshes(node, meshes); return meshes; } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index c90d65395..431af1163 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -86,28 +86,12 @@ typedef std::vector< std::pair > MeshPairList; their parent nodes (as they pertain to the skeleton, which is optionally returned in the second argument if it exists). */ -class NIFLoader : Ogre::ManualResourceLoader +class NIFLoader { public: - virtual void loadResource(Ogre::Resource *resource); - static MeshPairList load(const std::string &name, Ogre::SkeletonPtr *skel=NULL, const std::string &group="General"); - -private: - std::string mName; - std::string mShapeName; - bool mHasSkel; - - static void warn(const std::string &msg); - static void fail(const std::string &msg); - - static void createMeshes(const std::string &name, const std::string &group, bool hasSkel, - Nif::Node *node, MeshPairList &meshes, int flags=0); - - typedef std::map LoaderMap; - static LoaderMap sLoaders; }; } From 9028cfe83c707a95c0c1e9a8582eb05936d931d8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jul 2012 12:02:47 -0700 Subject: [PATCH 20/92] Look for the NiTriShape when the mesh resource wants to load It's still not loaded yet. --- components/nifogre/ogre_nif_loader.cpp | 32 +++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 079e6425b..6896ac8fb 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -379,6 +379,31 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } + bool findTriShape(Ogre::Mesh *mesh, Nif::Node *node) + { + if(node->recType == Nif::RC_NiTriShape && mShapeName == node->name) + { + warn("Not loading shape \""+mShapeName+"\" in "+mName); + return true; + } + + Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + { + if(findTriShape(mesh, children[i].getPtr())) + return true; + } + } + } + return false; + } + + typedef std::map LoaderMap; static LoaderMap sLoaders; @@ -392,7 +417,12 @@ public: virtual void loadResource(Ogre::Resource *resource) { - warn("Found no records in NIF for "+resource->getName()); + Ogre::Mesh *mesh = dynamic_cast(resource); + assert(mesh && "Attempting to load a mesh into a non-mesh resource!"); + + Nif::NIFFile nif(mName); + Nif::Node *node = dynamic_cast(nif.getRecord(0)); + findTriShape(mesh, node); } void createMeshes(Nif::Node *node, MeshPairList &meshes, int flags=0) From 3029c221efb8cc6070196eef806712e8e538c388 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jul 2012 12:59:39 -0700 Subject: [PATCH 21/92] Create materials when creating meshes --- components/nifogre/ogre_nif_loader.cpp | 148 ++++++++++++++++++++++--- 1 file changed, 131 insertions(+), 17 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 6896ac8fb..b0e92d82f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -226,26 +226,131 @@ static CompareFunction getTestMode(int mode) } */ -#if 0 -void NIFLoader::createMaterial(const Ogre::String &name, - const Ogre::Vector3 &ambient, - const Ogre::Vector3 &diffuse, - const Ogre::Vector3 &specular, - const Ogre::Vector3 &emissive, - float glossiness, float alpha, - int alphaFlags, float alphaTest, - const Ogre::String &texName) -{ - Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create(name, resourceGroup); +class NIFMaterialLoader { + +static std::multimap MaterialMap; + +static void warn(const std::string &msg) +{ + std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; +} + +static void fail(const std::string &msg) +{ + std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + abort(); +} + +public: +static Ogre::String getMaterial(const NiTriShape *shape, const Ogre::String &name, const Ogre::String &group) +{ + Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); + Ogre::MaterialPtr material = matMgr.getByName(name); + if(!material.isNull()) + return name; + + Ogre::Vector3 ambient(1.0f); + Ogre::Vector3 diffuse(1.0f); + Ogre::Vector3 specular(0.0f); + Ogre::Vector3 emissive(0.0f); + float glossiness = 0.0f; + float alpha = 1.0f; + int alphaFlags = -1; + ubyte alphaTest = 0; + Ogre::String texName; + + // These are set below if present + const NiTexturingProperty *t = NULL; + const NiMaterialProperty *m = NULL; + const NiAlphaProperty *a = NULL; + + // Scan the property list for material information + const PropertyList &list = shape->props; + for (size_t i = 0;i < list.length();i++) + { + // Entries may be empty + if (list[i].empty()) continue; + + const Property *pr = list[i].getPtr(); + if (pr->recType == RC_NiTexturingProperty) + t = static_cast(pr); + else if (pr->recType == RC_NiMaterialProperty) + m = static_cast(pr); + else if (pr->recType == RC_NiAlphaProperty) + a = static_cast(pr); + else + warn("Skipped property type: "+pr->recName); + } + + // Texture + if (t && t->textures[0].inUse) + { + NiSourceTexture *st = t->textures[0].texture.getPtr(); + if (st->external) + { + /* Bethesda at some at some point converted all their BSA + * textures from tga to dds for increased load speed, but all + * texture file name references were kept as .tga. + */ + texName = "textures\\" + st->filename; + if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) + { + Ogre::String::size_type pos = texName.rfind('.'); + texName.replace(pos, texName.length(), ".dds"); + } + } + else warn("Found internal texture, ignoring."); + } + + // Alpha modifiers + if (a) + { + alphaFlags = a->flags; + alphaTest = a->data.threshold; + } + + // Material + if(m) + { + ambient = m->data.ambient; + diffuse = m->data.diffuse; + specular = m->data.specular; + emissive = m->data.emissive; + glossiness = m->data.glossiness; + alpha = m->data.alpha; + } + + Ogre::String matname = name; + if (m || !texName.empty()) + { + // If we're here, then this mesh has a material. Thus we + // need to calculate a snappy material name. It should + // contain the mesh name (mesh->getName()) but also has to + // be unique. One mesh may use many materials. + std::multimap::iterator itr = MaterialMap.find(texName); + std::multimap::iterator lastElement; + lastElement = MaterialMap.upper_bound(texName); + if (itr != MaterialMap.end()) + { + for ( ; itr != lastElement; ++itr) + { + //std::cout << "OK!"; + //MaterialPtr mat = MaterialManager::getSingleton().getByName(itr->second,recourceGroup); + return itr->second; + //if( mat->getA + } + } + } + + // No existing material like this. Create a new one. + material = matMgr.create(matname, group, true); // This assigns the texture to this material. If the texture name is // a file name, and this file exists (in a resource directory), it // will automatically be loaded when needed. If not (such as for // internal NIF textures that we might support later), we should // already have inserted a manual loader for the texture. - - if (!texName.empty()) { Ogre::Pass *pass = material->getTechnique(0)->getPass(0); @@ -356,8 +461,13 @@ void NIFLoader::createMaterial(const Ogre::String &name, material->setSpecular(specular[0], specular[1], specular[2], alpha); material->setSelfIllumination(emissive[0], emissive[1], emissive[2]); material->setShininess(glossiness); + + MaterialMap.insert(std::make_pair(texName, matname)); + return matname; } -#endif + +}; +std::multimap NIFMaterialLoader::MaterialMap; class NIFMeshLoader : Ogre::ManualResourceLoader @@ -365,6 +475,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mName; std::string mGroup; std::string mShapeName; + std::string mMaterialName; bool mHasSkel; void warn(const std::string &msg) @@ -433,20 +544,23 @@ public: if(node->recType == Nif::RC_NiTriShape) { + NiTriShape *shape = dynamic_cast(node); + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - std::string fullname = mName+"@"+node->name; + std::string fullname = mName+"@"+shape->name; Ogre::MeshPtr mesh = meshMgr.getByName(fullname); if(mesh.isNull()) { NIFMeshLoader *loader = &sLoaders[fullname]; *loader = *this; - loader->mShapeName = node->name; + loader->mShapeName = shape->name; + loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); mesh = meshMgr.createManual(fullname, mGroup, loader); } - meshes.push_back(std::make_pair(mesh, (node->parent ? node->parent->name : std::string()))); + meshes.push_back(std::make_pair(mesh, (shape->parent ? shape->parent->name : std::string()))); } else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && node->recType != Nif::RC_NiRotatingParticles) From 441a5c2da20f595da6fd5d8ad0b98c2f6c4b9f07 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jul 2012 14:12:12 -0700 Subject: [PATCH 22/92] Load NiTriShapes into Ogre meshes --- components/nifogre/ogre_nif_loader.cpp | 173 ++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b0e92d82f..884d8f64e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -490,11 +490,182 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } + // Convert NiTriShape to Ogre::SubMesh + void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape *shape) + { + const Nif::NiTriShapeData *data = shape->data.getPtr(); + const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); + std::vector srcVerts = data->vertices; + std::vector srcNorms = data->normals; + if(skin != NULL) + { +#if 0 + // Convert vertices and normals back to bone space + std::vector newVerts(srcVerts.size(), Vector3(0,0,0)); + std::vector newNorms(srcNorms.size(), Vector3(0,0,0)); + + NiSkinDataRef data = skin->GetSkinData(); + const std::vector &bones = skin->GetBones(); + for(size_t b = 0;b < bones.size();b++) + { + Matrix44 mat = data->GetBoneTransform(b) * bones[b]->GetWorldTransform(); + + const std::vector &weights = data->GetBoneWeights(b); + for(size_t i = 0;i < weights.size();i++) + { + size_t index = weights[i].index; + float weight = weights[i].weight; + + newVerts.at(index) += (mat*srcVerts[index]) * weight; + if(newNorms.size() > index) + { + for(size_t j = 0;j < 3;j++) + { + newNorms[index][j] += mat[0][j]*srcNorms[index][0] * weight; + newNorms[index][j] += mat[1][j]*srcNorms[index][1] * weight; + newNorms[index][j] += mat[2][j]*srcNorms[index][2] * weight; + } + } + } + } + + srcVerts = newVerts; + srcNorms = newNorms; +#endif + } + + // Set the bounding box first + BoundsFinder bounds; + bounds.add(&srcVerts[0][0], srcVerts.size()); + mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX(), bounds.minY(), bounds.minZ(), + bounds.maxX(), bounds.maxY(), bounds.maxZ())); + mesh->_setBoundingSphereRadius(bounds.getRadius()); + + // This function is just one long stream of Ogre-barf, but it works + // great. + Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr(); + Ogre::HardwareVertexBufferSharedPtr vbuf; + Ogre::HardwareIndexBufferSharedPtr ibuf; + Ogre::VertexBufferBinding *bind; + Ogre::VertexDeclaration *decl; + int nextBuf = 0; + + Ogre::SubMesh *sub = mesh->createSubMesh(shape->name); + + // Add vertices + sub->useSharedVertices = false; + sub->vertexData = new Ogre::VertexData(); + sub->vertexData->vertexStart = 0; + sub->vertexData->vertexCount = srcVerts.size(); + + decl = sub->vertexData->vertexDeclaration; + bind = sub->vertexData->vertexBufferBinding; + if(srcVerts.size()) + { + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), + srcVerts.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, + true); + vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); + + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); + bind->setBinding(nextBuf++, vbuf); + } + + // Vertex normals + if(srcNorms.size()) + { + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), + srcNorms.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, + true); + vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); + + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); + bind->setBinding(nextBuf++, vbuf); + } + + // Vertex colors + const std::vector &colors = data->colors; + if(colors.size()) + { + Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); + std::vector colorsRGB(colors.size()); + for(size_t i = 0;i < colorsRGB.size();i++) + { + Ogre::ColourValue clr(colors[i][0], colors[i][1], colors[i][2], colors[i][3]); + rs->convertColourValue(clr, &colorsRGB[i]); + } + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), + colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, + true); + vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); + decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); + bind->setBinding(nextBuf++, vbuf); + } + + // Texture UV coordinates + size_t numUVs = data->uvlist.size(); + if(numUVs) + { + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size()*numUVs, + Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true); + for(size_t i = 0;i < numUVs;i++) + { + const std::vector &uvlist = data->uvlist[i]; + vbuf->writeData(i*srcVerts.size()*elemSize, elemSize*srcVerts.size(), &uvlist[0], true); + decl->addElement(nextBuf, i*srcVerts.size()*elemSize, Ogre::VET_FLOAT2, + Ogre::VES_TEXTURE_COORDINATES, i); + } + bind->setBinding(nextBuf++, vbuf); + } + + // Triangle faces + const std::vector &srcIdx = data->triangles; + if(srcIdx.size()) + { + ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), + Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); + ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); + sub->indexData->indexBuffer = ibuf; + sub->indexData->indexCount = srcIdx.size(); + sub->indexData->indexStart = 0; + } + + // Assign bone weights for this TriShape +#if 0 + if(skin != NULL) + { + // Get the skeleton resource, so weights can be applied + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + Ogre::SkeletonPtr skel = skelMgr->getByName(mesh->getSkeletonName()); + + NiSkinDataRef data = skin->GetSkinData(); + const std::vector &bones = skin->GetBones(); + for(size_t i = 0;i < bones.size();i++) + { + Ogre::VertexBoneAssignment boneInf; + boneInf.boneIndex = skel->getBone(bones[i]->GetName())->getHandle(); + + const std::vector &weights = data->GetBoneWeights(i); + for(size_t j = 0;j < weights.size();j++) + { + boneInf.vertexIndex = weights[j].index; + boneInf.weight = weights[j].weight; + sub->addBoneAssignment(boneInf); + } + } + } +#endif + + if(mMaterialName.length() > 0) + sub->setMaterialName(mMaterialName); + } + bool findTriShape(Ogre::Mesh *mesh, Nif::Node *node) { if(node->recType == Nif::RC_NiTriShape && mShapeName == node->name) { - warn("Not loading shape \""+mShapeName+"\" in "+mName); + handleNiTriShape(mesh, dynamic_cast(node)); return true; } From 61f32eca77bcf93e25d609987cddb72cc2bbc0f8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jul 2012 15:23:49 -0700 Subject: [PATCH 23/92] Add methods to get a node's local and full transform as a 4x4 matrix --- components/nif/nif_file.cpp | 14 ++++++++++++++ components/nif/node.hpp | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 231349302..789bae5e3 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -210,3 +210,17 @@ void NiSkinInstance::post(NIFFile *nif) bones[i]->makeBone(i, data->bones[i]); } } + +Ogre::Matrix4 Node::getLocalTransform() +{ + Ogre::Matrix4 mat4; + mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation)); + return mat4; +} + +Ogre::Matrix4 Node::getWorldTransform() +{ + if(parent != NULL) + return getLocalTransform() * parent->getWorldTransform(); + return getLocalTransform(); +} diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 1f1b91a46..f7d3c6e96 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -24,6 +24,8 @@ #ifndef _NIF_NODE_H_ #define _NIF_NODE_H_ +#include + #include "controlled.hpp" #include "data.hpp" #include "property.hpp" @@ -108,6 +110,9 @@ public: boneTrafo = &bi.trafo; boneIndex = ind; } + + Ogre::Matrix4 getLocalTransform(); + Ogre::Matrix4 getWorldTransform(); }; struct NiNode : Node From b1f7fd9f7b39b9728839b84693ab8617be739fd5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jul 2012 17:00:27 -0700 Subject: [PATCH 24/92] Pre-transform the mesh vertices when there's no skinning or skeleton --- components/nif/nif_file.cpp | 2 +- components/nifogre/ogre_nif_loader.cpp | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 789bae5e3..308196f32 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -213,7 +213,7 @@ void NiSkinInstance::post(NIFFile *nif) Ogre::Matrix4 Node::getLocalTransform() { - Ogre::Matrix4 mat4; + Ogre::Matrix4 mat4(Ogre::Matrix4::IDENTITY); mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation)); return mat4; } diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 884d8f64e..01551a702 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -533,12 +533,33 @@ class NIFMeshLoader : Ogre::ManualResourceLoader srcNorms = newNorms; #endif } + else if(!mHasSkel) + { + // No skinning and no skeleton, so just transform the vertices and + // normals into position. + Ogre::Matrix4 mat4 = shape->getWorldTransform(); + for(size_t i = 0;i < srcVerts.size();i++) + { + Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); + vec4 = mat4*vec4; + srcVerts[i] = Ogre::Vector3(&vec4[0]); + } + for(size_t i = 0;i < srcNorms.size();i++) + { + Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); + vec4 = mat4*vec4; + srcNorms[i] = Ogre::Vector3(&vec4[0]); + } + } // Set the bounding box first BoundsFinder bounds; bounds.add(&srcVerts[0][0], srcVerts.size()); - mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX(), bounds.minY(), bounds.minZ(), - bounds.maxX(), bounds.maxY(), bounds.maxZ())); + // No idea why this offset is needed. It works fine without it if the + // vertices weren't transformed first, but otherwise it fails later on + // when the object is being inserted into the scene. + mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, + bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); mesh->_setBoundingSphereRadius(bounds.getRadius()); // This function is just one long stream of Ogre-barf, but it works From ad75b47472dbf3856120fe2ee8b65d352395b34c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jul 2012 19:07:31 -0700 Subject: [PATCH 25/92] Build and set up a skeleton for meshes --- components/nifogre/ogre_nif_loader.cpp | 72 +++++++++++++++++++------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 01551a702..1db0b92a5 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -141,9 +141,35 @@ static void fail(const std::string &msg) abort(); } + +void buildBones(Ogre::Skeleton *skel, Nif::NiNode *node, Ogre::Bone *parent=NULL) +{ + Ogre::Bone *bone = skel->createBone(node->name); + if(parent) parent->addChild(bone); + + bone->setOrientation(node->trafo.rotation); + bone->setPosition(node->trafo.pos); + bone->setScale(Ogre::Vector3(node->trafo.scale)); + bone->setBindingPose(); + bone->setInitialState(); + + const Nif::NodeList &children = node->children; + for(size_t i = 0;i < children.length();i++) + { + Nif::NiNode *next; + if(!children[i].empty() && (next=dynamic_cast(children[i].getPtr()))) + buildBones(skel, next, bone); + } +} + void loadResource(Ogre::Resource *resource) { - warn("Found no records in NIF for "+resource->getName()); + Ogre::Skeleton *skel = dynamic_cast(resource); + OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); + + Nif::NIFFile nif(skel->getName()); + Nif::NiNode *node = dynamic_cast(nif.getRecord(0)); + buildBones(skel, node); } static bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node, Ogre::SkeletonPtr *skel) @@ -499,21 +525,29 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::vector srcNorms = data->normals; if(skin != NULL) { -#if 0 - // Convert vertices and normals back to bone space - std::vector newVerts(srcVerts.size(), Vector3(0,0,0)); - std::vector newNorms(srcNorms.size(), Vector3(0,0,0)); + // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be + // explicitly attached later. + mesh->setSkeletonName(mName); - NiSkinDataRef data = skin->GetSkinData(); - const std::vector &bones = skin->GetBones(); - for(size_t b = 0;b < bones.size();b++) + // Convert vertices and normals to bone space from bind position. It would be + // better to transform the bones into bind position, but there doesn't seem to + // be a reliable way to do that. + std::vector newVerts(srcVerts.size(), Ogre::Vector3(0.0f)); + std::vector newNorms(srcNorms.size(), Ogre::Vector3(1.0f)); + + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t b = 0;b < bones.length();b++) { - Matrix44 mat = data->GetBoneTransform(b) * bones[b]->GetWorldTransform(); + Ogre::Matrix4 mat(Ogre::Matrix4::IDENTITY); + mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), + Ogre::Quaternion(data->bones[b].trafo.rotation)); + mat = mat * bones[b]->getWorldTransform(); - const std::vector &weights = data->GetBoneWeights(b); + const std::vector &weights = data->bones[b].weights; for(size_t i = 0;i < weights.size();i++) { - size_t index = weights[i].index; + size_t index = weights[i].vertex; float weight = weights[i].weight; newVerts.at(index) += (mat*srcVerts[index]) * weight; @@ -531,7 +565,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader srcVerts = newVerts; srcNorms = newNorms; -#endif } else if(!mHasSkel) { @@ -653,30 +686,29 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } // Assign bone weights for this TriShape -#if 0 if(skin != NULL) { // Get the skeleton resource, so weights can be applied Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); Ogre::SkeletonPtr skel = skelMgr->getByName(mesh->getSkeletonName()); + skel->touch(); - NiSkinDataRef data = skin->GetSkinData(); - const std::vector &bones = skin->GetBones(); - for(size_t i = 0;i < bones.size();i++) + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t i = 0;i < bones.length();i++) { Ogre::VertexBoneAssignment boneInf; - boneInf.boneIndex = skel->getBone(bones[i]->GetName())->getHandle(); + boneInf.boneIndex = skel->getBone(bones[i]->name)->getHandle(); - const std::vector &weights = data->GetBoneWeights(i); + const std::vector &weights = data->bones[i].weights; for(size_t j = 0;j < weights.size();j++) { - boneInf.vertexIndex = weights[j].index; + boneInf.vertexIndex = weights[j].vertex; boneInf.weight = weights[j].weight; sub->addBoneAssignment(boneInf); } } } -#endif if(mMaterialName.length() > 0) sub->setMaterialName(mMaterialName); From a539e98274971f9495075b7092a5ba264c3e7994 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jul 2012 10:48:48 -0700 Subject: [PATCH 26/92] Handle all meshes when inserting objects into the scene --- apps/openmw/mwrender/objects.cpp | 69 ++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index ea58ec716..2ff9de9a4 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -92,12 +92,19 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) Ogre::SceneNode* insert = ptr.getRefData().getBaseNode(); assert(insert); - // FIXME: There can be more than one! + Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; NifOgre::MeshPairList meshes = NifOgre::NIFLoader::load(mesh); - Ogre::Entity *ent = mRenderer.getScene()->createEntity(meshes[0].first->getName()); + std::vector entities(meshes.size()); + for(size_t i = 0;i < meshes.size();i++) + { + entities[i] = mRenderer.getScene()->createEntity(meshes[i].first->getName()); - - Ogre::Vector3 extents = ent->getBoundingBox().getSize(); + const Ogre::AxisAlignedBox &tmp = entities[i]->getBoundingBox(); + bounds.merge(Ogre::AxisAlignedBox(insert->_getDerivedPosition() + tmp.getMinimum(), + insert->_getDerivedPosition() + tmp.getMaximum()) + ); + } + Ogre::Vector3 extents = bounds.getSize(); extents *= insert->getScale(); float size = std::max(std::max(extents.x, extents.y), extents.z); @@ -109,42 +116,42 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) if (mBounds.find(ptr.getCell()) == mBounds.end()) mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; - - Ogre::AxisAlignedBox bounds = ent->getBoundingBox(); - bounds = Ogre::AxisAlignedBox( - insert->_getDerivedPosition() + bounds.getMinimum(), - insert->_getDerivedPosition() + bounds.getMaximum() - ); - - bounds.scale(insert->getScale()); mBounds[ptr.getCell()].merge(bounds); bool transparent = false; - for (unsigned int i=0; igetNumSubEntities(); ++i) + for(size_t i = 0;i < entities.size();i++) { - Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) + Ogre::Entity *ent = entities[i]; + for (unsigned int i=0; igetNumSubEntities(); ++i) { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) + Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements()) { - Ogre::Pass* pass = passIt.getNext(); + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements()) + { + Ogre::Pass* pass = passIt.getNext(); - if (pass->getDepthWriteEnabled() == false) - transparent = true; + if (pass->getDepthWriteEnabled() == false) + transparent = true; + } } } } if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || transparent) { - insert->attachObject(ent); + for(size_t i = 0;i < entities.size();i++) + { + Ogre::Entity *ent = entities[i]; + insert->attachObject(ent); - ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); - ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); - ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); + ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); + ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + } } else { @@ -184,15 +191,19 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) // - there will be too many batches. sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500)); - sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); - sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); sg->setCastShadows(true); sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - mRenderer.getScene()->destroyEntity(ent); + for(size_t i = 0;i < entities.size();i++) + { + Ogre::Entity *ent = entities[i]; + sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); + + mRenderer.getScene()->destroyEntity(ent); + } } } From 75ce10c580cdf673586e8122f060b3c7876380d9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jul 2012 11:31:45 -0700 Subject: [PATCH 27/92] Don't load data for hidden meshes --- components/nifogre/ogre_nif_loader.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1db0b92a5..044c9cd72 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -755,6 +755,13 @@ public: Ogre::Mesh *mesh = dynamic_cast(resource); assert(mesh && "Attempting to load a mesh into a non-mesh resource!"); + if(!mShapeName.length()) + { + if(mHasSkel) + mesh->setSkeletonName(mName); + return; + } + Nif::NIFFile nif(mName); Nif::Node *node = dynamic_cast(nif.getRecord(0)); findTriShape(mesh, node); @@ -778,8 +785,11 @@ public: { NIFMeshLoader *loader = &sLoaders[fullname]; *loader = *this; - loader->mShapeName = shape->name; - loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); + if(!(flags&0x01)) // Not hidden + { + loader->mShapeName = shape->name; + loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); + } mesh = meshMgr.createManual(fullname, mGroup, loader); } From 12f17858828b6134a8716fb9971bd97d49aa57ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jul 2012 11:43:16 -0700 Subject: [PATCH 28/92] Use default bone names for duplicate names --- components/nifogre/ogre_nif_loader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 044c9cd72..9c0e2e10f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -144,7 +144,11 @@ static void fail(const std::string &msg) void buildBones(Ogre::Skeleton *skel, Nif::NiNode *node, Ogre::Bone *parent=NULL) { - Ogre::Bone *bone = skel->createBone(node->name); + Ogre::Bone *bone; + if(!skel->hasBone(node->name)) + bone = skel->createBone(node->name); + else + bone = skel->createBone(); if(parent) parent->addChild(bone); bone->setOrientation(node->trafo.rotation); From 63e40d6e92e4b55b7c05984a10e1ae59a5f0e8ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jul 2012 13:16:11 -0700 Subject: [PATCH 29/92] Fix world transform calculation --- components/nif/nif_file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 308196f32..3313d89ab 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -221,6 +221,6 @@ Ogre::Matrix4 Node::getLocalTransform() Ogre::Matrix4 Node::getWorldTransform() { if(parent != NULL) - return getLocalTransform() * parent->getWorldTransform(); + return parent->getWorldTransform() * getLocalTransform(); return getLocalTransform(); } From df76c324a4af9681c39d95b187562fc2220c2024 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jul 2012 13:34:56 -0700 Subject: [PATCH 30/92] Handle the MRK text string marker --- components/nifogre/ogre_nif_loader.cpp | 28 +++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 9c0e2e10f..7a7b9e572 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -771,15 +771,33 @@ public: findTriShape(mesh, node); } - void createMeshes(Nif::Node *node, MeshPairList &meshes, int flags=0) + void createMeshes(const Nif::Node *node, MeshPairList &meshes, int flags=0) { flags |= node->flags; - // TODO: Check for extra data + Nif::ExtraPtr e = node->extra; + while(!e.empty()) + { + Nif::NiStringExtraData *sd = dynamic_cast(e.getPtr()); + if(sd != NULL) + { + // String markers may contain important information + // affecting the entire subtree of this obj + if(sd->string == "MRK") + { + // Marker objects. These are only visible in the + // editor. + flags |= 0x01; + } + } + else + warn("Unhandled extra data type "+e->recType); + e = e->extra; + } if(node->recType == Nif::RC_NiTriShape) { - NiTriShape *shape = dynamic_cast(node); + const NiTriShape *shape = dynamic_cast(node); Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); std::string fullname = mName+"@"+shape->name; @@ -804,10 +822,10 @@ public: node->recType != Nif::RC_NiRotatingParticles) warn("Unhandled mesh node type: "+node->recName); - Nif::NiNode *ninode = dynamic_cast(node); + const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { - Nif::NodeList &children = ninode->children; + const Nif::NodeList &children = ninode->children; for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) From bf26f029f92cac2857c886c246b3df11de75d773 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jul 2012 13:47:19 -0700 Subject: [PATCH 31/92] Fix some skinning-related transformations --- components/nifogre/ogre_nif_loader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 7a7b9e572..cffab724e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -546,7 +546,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::Matrix4 mat(Ogre::Matrix4::IDENTITY); mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat = mat * bones[b]->getWorldTransform(); + mat = bones[b]->getWorldTransform() * mat; const std::vector &weights = data->bones[b].weights; for(size_t i = 0;i < weights.size();i++) @@ -559,9 +559,9 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { for(size_t j = 0;j < 3;j++) { - newNorms[index][j] += mat[0][j]*srcNorms[index][0] * weight; - newNorms[index][j] += mat[1][j]*srcNorms[index][1] * weight; - newNorms[index][j] += mat[2][j]*srcNorms[index][2] * weight; + newNorms[index][j] += mat[j][0]*srcNorms[index][0] * weight; + newNorms[index][j] += mat[j][1]*srcNorms[index][1] * weight; + newNorms[index][j] += mat[j][2]*srcNorms[index][2] * weight; } } } From fefbf86531f84c07766bb4b61f95f6345e8c3c73 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jul 2012 14:30:23 -0700 Subject: [PATCH 32/92] Use Ogre's matrix ops to transform normals --- components/nifogre/ogre_nif_loader.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index cffab724e..29ead0461 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -557,12 +557,9 @@ class NIFMeshLoader : Ogre::ManualResourceLoader newVerts.at(index) += (mat*srcVerts[index]) * weight; if(newNorms.size() > index) { - for(size_t j = 0;j < 3;j++) - { - newNorms[index][j] += mat[j][0]*srcNorms[index][0] * weight; - newNorms[index][j] += mat[j][1]*srcNorms[index][1] * weight; - newNorms[index][j] += mat[j][2]*srcNorms[index][2] * weight; - } + Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); + vec4 = mat*vec4 * weight; + newNorms[index] += Ogre::Vector3(&vec4[0]); } } } From 65c20f128f8c6552da1707c072c23698a40d8364 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jul 2012 21:18:33 -0700 Subject: [PATCH 33/92] Build bones for non-NiNode nodes (NiTriShapes, etc) --- components/nifogre/ogre_nif_loader.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 29ead0461..c0f3c25d0 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -142,7 +142,7 @@ static void fail(const std::string &msg) } -void buildBones(Ogre::Skeleton *skel, Nif::NiNode *node, Ogre::Bone *parent=NULL) +void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent=NULL) { Ogre::Bone *bone; if(!skel->hasBone(node->name)) @@ -157,12 +157,15 @@ void buildBones(Ogre::Skeleton *skel, Nif::NiNode *node, Ogre::Bone *parent=NULL bone->setBindingPose(); bone->setInitialState(); - const Nif::NodeList &children = node->children; - for(size_t i = 0;i < children.length();i++) + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - Nif::NiNode *next; - if(!children[i].empty() && (next=dynamic_cast(children[i].getPtr()))) - buildBones(skel, next, bone); + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + buildBones(skel, children[i].getPtr(), bone); + } } } @@ -172,7 +175,7 @@ void loadResource(Ogre::Resource *resource) OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); Nif::NIFFile nif(skel->getName()); - Nif::NiNode *node = dynamic_cast(nif.getRecord(0)); + const Nif::Node *node = dynamic_cast(nif.getRecord(0)); buildBones(skel, node); } From 93f0043afc098b7384b1b02e389c478052bc47bc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 10:04:21 -0700 Subject: [PATCH 34/92] Set the mesh's attach point as the NiTriShape's node --- components/nifogre/ogre_nif_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c0f3c25d0..fef7054f7 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -816,7 +816,7 @@ public: mesh = meshMgr.createManual(fullname, mGroup, loader); } - meshes.push_back(std::make_pair(mesh, (shape->parent ? shape->parent->name : std::string()))); + meshes.push_back(std::make_pair(mesh, shape->name)); } else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && node->recType != Nif::RC_NiRotatingParticles) From 0a4a141f2e94925f24f60b09e85e4a365ef336d5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 11:23:34 -0700 Subject: [PATCH 35/92] Support multiple meshes for creatures --- apps/openmw/mwrender/animation.cpp | 1 - apps/openmw/mwrender/animation.hpp | 4 +- apps/openmw/mwrender/creatureanimation.cpp | 43 ++++++++++++---------- apps/openmw/mwrender/npcanimation.hpp | 1 + 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 08176077c..17c3f62ac 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,7 +23,6 @@ Animation::Animation(OEngine::Render::OgreRenderer& _rend) , mShapeIndexI() , mTransformations(NULL) , mTextmappings(NULL) - , mBase(NULL) { } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 0e96b4d4d..ea18865da 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,6 +1,8 @@ #ifndef _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H +#include + #include #include "../mwworld/actiontalk.hpp" #include @@ -37,7 +39,7 @@ protected: std::vector* mTransformations; std::map* mTextmappings; - Ogre::Entity* mBase; + std::vector mBase; void handleAnimationTransforms(); bool timeIndex( float time, const std::vector & times, int & i, int & j, float & x ); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 99800f06c..b42feec68 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,32 +26,35 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O { std::string mesh = "meshes\\" + ref->base->model; - // FIXME: There can be more than one! NifOgre::MeshPairList meshes = NifOgre::NIFLoader::load(mesh); - mBase = mRend.getScene()->createEntity(meshes[0].first->getName()); - mBase->setVisibilityFlags(RV_Actors); - - bool transparent = false; - for (unsigned int i=0; i < mBase->getNumSubEntities(); ++i) + for(size_t i = 0;i < meshes.size();i++) { - Ogre::MaterialPtr mat = mBase->getSubEntity(i)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); + mBase.push_back(mRend.getScene()->createEntity(meshes[i].first->getName())); + Ogre::Entity *base = mBase.back(); + base->setVisibilityFlags(RV_Actors); - if (pass->getDepthWriteEnabled() == false) - transparent = true; + bool transparent = false; + for (unsigned int j=0;j < base->getNumSubEntities() && !transparent; ++j) + { + Ogre::MaterialPtr mat = base->getSubEntity(j)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements() && !transparent) + { + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements() && !transparent) + { + Ogre::Pass* pass = passIt.getNext(); + + if (pass->getDepthWriteEnabled() == false) + transparent = true; + } } } - } - mBase->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - mInsert->attachObject(mBase); + mInsert->attachObject(base); + } } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 82d847091..651f0ffe2 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -41,6 +41,7 @@ private: Ogre::Entity* head; Ogre::SceneNode* mInsert; + Ogre::Entity *mBase; // FIXME: Temporary! bool isBeast; bool isFemale; std::string headModel; From 89cfe778f04df460a03fa3d3f4e00eccec54ee19 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 11:38:20 -0700 Subject: [PATCH 36/92] Support multiple entities for the NPC base --- apps/openmw/mwrender/npcanimation.cpp | 91 ++++++++++++++------------- apps/openmw/mwrender/npcanimation.hpp | 2 +- 2 files changed, 50 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index cede30c96..e8e24473c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -45,7 +45,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere lAnkle(0), groin(0), lfoot(0), - rfoot(0) + rfoot(0), + mSkelBase(0) { MWWorld::LiveCellRef *ref = ptr.get(); @@ -82,33 +83,39 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - // FIXME: There can be more than one! NifOgre::MeshPairList meshes = NifOgre::NIFLoader::load(smodel); - mBase = mRend.getScene()->createEntity(meshes[0].first->getName()); - - mBase->setVisibilityFlags(RV_Actors); - bool transparent = false; - for (unsigned int i=0; igetNumSubEntities(); ++i) + for(size_t i = 0;i < meshes.size();i++) { - Ogre::MaterialPtr mat = mBase->getSubEntity(i)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) + mBase.push_back(mRend.getScene()->createEntity(meshes[i].first->getName())); + Ogre::Entity *base = mBase.back(); + + if(!mSkelBase && base->hasSkeleton()) + mSkelBase = base; + + base->setVisibilityFlags(RV_Actors); + bool transparent = false; + for(unsigned int j=0;j < base->getNumSubEntities();++j) { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) + Ogre::MaterialPtr mat = base->getSubEntity(j)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements()) { - Ogre::Pass* pass = passIt.getNext(); - if (pass->getDepthWriteEnabled() == false) - transparent = true; + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements()) + { + Ogre::Pass* pass = passIt.getNext(); + if (pass->getDepthWriteEnabled() == false) + transparent = true; + } } } - } - mBase->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - mBase->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones - //stay in the same place when we skipanim, or open a gui window + base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones + //stay in the same place when we skipanim, or open a gui window - mInsert->attachObject(mBase); + mInsert->attachObject(base); + } if(isFemale) mInsert->scale(race->data.height.female, race->data.height.female, race->data.height.female); @@ -388,7 +395,7 @@ Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, const std Ogre::Entity* part = mRend.getScene()->createEntity(meshes[0].first->getName()); part->setVisibilityFlags(RV_Actors); - mBase->attachObjectToBone(bonename, part); + mSkelBase->attachObjectToBone(bonename, part); return part; } @@ -430,32 +437,32 @@ void NpcAnimation::removeIndividualPart(int type) if(type == ESM::PRT_Head && head) //0 { - mBase->detachObjectFromBone(head); + mSkelBase->detachObjectFromBone(head); head = 0; } else if(type == ESM::PRT_Hair && hair) //1 { - mBase->detachObjectFromBone(hair); + mSkelBase->detachObjectFromBone(hair); hair = 0; } else if(type == ESM::PRT_Neck && neck) //2 { - mBase->detachObjectFromBone(neck); + mSkelBase->detachObjectFromBone(neck); neck = 0; } else if(type == ESM::PRT_Groin && groin)//4 { - mBase->detachObjectFromBone(groin); + mSkelBase->detachObjectFromBone(groin); groin = 0; } else if(type == ESM::PRT_RWrist && rWrist)//8 { - mBase->detachObjectFromBone(rWrist); + mSkelBase->detachObjectFromBone(rWrist); rWrist = 0; } else if(type == ESM::PRT_LWrist && lWrist) //9 { - mBase->detachObjectFromBone(lWrist); + mSkelBase->detachObjectFromBone(lWrist); lWrist = 0; } else if(type == ESM::PRT_Shield) //10 @@ -463,72 +470,72 @@ void NpcAnimation::removeIndividualPart(int type) } else if(type == ESM::PRT_RForearm && rForearm) //11 { - mBase->detachObjectFromBone(rForearm); + mSkelBase->detachObjectFromBone(rForearm); rForearm = 0; } else if(type == ESM::PRT_LForearm && lForearm) //12 { - mBase->detachObjectFromBone(lForearm); + mSkelBase->detachObjectFromBone(lForearm); lForearm = 0; } else if(type == ESM::PRT_RUpperarm && rupperArm) //13 { - mBase->detachObjectFromBone(rupperArm); + mSkelBase->detachObjectFromBone(rupperArm); rupperArm = 0; } else if(type == ESM::PRT_LUpperarm && lupperArm) //14 { - mBase->detachObjectFromBone(lupperArm); + mSkelBase->detachObjectFromBone(lupperArm); lupperArm = 0; } else if(type == ESM::PRT_RFoot && rfoot) //15 { - mBase->detachObjectFromBone(rfoot); + mSkelBase->detachObjectFromBone(rfoot); rfoot = 0; } else if(type == ESM::PRT_LFoot && lfoot) //16 { - mBase->detachObjectFromBone(lfoot); + mSkelBase->detachObjectFromBone(lfoot); lfoot = 0; } else if(type == ESM::PRT_RAnkle && rAnkle) //17 { - mBase->detachObjectFromBone(rAnkle); + mSkelBase->detachObjectFromBone(rAnkle); rAnkle = 0; } else if(type == ESM::PRT_LAnkle && lAnkle) //18 { - mBase->detachObjectFromBone(lAnkle); + mSkelBase->detachObjectFromBone(lAnkle); lAnkle = 0; } else if(type == ESM::PRT_RKnee && rKnee) //19 { - mBase->detachObjectFromBone(rKnee); + mSkelBase->detachObjectFromBone(rKnee); rKnee = 0; } else if(type == ESM::PRT_LKnee && lKnee) //20 { - mBase->detachObjectFromBone(lKnee); + mSkelBase->detachObjectFromBone(lKnee); lKnee = 0; } else if(type == ESM::PRT_RLeg && rUpperLeg) //21 { - mBase->detachObjectFromBone(rUpperLeg); + mSkelBase->detachObjectFromBone(rUpperLeg); rUpperLeg = 0; } else if(type == ESM::PRT_LLeg && lUpperLeg) //22 { - mBase->detachObjectFromBone(lUpperLeg); + mSkelBase->detachObjectFromBone(lUpperLeg); lUpperLeg = 0; } else if(type == ESM::PRT_RPauldron && rclavicle) //23 { - mBase->detachObjectFromBone(rclavicle); + mSkelBase->detachObjectFromBone(rclavicle); rclavicle = 0; } else if(type == ESM::PRT_LPauldron && lclavicle) //24 { - mBase->detachObjectFromBone(lclavicle); + mSkelBase->detachObjectFromBone(lclavicle); lclavicle = 0; } else if(type == ESM::PRT_Weapon) //25 diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 651f0ffe2..a60c8d7fe 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -41,7 +41,7 @@ private: Ogre::Entity* head; Ogre::SceneNode* mInsert; - Ogre::Entity *mBase; // FIXME: Temporary! + Ogre::Entity *mSkelBase; // Entity with the base skeleton (temporary) bool isBeast; bool isFemale; std::string headModel; From c6cc82a51a6df78113dbc2a6e838dfc9231b5704 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 12:19:50 -0700 Subject: [PATCH 37/92] Handle multiple entities per NPC part --- apps/openmw/mwrender/npcanimation.cpp | 181 ++++++++------------------ apps/openmw/mwrender/npcanimation.hpp | 43 +++--- 2 files changed, 79 insertions(+), 145 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e8e24473c..ce22da779 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -28,24 +28,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere boots(mInv.end()), leftglove(mInv.end()), rightglove(mInv.end()), skirtiter(mInv.end()), pants(mInv.end()), - lclavicle(0), - rclavicle(0), - rupperArm(0), - lupperArm(0), - rUpperLeg(0), - lUpperLeg(0), - lForearm(0), - rForearm(0), - lWrist(0), - rWrist(0), - rKnee(0), - lKnee(0), - neck(0), - rAnkle(0), - lAnkle(0), - groin(0), - lfoot(0), - rfoot(0), mSkelBase(0) { MWWorld::LiveCellRef *ref = ptr.get(); @@ -388,15 +370,19 @@ void NpcAnimation::updateParts() } } -Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, const std::string &bonename) +std::vector NpcAnimation::insertBoundedPart(const std::string &mesh, const std::string &bonename) { - // FIXME: There can be more than one! NifOgre::MeshPairList meshes = NIFLoader::load(mesh); - Ogre::Entity* part = mRend.getScene()->createEntity(meshes[0].first->getName()); - part->setVisibilityFlags(RV_Actors); + std::vector parts; + for(size_t i = 0;i < meshes.size();i++) + { + parts.push_back(mRend.getScene()->createEntity(meshes[i].first->getName())); + Ogre::Entity *part = parts.back(); - mSkelBase->attachObjectToBone(bonename, part); - return part; + part->setVisibilityFlags(RV_Actors); + mSkelBase->attachObjectToBone(bonename, part); + } + return parts; } void NpcAnimation::runAnimation(float timepassed) @@ -430,114 +416,61 @@ void NpcAnimation::runAnimation(float timepassed) } } +void NpcAnimation::removeEntities(std::vector &entities) +{ + for(size_t i = 0;i < entities.size();i++) + mSkelBase->detachObjectFromBone(entities[i]); + entities.clear(); +} + void NpcAnimation::removeIndividualPart(int type) { mPartPriorities[type] = 0; mPartslots[type] = -1; - if(type == ESM::PRT_Head && head) //0 - { - mSkelBase->detachObjectFromBone(head); - head = 0; - } - else if(type == ESM::PRT_Hair && hair) //1 - { - mSkelBase->detachObjectFromBone(hair); - hair = 0; - } - else if(type == ESM::PRT_Neck && neck) //2 - { - mSkelBase->detachObjectFromBone(neck); - neck = 0; - } - else if(type == ESM::PRT_Groin && groin)//4 - { - mSkelBase->detachObjectFromBone(groin); - groin = 0; - } - else if(type == ESM::PRT_RWrist && rWrist)//8 - { - mSkelBase->detachObjectFromBone(rWrist); - rWrist = 0; - } - else if(type == ESM::PRT_LWrist && lWrist) //9 - { - mSkelBase->detachObjectFromBone(lWrist); - lWrist = 0; - } + if(type == ESM::PRT_Head) //0 + removeEntities(head); + else if(type == ESM::PRT_Hair) //1 + removeEntities(hair); + else if(type == ESM::PRT_Neck) //2 + removeEntities(neck); + else if(type == ESM::PRT_Groin)//4 + removeEntities(groin); + else if(type == ESM::PRT_RWrist)//8 + removeEntities(rWrist); + else if(type == ESM::PRT_LWrist) //9 + removeEntities(lWrist); else if(type == ESM::PRT_Shield) //10 { } - else if(type == ESM::PRT_RForearm && rForearm) //11 - { - mSkelBase->detachObjectFromBone(rForearm); - rForearm = 0; - } - else if(type == ESM::PRT_LForearm && lForearm) //12 - { - mSkelBase->detachObjectFromBone(lForearm); - lForearm = 0; - } - else if(type == ESM::PRT_RUpperarm && rupperArm) //13 - { - mSkelBase->detachObjectFromBone(rupperArm); - rupperArm = 0; - } - else if(type == ESM::PRT_LUpperarm && lupperArm) //14 - { - mSkelBase->detachObjectFromBone(lupperArm); - lupperArm = 0; - } - else if(type == ESM::PRT_RFoot && rfoot) //15 - { - mSkelBase->detachObjectFromBone(rfoot); - rfoot = 0; - } - else if(type == ESM::PRT_LFoot && lfoot) //16 - { - mSkelBase->detachObjectFromBone(lfoot); - lfoot = 0; - } - else if(type == ESM::PRT_RAnkle && rAnkle) //17 - { - mSkelBase->detachObjectFromBone(rAnkle); - rAnkle = 0; - } - else if(type == ESM::PRT_LAnkle && lAnkle) //18 - { - mSkelBase->detachObjectFromBone(lAnkle); - lAnkle = 0; - } - else if(type == ESM::PRT_RKnee && rKnee) //19 - { - mSkelBase->detachObjectFromBone(rKnee); - rKnee = 0; - } - else if(type == ESM::PRT_LKnee && lKnee) //20 - { - mSkelBase->detachObjectFromBone(lKnee); - lKnee = 0; - } - else if(type == ESM::PRT_RLeg && rUpperLeg) //21 - { - mSkelBase->detachObjectFromBone(rUpperLeg); - rUpperLeg = 0; - } - else if(type == ESM::PRT_LLeg && lUpperLeg) //22 - { - mSkelBase->detachObjectFromBone(lUpperLeg); - lUpperLeg = 0; - } - else if(type == ESM::PRT_RPauldron && rclavicle) //23 - { - mSkelBase->detachObjectFromBone(rclavicle); - rclavicle = 0; - } - else if(type == ESM::PRT_LPauldron && lclavicle) //24 - { - mSkelBase->detachObjectFromBone(lclavicle); - lclavicle = 0; - } + else if(type == ESM::PRT_RForearm) //11 + removeEntities(rForearm); + else if(type == ESM::PRT_LForearm) //12 + removeEntities(lForearm); + else if(type == ESM::PRT_RUpperarm) //13 + removeEntities(rupperArm); + else if(type == ESM::PRT_LUpperarm) //14 + removeEntities(lupperArm); + else if(type == ESM::PRT_RFoot) //15 + removeEntities(rfoot); + else if(type == ESM::PRT_LFoot) //16 + removeEntities(lfoot); + else if(type == ESM::PRT_RAnkle) //17 + removeEntities(rAnkle); + else if(type == ESM::PRT_LAnkle) //18 + removeEntities(lAnkle); + else if(type == ESM::PRT_RKnee) //19 + removeEntities(rKnee); + else if(type == ESM::PRT_LKnee) //20 + removeEntities(lKnee); + else if(type == ESM::PRT_RLeg) //21 + removeEntities(rUpperLeg); + else if(type == ESM::PRT_LLeg) //22 + removeEntities(lUpperLeg); + else if(type == ESM::PRT_RPauldron) //23 + removeEntities(rclavicle); + else if(type == ESM::PRT_LPauldron) //24 + removeEntities(lclavicle); else if(type == ESM::PRT_Weapon) //25 { } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index a60c8d7fe..7830b68cc 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -19,26 +19,26 @@ private: int mPartPriorities[27]; //Bounded Parts - Ogre::Entity* lclavicle; - Ogre::Entity* rclavicle; - Ogre::Entity* rupperArm; - Ogre::Entity* lupperArm; - Ogre::Entity* rUpperLeg; - Ogre::Entity* lUpperLeg; - Ogre::Entity* lForearm; - Ogre::Entity* rForearm; - Ogre::Entity* lWrist; - Ogre::Entity* rWrist; - Ogre::Entity* rKnee; - Ogre::Entity* lKnee; - Ogre::Entity* neck; - Ogre::Entity* rAnkle; - Ogre::Entity* lAnkle; - Ogre::Entity* groin; - Ogre::Entity* lfoot; - Ogre::Entity* rfoot; - Ogre::Entity* hair; - Ogre::Entity* head; + std::vector lclavicle; + std::vector rclavicle; + std::vector rupperArm; + std::vector lupperArm; + std::vector rUpperLeg; + std::vector lUpperLeg; + std::vector lForearm; + std::vector rForearm; + std::vector lWrist; + std::vector rWrist; + std::vector rKnee; + std::vector lKnee; + std::vector neck; + std::vector rAnkle; + std::vector lAnkle; + std::vector groin; + std::vector lfoot; + std::vector rfoot; + std::vector hair; + std::vector head; Ogre::SceneNode* mInsert; Ogre::Entity *mSkelBase; // Entity with the base skeleton (temporary) @@ -65,9 +65,10 @@ private: public: NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); virtual ~NpcAnimation(); - Ogre::Entity* insertBoundedPart(const std::string &mesh, const std::string &bonename); + std::vector insertBoundedPart(const std::string &mesh, const std::string &bonename); virtual void runAnimation(float timepassed); void updateParts(); + void removeEntities(std::vector &entities); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); From 3dedac5cb14623911a43de2027c8f86077586e8d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 13:40:03 -0700 Subject: [PATCH 38/92] Create mesh entities for objects when loading the NIF --- apps/openmw/mwrender/objects.cpp | 23 +++++++-------- components/nifogre/ogre_nif_loader.cpp | 39 ++++++++++++++++++++++++++ components/nifogre/ogre_nif_loader.hpp | 12 ++++++++ 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 2ff9de9a4..bc1a4a521 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -93,13 +93,10 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) assert(insert); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - NifOgre::MeshPairList meshes = NifOgre::NIFLoader::load(mesh); - std::vector entities(meshes.size()); - for(size_t i = 0;i < meshes.size();i++) + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, mesh); + for(size_t i = 0;i < entities.mEntities.size();i++) { - entities[i] = mRenderer.getScene()->createEntity(meshes[i].first->getName()); - - const Ogre::AxisAlignedBox &tmp = entities[i]->getBoundingBox(); + const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox(); bounds.merge(Ogre::AxisAlignedBox(insert->_getDerivedPosition() + tmp.getMinimum(), insert->_getDerivedPosition() + tmp.getMaximum()) ); @@ -119,9 +116,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) mBounds[ptr.getCell()].merge(bounds); bool transparent = false; - for(size_t i = 0;i < entities.size();i++) + for(size_t i = 0;i < entities.mEntities.size();i++) { - Ogre::Entity *ent = entities[i]; + Ogre::Entity *ent = entities.mEntities[i]; for (unsigned int i=0; igetNumSubEntities(); ++i) { Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); @@ -143,10 +140,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || transparent) { - for(size_t i = 0;i < entities.size();i++) + for(size_t i = 0;i < entities.mEntities.size();i++) { - Ogre::Entity *ent = entities[i]; - insert->attachObject(ent); + Ogre::Entity *ent = entities.mEntities[i]; ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); @@ -197,9 +193,10 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - for(size_t i = 0;i < entities.size();i++) + for(size_t i = 0;i < entities.mEntities.size();i++) { - Ogre::Entity *ent = entities[i]; + Ogre::Entity *ent = entities.mEntities[i]; + insert->detachObject(ent); sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); mRenderer.getScene()->destroyEntity(ent); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index fef7054f7..c90083619 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -871,6 +872,44 @@ MeshPairList NIFLoader::load(const std::string &name, Ogre::SkeletonPtr *skel, c return meshes; } +EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, const std::string &name, const std::string &group) +{ + EntityList entitylist; + + MeshPairList meshes = load(name, NULL, group); + if(meshes.size() == 0) + return entitylist; + + Ogre::SceneManager *sceneMgr = parent->getCreator(); + for(size_t i = 0;i < meshes.size();i++) + { + entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first->getName())); + Ogre::Entity *entity = entitylist.mEntities.back(); + if(!entitylist.mSkelBase && entity->hasSkeleton()) + entitylist.mSkelBase = entity; + } + + if(entitylist.mSkelBase) + { + parent->attachObject(entitylist.mSkelBase); + for(size_t i = 0;i < entitylist.mEntities.size();i++) + { + Ogre::Entity *entity = entitylist.mEntities[i]; + if(entity != entitylist.mSkelBase && entity->hasSkeleton()) + entity->shareSkeletonInstanceWith(entitylist.mSkelBase); + else if(entity != entitylist.mSkelBase) + entitylist.mSkelBase->attachObjectToBone(meshes[i].second, entity); + } + } + else + { + for(size_t i = 0;i < entitylist.mEntities.size();i++) + parent->attachObject(entitylist.mEntities[i]); + } + + return entitylist; +} + /* More code currently not in use, from the old D source. This was used in the first attempt at loading NIF meshes, where each submesh diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 4e9ffc31e..bd6f99b2f 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -58,6 +58,14 @@ namespace Nif namespace NifOgre { +struct EntityList { + std::vector mEntities; + Ogre::Entity *mSkelBase; + + EntityList() : mSkelBase(0) + { } +}; + /** This holds a list of meshes along with the names of their parent nodes */ typedef std::vector< std::pair > MeshPairList; @@ -81,6 +89,10 @@ public: static MeshPairList load(const std::string &name, Ogre::SkeletonPtr *skel=NULL, const std::string &group="General"); + + static EntityList createEntities(Ogre::SceneNode *parent, + const std::string &name, + const std::string &group="General"); }; } From 3efd2030e206099f613d99aadee3ddce3e959a6b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 14:11:07 -0700 Subject: [PATCH 39/92] Create entities when loading NIFs for creatures --- apps/openmw/mwrender/creatureanimation.cpp | 17 +++++++---------- components/nifogre/ogre_nif_loader.cpp | 3 +++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index b42feec68..92930e8d4 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,17 +26,16 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O { std::string mesh = "meshes\\" + ref->base->model; - NifOgre::MeshPairList meshes = NifOgre::NIFLoader::load(mesh); - for(size_t i = 0;i < meshes.size();i++) + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mInsert, mesh); + mBase = entities.mEntities; + for(size_t i = 0;i < mBase.size();i++) { - mBase.push_back(mRend.getScene()->createEntity(meshes[i].first->getName())); - Ogre::Entity *base = mBase.back(); - base->setVisibilityFlags(RV_Actors); + mBase[i]->setVisibilityFlags(RV_Actors); bool transparent = false; - for (unsigned int j=0;j < base->getNumSubEntities() && !transparent; ++j) + for (unsigned int j=0;j < mBase[i]->getNumSubEntities() && !transparent; ++j) { - Ogre::MaterialPtr mat = base->getSubEntity(j)->getMaterial(); + Ogre::MaterialPtr mat = mBase[i]->getSubEntity(j)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); while (techIt.hasMoreElements() && !transparent) { @@ -51,9 +50,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O } } } - base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - - mInsert->attachObject(base); + mBase[i]->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } } } diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c90083619..79eaa6680 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -896,7 +896,10 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, const std::string { Ogre::Entity *entity = entitylist.mEntities[i]; if(entity != entitylist.mSkelBase && entity->hasSkeleton()) + { entity->shareSkeletonInstanceWith(entitylist.mSkelBase); + parent->attachObject(entity); + } else if(entity != entitylist.mSkelBase) entitylist.mSkelBase->attachObjectToBone(meshes[i].second, entity); } From a590db2cf46da03e5fd8642f629424a039c3434a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 15:43:40 -0700 Subject: [PATCH 40/92] Create entities when loading NIFs for the NPC base --- apps/openmw/mwrender/npcanimation.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index ce22da779..86a58c849 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -65,14 +65,12 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - NifOgre::MeshPairList meshes = NifOgre::NIFLoader::load(smodel); - for(size_t i = 0;i < meshes.size();i++) + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mInsert, smodel); + mBase = entities.mEntities; + mSkelBase = entities.mSkelBase; + for(size_t i = 0;i < mBase.size();i++) { - mBase.push_back(mRend.getScene()->createEntity(meshes[i].first->getName())); - Ogre::Entity *base = mBase.back(); - - if(!mSkelBase && base->hasSkeleton()) - mSkelBase = base; + Ogre::Entity *base = mBase[i]; base->setVisibilityFlags(RV_Actors); bool transparent = false; @@ -95,8 +93,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones //stay in the same place when we skipanim, or open a gui window - - mInsert->attachObject(base); } if(isFemale) From 94f3e7a6c069cc9d4de5959a343bc06d0d66b320 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 16:00:03 -0700 Subject: [PATCH 41/92] Store the entity list in the object --- apps/openmw/mwrender/animation.hpp | 3 ++- apps/openmw/mwrender/creatureanimation.cpp | 14 +++++++------- apps/openmw/mwrender/npcanimation.cpp | 15 ++++++--------- apps/openmw/mwrender/npcanimation.hpp | 1 - 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ea18865da..def7f226c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -3,6 +3,7 @@ #include +#include #include #include "../mwworld/actiontalk.hpp" #include @@ -39,7 +40,7 @@ protected: std::vector* mTransformations; std::map* mTextmappings; - std::vector mBase; + NifOgre::EntityList mEntityList; void handleAnimationTransforms(); bool timeIndex( float time, const std::vector & times, int & i, int & j, float & x ); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 92930e8d4..fd2855154 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,16 +26,16 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O { std::string mesh = "meshes\\" + ref->base->model; - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mInsert, mesh); - mBase = entities.mEntities; - for(size_t i = 0;i < mBase.size();i++) + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, mesh); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) { - mBase[i]->setVisibilityFlags(RV_Actors); + Ogre::Entity *ent = mEntityList.mEntities[i]; + ent->setVisibilityFlags(RV_Actors); bool transparent = false; - for (unsigned int j=0;j < mBase[i]->getNumSubEntities() && !transparent; ++j) + for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) { - Ogre::MaterialPtr mat = mBase[i]->getSubEntity(j)->getMaterial(); + Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); while (techIt.hasMoreElements() && !transparent) { @@ -50,7 +50,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O } } } - mBase[i]->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 86a58c849..cdef5ce8b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -27,8 +27,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere leftpauldron(mInv.end()), rightpauldron(mInv.end()), boots(mInv.end()), leftglove(mInv.end()), rightglove(mInv.end()), skirtiter(mInv.end()), - pants(mInv.end()), - mSkelBase(0) + pants(mInv.end()) { MWWorld::LiveCellRef *ref = ptr.get(); @@ -65,12 +64,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mInsert, smodel); - mBase = entities.mEntities; - mSkelBase = entities.mSkelBase; - for(size_t i = 0;i < mBase.size();i++) + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, smodel); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) { - Ogre::Entity *base = mBase[i]; + Ogre::Entity *base = mEntityList.mEntities[i]; base->setVisibilityFlags(RV_Actors); bool transparent = false; @@ -376,7 +373,7 @@ std::vector NpcAnimation::insertBoundedPart(const std::string &me Ogre::Entity *part = parts.back(); part->setVisibilityFlags(RV_Actors); - mSkelBase->attachObjectToBone(bonename, part); + mEntityList.mSkelBase->attachObjectToBone(bonename, part); } return parts; } @@ -415,7 +412,7 @@ void NpcAnimation::runAnimation(float timepassed) void NpcAnimation::removeEntities(std::vector &entities) { for(size_t i = 0;i < entities.size();i++) - mSkelBase->detachObjectFromBone(entities[i]); + mEntityList.mSkelBase->detachObjectFromBone(entities[i]); entities.clear(); } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 7830b68cc..f27642720 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -41,7 +41,6 @@ private: std::vector head; Ogre::SceneNode* mInsert; - Ogre::Entity *mSkelBase; // Entity with the base skeleton (temporary) bool isBeast; bool isFemale; std::string headModel; From 496343b714e9b78dbb3297307122775cac57db03 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 16:36:43 -0700 Subject: [PATCH 42/92] Use the proper member for the NIF type string --- components/nifogre/ogre_nif_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 79eaa6680..305e66df1 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -792,7 +792,7 @@ public: } } else - warn("Unhandled extra data type "+e->recType); + warn("Unhandled extra data type "+e->recName); e = e->extra; } From 1c544682d5bf12b152cb3e868b90e22085806af3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 16:45:01 -0700 Subject: [PATCH 43/92] Stub handling for NiTextKeyExtraData to suppress some spam --- components/nifogre/ogre_nif_loader.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 305e66df1..761924488 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -779,8 +779,9 @@ public: Nif::ExtraPtr e = node->extra; while(!e.empty()) { - Nif::NiStringExtraData *sd = dynamic_cast(e.getPtr()); - if(sd != NULL) + Nif::NiStringExtraData *sd; + Nif::NiTextKeyExtraData *td; + if((sd=dynamic_cast(e.getPtr())) != NULL) { // String markers may contain important information // affecting the entire subtree of this obj @@ -791,6 +792,10 @@ public: flags |= 0x01; } } + else if((td=dynamic_cast(e.getPtr())) != NULL) + { + // TODO: Read and store text keys somewhere + } else warn("Unhandled extra data type "+e->recName); e = e->extra; From 92546ca18d034300b12b179dc099e1cee37c005f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 20:23:09 -0700 Subject: [PATCH 44/92] Move the last bits of code to createEntities --- apps/openmw/mwrender/npcanimation.cpp | 14 ++++---------- apps/openmw/mwrender/sky.cpp | 22 +++++++++------------- components/nifogre/ogre_nif_loader.hpp | 2 +- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index cdef5ce8b..439f6fa2d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -365,16 +365,10 @@ void NpcAnimation::updateParts() std::vector NpcAnimation::insertBoundedPart(const std::string &mesh, const std::string &bonename) { - NifOgre::MeshPairList meshes = NIFLoader::load(mesh); - std::vector parts; - for(size_t i = 0;i < meshes.size();i++) - { - parts.push_back(mRend.getScene()->createEntity(meshes[i].first->getName())); - Ogre::Entity *part = parts.back(); - - part->setVisibilityFlags(RV_Actors); - mEntityList.mSkelBase->attachObjectToBone(bonename, part); - } + NifOgre::EntityList entities = NIFLoader::createEntities(mInsert, mesh); + std::vector &parts = entities.mEntities; + for(size_t i = 0;i < parts.size();i++) + parts[i]->setVisibilityFlags(RV_Actors); return parts; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8f49e03df..682a96419 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -509,16 +509,14 @@ void SkyManager::create() /// \todo sky_night_02.nif (available in Bloodmoon) mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::MeshPairList meshes = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif"); - for(size_t i = 0;i < meshes.size();i++) + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); + for(size_t i = 0;i < entities.mEntities.size();i++) { - Entity* night1_ent = mSceneMgr->createEntity(meshes[i].first->getName()); + Entity* night1_ent = entities.mEntities[i]; night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setCastShadows(false); - mAtmosphereNight->attachObject(night1_ent); - for (unsigned int i=0; igetNumSubEntities(); ++i) { MaterialPtr mp = night1_ent->getSubEntity(i)->getMaterial(); @@ -589,17 +587,16 @@ void SkyManager::create() fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); mAtmosphereDay = mRootNode->createChildSceneNode(); - meshes = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif"); - for(size_t i = 0;i < meshes.size();i++) + entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); + for(size_t i = 0;i < entities.mEntities.size();i++) { - Entity* atmosphere_ent = mSceneMgr->createEntity(meshes[i].first->getName()); + Entity* atmosphere_ent = entities.mEntities[i]; atmosphere_ent->setCastShadows(false); ModVertexAlpha(atmosphere_ent, 0); atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); - mAtmosphereDay->attachObject(atmosphere_ent); mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial(); mAtmosphereMaterial = mAtmosphereMaterial->clone("Atmosphere"); @@ -677,13 +674,12 @@ void SkyManager::create() mCloudFragmentShader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); SceneNode* clouds_node = mRootNode->createChildSceneNode(); - meshes = NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif"); - for(size_t i = 0;i < meshes.size();i++) + entities = NifOgre::NIFLoader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); + for(size_t i = 0;i < entities.mEntities.size();i++) { - Entity* clouds_ent = mSceneMgr->createEntity(meshes[i].first->getName()); + Entity* clouds_ent = entities.mEntities[i]; clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); - clouds_node->attachObject(clouds_ent); mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial(); mCloudMaterial = mCloudMaterial->clone("Clouds"); diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index bd6f99b2f..f21069b75 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -85,11 +85,11 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { -public: static MeshPairList load(const std::string &name, Ogre::SkeletonPtr *skel=NULL, const std::string &group="General"); +public: static EntityList createEntities(Ogre::SceneNode *parent, const std::string &name, const std::string &group="General"); From b04c3cbcac64988ec3a964a1b323946c6d56abbe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 21:42:47 -0700 Subject: [PATCH 45/92] Store the entities' root node in the EntityList --- components/nifogre/ogre_nif_loader.cpp | 1 + components/nifogre/ogre_nif_loader.hpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 761924488..c74f1fe0d 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -885,6 +885,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, const std::string if(meshes.size() == 0) return entitylist; + entitylist.mRootNode = parent; Ogre::SceneManager *sceneMgr = parent->getCreator(); for(size_t i = 0;i < meshes.size();i++) { diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index f21069b75..70f467295 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -61,8 +61,9 @@ namespace NifOgre struct EntityList { std::vector mEntities; Ogre::Entity *mSkelBase; + Ogre::SceneNode *mRootNode; - EntityList() : mSkelBase(0) + EntityList() : mSkelBase(0), mRootNode(0) { } }; From a32740cf5ee1712299be24d00d8ba67d90fe2e29 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 22:41:26 -0700 Subject: [PATCH 46/92] Remove an unused parameter --- components/nifogre/ogre_nif_loader.cpp | 20 ++++++++------------ components/nifogre/ogre_nif_loader.hpp | 4 +--- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c74f1fe0d..9c294f8c3 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -180,20 +180,19 @@ void loadResource(Ogre::Resource *resource) buildBones(skel, node); } -static bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node, Ogre::SkeletonPtr *skel) +static bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node) { if(node->boneTrafo != NULL) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr tmp = skelMgr.getByName(name); - if(tmp.isNull()) + Ogre::SkeletonPtr skel = skelMgr.getByName(name); + if(skel.isNull()) { static NIFSkeletonLoader loader; - tmp = skelMgr.create(name, group, true, &loader); + skel = skelMgr.create(name, group, true, &loader); } - if(skel) *skel = tmp; return true; } @@ -205,7 +204,7 @@ static bool createSkeleton(const std::string &name, const std::string &group, Ni { if(!children[i].empty()) { - if(createSkeleton(name, group, children[i].getPtr(), skel)) + if(createSkeleton(name, group, children[i].getPtr())) return true; } } @@ -843,13 +842,10 @@ public: NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; -MeshPairList NIFLoader::load(const std::string &name, Ogre::SkeletonPtr *skel, const std::string &group) +MeshPairList NIFLoader::load(const std::string &name, const std::string &group) { MeshPairList meshes; - if(skel != NULL) - skel->setNull(); - Nif::NIFFile nif(name); if (nif.numRecords() < 1) { @@ -869,7 +865,7 @@ MeshPairList NIFLoader::load(const std::string &name, Ogre::SkeletonPtr *skel, c return meshes; } - bool hasSkel = NIFSkeletonLoader::createSkeleton(name, group, node, skel); + bool hasSkel = NIFSkeletonLoader::createSkeleton(name, group, node); NIFMeshLoader meshldr(name, group, hasSkel); meshldr.createMeshes(node, meshes); @@ -881,7 +877,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, const std::string { EntityList entitylist; - MeshPairList meshes = load(name, NULL, group); + MeshPairList meshes = load(name, group); if(meshes.size() == 0) return entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 70f467295..3f58097c0 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -86,9 +86,7 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { - static MeshPairList load(const std::string &name, - Ogre::SkeletonPtr *skel=NULL, - const std::string &group="General"); + static MeshPairList load(const std::string &name, const std::string &group); public: static EntityList createEntities(Ogre::SceneNode *parent, From 4109d0d9232b13813f53a74e78afcffb7f772b45 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jul 2012 22:47:56 -0700 Subject: [PATCH 47/92] Destroy entities removed from the NPC --- apps/openmw/mwrender/npcanimation.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 439f6fa2d..d740dd7db 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -405,8 +405,12 @@ void NpcAnimation::runAnimation(float timepassed) void NpcAnimation::removeEntities(std::vector &entities) { + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); for(size_t i = 0;i < entities.size();i++) + { mEntityList.mSkelBase->detachObjectFromBone(entities[i]); + sceneMgr->destroyEntity(entities[i]); + } entities.clear(); } From 02d39080c8e3f66d7ff77d5cc9617d8ba4174767 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 00:17:39 -0700 Subject: [PATCH 48/92] Destroy entities when they're done with. --- apps/openmw/mwrender/animation.cpp | 5 +++++ apps/openmw/mwrender/npcanimation.cpp | 20 ++++++++++++++++++++ apps/openmw/mwrender/npcanimation.hpp | 1 - 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 17c3f62ac..fddfe7b8a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace MWRender { @@ -28,6 +29,10 @@ Animation::Animation(OEngine::Render::OgreRenderer& _rend) Animation::~Animation() { + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) + sceneMgr->destroyEntity(mEntityList.mEntities[i]); + mEntityList.mEntities.clear(); } void Animation::startScript(std::string groupname, int mode, int loops) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d740dd7db..51bad3d0e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -17,6 +17,26 @@ using namespace NifOgre; namespace MWRender{ NpcAnimation::~NpcAnimation() { + removeEntities(head); + removeEntities(hair); + removeEntities(neck); + removeEntities(groin); + removeEntities(rWrist); + removeEntities(lWrist); + removeEntities(rForearm); + removeEntities(lForearm); + removeEntities(rupperArm); + removeEntities(lupperArm); + removeEntities(rfoot); + removeEntities(lfoot); + removeEntities(rAnkle); + removeEntities(lAnkle); + removeEntities(rKnee); + removeEntities(lKnee); + removeEntities(rUpperLeg); + removeEntities(lUpperLeg); + removeEntities(rclavicle); + removeEntities(lclavicle); } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index f27642720..6fb549408 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -40,7 +40,6 @@ private: std::vector hair; std::vector head; - Ogre::SceneNode* mInsert; bool isBeast; bool isFemale; std::string headModel; From 6611b0b317986430bac19cb57058cefb1d8c4af4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 10:09:16 -0700 Subject: [PATCH 49/92] Use an array instead of a bunch of nearly-identical if blocks --- apps/openmw/mwrender/npcanimation.cpp | 100 ++++++++------------------ 1 file changed, 28 insertions(+), 72 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 51bad3d0e..eb5fceb0e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -123,79 +123,35 @@ void NpcAnimation::updateParts() { bool apparelChanged = false; - //mInv.getSlot(MWWorld::InventoryStore::Slot_Robe); - if(robe != mInv.getSlot(MWWorld::InventoryStore::Slot_Robe)) + const struct { + MWWorld::ContainerStoreIterator *iter; + int slot; + } slotlist[] = { + { &robe, MWWorld::InventoryStore::Slot_Robe }, + { &skirtiter, MWWorld::InventoryStore::Slot_Skirt }, + { &helmet, MWWorld::InventoryStore::Slot_Helmet }, + { &cuirass, MWWorld::InventoryStore::Slot_Cuirass }, + { &greaves, MWWorld::InventoryStore::Slot_Greaves }, + { &leftpauldron, MWWorld::InventoryStore::Slot_LeftPauldron }, + { &rightpauldron, MWWorld::InventoryStore::Slot_RightPauldron }, + { &boots, MWWorld::InventoryStore::Slot_Boots }, // !isBeast + { &leftglove, MWWorld::InventoryStore::Slot_LeftGauntlet }, + { &rightglove, MWWorld::InventoryStore::Slot_RightGauntlet }, + { &shirt, MWWorld::InventoryStore::Slot_Shirt }, + { &pants, MWWorld::InventoryStore::Slot_Pants }, + }; + for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) { - // A robe was added or removed - robe = mInv.getSlot(MWWorld::InventoryStore::Slot_Robe); - removePartGroup(MWWorld::InventoryStore::Slot_Robe); - apparelChanged = true; - } - if(skirtiter != mInv.getSlot(MWWorld::InventoryStore::Slot_Skirt)) - { - skirtiter = mInv.getSlot(MWWorld::InventoryStore::Slot_Skirt); - removePartGroup(MWWorld::InventoryStore::Slot_Skirt); - apparelChanged = true; - } - if(helmet != mInv.getSlot(MWWorld::InventoryStore::Slot_Helmet)) - { - helmet = mInv.getSlot(MWWorld::InventoryStore::Slot_Helmet); - removePartGroup(MWWorld::InventoryStore::Slot_Helmet); - apparelChanged = true; - } - if(cuirass != mInv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)) - { - cuirass = mInv.getSlot(MWWorld::InventoryStore::Slot_Cuirass); - removePartGroup(MWWorld::InventoryStore::Slot_Cuirass); - apparelChanged = true; - } - if(greaves != mInv.getSlot(MWWorld::InventoryStore::Slot_Greaves)) - { - greaves = mInv.getSlot(MWWorld::InventoryStore::Slot_Greaves); - removePartGroup(MWWorld::InventoryStore::Slot_Greaves); - apparelChanged = true; - } - if(leftpauldron != mInv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron)) - { - leftpauldron = mInv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron); - removePartGroup(MWWorld::InventoryStore::Slot_LeftPauldron); - apparelChanged = true; - } - if(rightpauldron != mInv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron)) - { - rightpauldron = mInv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron); - removePartGroup(MWWorld::InventoryStore::Slot_RightPauldron); - apparelChanged = true; - } - if(!isBeast && boots != mInv.getSlot(MWWorld::InventoryStore::Slot_Boots)) - { - boots = mInv.getSlot(MWWorld::InventoryStore::Slot_Boots); - removePartGroup(MWWorld::InventoryStore::Slot_Boots); - apparelChanged = true; - } - if(leftglove != mInv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet)) - { - leftglove = mInv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet); - removePartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet); - apparelChanged = true; - } - if(rightglove != mInv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet)) - { - rightglove = mInv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet); - removePartGroup(MWWorld::InventoryStore::Slot_RightGauntlet); - apparelChanged = true; - } - if(shirt != mInv.getSlot(MWWorld::InventoryStore::Slot_Shirt)) - { - shirt = mInv.getSlot(MWWorld::InventoryStore::Slot_Shirt); - removePartGroup(MWWorld::InventoryStore::Slot_Shirt); - apparelChanged = true; - } - if(pants != mInv.getSlot(MWWorld::InventoryStore::Slot_Pants)) - { - pants = mInv.getSlot(MWWorld::InventoryStore::Slot_Pants); - removePartGroup(MWWorld::InventoryStore::Slot_Pants); - apparelChanged = true; + if(slotlist[i].iter == &boots && isBeast) + continue; + + MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); + if(*slotlist[i].iter != iter) + { + *slotlist[i].iter = iter; + removePartGroup(slotlist[i].slot); + apparelChanged = true; + } } if(apparelChanged) From 04e496a6ca4e1329c95b084b77e14572b0c61455 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 10:26:25 -0700 Subject: [PATCH 50/92] Store the entity lists for NPC parts --- apps/openmw/mwrender/npcanimation.cpp | 18 ++++++----- apps/openmw/mwrender/npcanimation.hpp | 44 +++++++++++++-------------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index eb5fceb0e..b4e39ff15 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -339,13 +339,13 @@ void NpcAnimation::updateParts() } } -std::vector NpcAnimation::insertBoundedPart(const std::string &mesh, const std::string &bonename) +NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, const std::string &bonename) { NifOgre::EntityList entities = NIFLoader::createEntities(mInsert, mesh); std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) parts[i]->setVisibilityFlags(RV_Actors); - return parts; + return entities; } void NpcAnimation::runAnimation(float timepassed) @@ -379,15 +379,19 @@ void NpcAnimation::runAnimation(float timepassed) } } -void NpcAnimation::removeEntities(std::vector &entities) +void NpcAnimation::removeEntities(NifOgre::EntityList &entities) { + assert(&entities != &mEntityList); + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < entities.size();i++) + for(size_t i = 0;i < entities.mEntities.size();i++) { - mEntityList.mSkelBase->detachObjectFromBone(entities[i]); - sceneMgr->destroyEntity(entities[i]); + mEntityList.mSkelBase->detachObjectFromBone(entities.mEntities[i]); + sceneMgr->destroyEntity(entities.mEntities[i]); } - entities.clear(); + entities.mEntities.clear(); + entities.mSkelBase = NULL; + entities.mRootNode = NULL; } void NpcAnimation::removeIndividualPart(int type) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 6fb549408..1eec1294f 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -19,26 +19,26 @@ private: int mPartPriorities[27]; //Bounded Parts - std::vector lclavicle; - std::vector rclavicle; - std::vector rupperArm; - std::vector lupperArm; - std::vector rUpperLeg; - std::vector lUpperLeg; - std::vector lForearm; - std::vector rForearm; - std::vector lWrist; - std::vector rWrist; - std::vector rKnee; - std::vector lKnee; - std::vector neck; - std::vector rAnkle; - std::vector lAnkle; - std::vector groin; - std::vector lfoot; - std::vector rfoot; - std::vector hair; - std::vector head; + NifOgre::EntityList lclavicle; + NifOgre::EntityList rclavicle; + NifOgre::EntityList rupperArm; + NifOgre::EntityList lupperArm; + NifOgre::EntityList rUpperLeg; + NifOgre::EntityList lUpperLeg; + NifOgre::EntityList lForearm; + NifOgre::EntityList rForearm; + NifOgre::EntityList lWrist; + NifOgre::EntityList rWrist; + NifOgre::EntityList rKnee; + NifOgre::EntityList lKnee; + NifOgre::EntityList neck; + NifOgre::EntityList rAnkle; + NifOgre::EntityList lAnkle; + NifOgre::EntityList groin; + NifOgre::EntityList lfoot; + NifOgre::EntityList rfoot; + NifOgre::EntityList hair; + NifOgre::EntityList head; bool isBeast; bool isFemale; @@ -63,10 +63,10 @@ private: public: NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); virtual ~NpcAnimation(); - std::vector insertBoundedPart(const std::string &mesh, const std::string &bonename); + NifOgre::EntityList insertBoundedPart(const std::string &mesh, const std::string &bonename); virtual void runAnimation(float timepassed); void updateParts(); - void removeEntities(std::vector &entities); + void removeEntities(NifOgre::EntityList &entities); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); From db948969c98cd032915a7aae450f1d522ab48bba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 11:14:13 -0700 Subject: [PATCH 51/92] Attach NPC parts to the proper bone --- apps/openmw/mwrender/npcanimation.cpp | 3 +- components/nifogre/ogre_nif_loader.cpp | 43 ++++++++++++++++++++++++++ components/nifogre/ogre_nif_loader.hpp | 6 ++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b4e39ff15..991ef827e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -341,7 +341,8 @@ void NpcAnimation::updateParts() NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, const std::string &bonename) { - NifOgre::EntityList entities = NIFLoader::createEntities(mInsert, mesh); + NifOgre::EntityList entities = NIFLoader::createEntities(mEntityList.mSkelBase, bonename, + mInsert->getCreator(), mesh); std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) parts[i]->setVisibilityFlags(RV_Actors); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 9c294f8c3..44992eea4 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -915,6 +915,49 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, const std::string return entitylist; } +EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneManager *sceneMgr, + const std::string &name, + const std::string &group) +{ + EntityList entitylist; + + MeshPairList meshes = load(name, group); + if(meshes.size() == 0) + return entitylist; + + for(size_t i = 0;i < meshes.size();i++) + { + entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first->getName())); + Ogre::Entity *entity = entitylist.mEntities.back(); + if(!entitylist.mSkelBase && entity->hasSkeleton()) + entitylist.mSkelBase = entity; + } + + if(entitylist.mSkelBase) + { + parent->attachObjectToBone(bonename, entitylist.mSkelBase); + for(size_t i = 0;i < entitylist.mEntities.size();i++) + { + Ogre::Entity *entity = entitylist.mEntities[i]; + if(entity != entitylist.mSkelBase && entity->hasSkeleton()) + { + entity->shareSkeletonInstanceWith(entitylist.mSkelBase); + parent->attachObjectToBone(bonename, entity); + } + else if(entity != entitylist.mSkelBase) + entitylist.mSkelBase->attachObjectToBone(meshes[i].second, entity); + } + } + else + { + for(size_t i = 0;i < entitylist.mEntities.size();i++) + parent->attachObjectToBone(bonename, entitylist.mEntities[i]); + } + + return entitylist; +} + /* More code currently not in use, from the old D source. This was used in the first attempt at loading NIF meshes, where each submesh diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 3f58097c0..2348a9b10 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -58,6 +58,7 @@ namespace Nif namespace NifOgre { +// FIXME: This should not be in NifOgre, it works agnostic of what model format is used struct EntityList { std::vector mEntities; Ogre::Entity *mSkelBase; @@ -89,6 +90,11 @@ class NIFLoader static MeshPairList load(const std::string &name, const std::string &group); public: + static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneManager *sceneMgr, + const std::string &name, + const std::string &group="General"); + static EntityList createEntities(Ogre::SceneNode *parent, const std::string &name, const std::string &group="General"); From 3b29d280b91c31113cde0860722fc4484769a164 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 12:47:16 -0700 Subject: [PATCH 52/92] Filter out skinned shapes that don't match the bone name --- components/nifogre/ogre_nif_loader.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 44992eea4..d72c45abd 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -926,12 +926,23 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo if(meshes.size() == 0) return entitylist; + std::string filter = "Tri "+bonename; for(size_t i = 0;i < meshes.size();i++) { - entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first->getName())); - Ogre::Entity *entity = entitylist.mEntities.back(); - if(!entitylist.mSkelBase && entity->hasSkeleton()) - entitylist.mSkelBase = entity; + Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first->getName()); + if(ent->hasSkeleton()) + { + if(meshes[i].second.length() < filter.length() || filter.compare(meshes[i].second) != 0) + { + sceneMgr->destroyEntity(ent); + meshes.erase(meshes.begin()+i); + i--; + continue; + } + if(!entitylist.mSkelBase) + entitylist.mSkelBase = ent; + } + entitylist.mEntities.push_back(ent); } if(entitylist.mSkelBase) @@ -946,7 +957,7 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo parent->attachObjectToBone(bonename, entity); } else if(entity != entitylist.mSkelBase) - entitylist.mSkelBase->attachObjectToBone(meshes[i].second, entity); + parent->attachObjectToBone(bonename, entity); } } else From e8ff304562ff6d87bd9781c3a6a6e6b1fd07963f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 12:53:45 -0700 Subject: [PATCH 53/92] Fix the initial normal vector for vertex fixups --- components/nifogre/ogre_nif_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index d72c45abd..23e1e99d5 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -540,7 +540,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // better to transform the bones into bind position, but there doesn't seem to // be a reliable way to do that. std::vector newVerts(srcVerts.size(), Ogre::Vector3(0.0f)); - std::vector newNorms(srcNorms.size(), Ogre::Vector3(1.0f)); + std::vector newNorms(srcNorms.size(), Ogre::Vector3(0.0f)); const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; From 2890904fb543c8555578fcb2e486d9812279a332 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 15:27:33 -0700 Subject: [PATCH 54/92] Use lowercase names for the mesh and skeleton resources To reduce the risk of duplicates due to different capitalizations. --- components/nifogre/ogre_nif_loader.cpp | 5 ++++- components/nifogre/ogre_nif_loader.hpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 23e1e99d5..6e2aa1663 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -807,6 +807,7 @@ public: Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); std::string fullname = mName+"@"+shape->name; + std::transform(fullname.begin(), fullname.end(), fullname.begin(), ::tolower); Ogre::MeshPtr mesh = meshMgr.getByName(fullname); if(mesh.isNull()) { @@ -842,10 +843,12 @@ public: NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; -MeshPairList NIFLoader::load(const std::string &name, const std::string &group) +MeshPairList NIFLoader::load(std::string name, const std::string &group) { MeshPairList meshes; + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + Nif::NIFFile nif(name); if (nif.numRecords() < 1) { diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 2348a9b10..b0b1ce27b 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -87,7 +87,7 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { - static MeshPairList load(const std::string &name, const std::string &group); + static MeshPairList load(std::string name, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, From 04b244cf9e63225e69ed707d44b9a71746471a6c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 17:18:21 -0700 Subject: [PATCH 55/92] Use the mesh's skeleton to transform shapes into "bind pose" instead of the NIF nodes --- components/nifogre/ogre_nif_loader.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 6e2aa1663..9fd3d44f1 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -526,6 +526,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Convert NiTriShape to Ogre::SubMesh void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape *shape) { + Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); std::vector srcVerts = data->vertices; @@ -536,6 +537,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // explicitly attached later. mesh->setSkeletonName(mName); + // Get the skeleton resource, so vertices can be transformed into the bones' initial state. + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + skel = skelMgr->getByName(mName); + skel->touch(); + // Convert vertices and normals to bone space from bind position. It would be // better to transform the bones into bind position, but there doesn't seem to // be a reliable way to do that. @@ -546,10 +552,13 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NodeList &bones = skin->bones; for(size_t b = 0;b < bones.length();b++) { - Ogre::Matrix4 mat(Ogre::Matrix4::IDENTITY); + Ogre::Bone *bone = skel->getBone(bones[b]->name); + Ogre::Matrix4 mat, mat2; mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat = bones[b]->getWorldTransform() * mat; + mat2.makeTransform(bone->_getDerivedPosition(), bone->_getDerivedScale(), + bone->_getDerivedOrientation()); + mat = mat2 * mat; const std::vector &weights = data->bones[b].weights; for(size_t i = 0;i < weights.size();i++) @@ -692,11 +701,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Assign bone weights for this TriShape if(skin != NULL) { - // Get the skeleton resource, so weights can be applied - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - Ogre::SkeletonPtr skel = skelMgr->getByName(mesh->getSkeletonName()); - skel->touch(); - const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; for(size_t i = 0;i < bones.length();i++) From 626dcd54dc1da12647be1316a6010fe30e689da3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 17:26:51 -0700 Subject: [PATCH 56/92] Store the skeleton name with the mesh resource loader instead of a flag --- components/nifogre/ogre_nif_loader.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 9fd3d44f1..c4e1398f9 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -509,7 +509,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mGroup; std::string mShapeName; std::string mMaterialName; - bool mHasSkel; + std::string mSkelName; void warn(const std::string &msg) { @@ -535,7 +535,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be // explicitly attached later. - mesh->setSkeletonName(mName); + mesh->setSkeletonName(mSkelName); // Get the skeleton resource, so vertices can be transformed into the bones' initial state. Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); @@ -579,7 +579,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader srcVerts = newVerts; srcNorms = newNorms; } - else if(!mHasSkel) + else if(mSkelName.length() == 0) { // No skinning and no skeleton, so just transform the vertices and // normals into position. @@ -752,10 +752,9 @@ class NIFMeshLoader : Ogre::ManualResourceLoader public: NIFMeshLoader() - : mHasSkel(false) { } - NIFMeshLoader(const std::string &name, const std::string &group, bool hasSkel) - : mName(name), mGroup(group), mHasSkel(hasSkel) + NIFMeshLoader(const std::string &name, const std::string &group, const std::string skelName) + : mName(name), mGroup(group), mSkelName(skelName) { } virtual void loadResource(Ogre::Resource *resource) @@ -765,8 +764,8 @@ public: if(!mShapeName.length()) { - if(mHasSkel) - mesh->setSkeletonName(mName); + if(mSkelName.length() > 0) + mesh->setSkeletonName(mSkelName); return; } @@ -874,7 +873,7 @@ MeshPairList NIFLoader::load(std::string name, const std::string &group) bool hasSkel = NIFSkeletonLoader::createSkeleton(name, group, node); - NIFMeshLoader meshldr(name, group, hasSkel); + NIFMeshLoader meshldr(name, group, (hasSkel ? name : std::string())); meshldr.createMeshes(node, meshes); return meshes; From 5154188110d7bcf223c4c73198b370de19d556bc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 18:29:25 -0700 Subject: [PATCH 57/92] Allow specifying an alternate skeleton for mesh skinning --- components/nifogre/ogre_nif_loader.cpp | 18 +++++++++++------- components/nifogre/ogre_nif_loader.hpp | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c4e1398f9..8e73c2503 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -539,7 +539,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Get the skeleton resource, so vertices can be transformed into the bones' initial state. Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - skel = skelMgr->getByName(mName); + skel = skelMgr->getByName(mSkelName); skel->touch(); // Convert vertices and normals to bone space from bind position. It would be @@ -808,7 +808,9 @@ public: const NiTriShape *shape = dynamic_cast(node); Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - std::string fullname = mName+"@"+shape->name; + std::string fullname = mName+"@shape="+shape->name; + if(mSkelName.length() > 0 && mName != mSkelName) + fullname += "@skel="+mSkelName; std::transform(fullname.begin(), fullname.end(), fullname.begin(), ::tolower); Ogre::MeshPtr mesh = meshMgr.getByName(fullname); @@ -846,11 +848,12 @@ public: NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; -MeshPairList NIFLoader::load(std::string name, const std::string &group) +MeshPairList NIFLoader::load(std::string name, std::string skelName, const std::string &group) { MeshPairList meshes; std::transform(name.begin(), name.end(), name.begin(), ::tolower); + std::transform(skelName.begin(), skelName.end(), skelName.begin(), ::tolower); Nif::NIFFile nif(name); if (nif.numRecords() < 1) @@ -873,7 +876,7 @@ MeshPairList NIFLoader::load(std::string name, const std::string &group) bool hasSkel = NIFSkeletonLoader::createSkeleton(name, group, node); - NIFMeshLoader meshldr(name, group, (hasSkel ? name : std::string())); + NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); meshldr.createMeshes(node, meshes); return meshes; @@ -883,7 +886,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, const std::string { EntityList entitylist; - MeshPairList meshes = load(name, group); + MeshPairList meshes = load(name, name, group); if(meshes.size() == 0) return entitylist; @@ -928,7 +931,7 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo { EntityList entitylist; - MeshPairList meshes = load(name, group); + MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), group); if(meshes.size() == 0) return entitylist; @@ -953,13 +956,14 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo if(entitylist.mSkelBase) { + entitylist.mSkelBase->shareSkeletonInstanceWith(parent); parent->attachObjectToBone(bonename, entitylist.mSkelBase); for(size_t i = 0;i < entitylist.mEntities.size();i++) { Ogre::Entity *entity = entitylist.mEntities[i]; if(entity != entitylist.mSkelBase && entity->hasSkeleton()) { - entity->shareSkeletonInstanceWith(entitylist.mSkelBase); + entity->shareSkeletonInstanceWith(parent); parent->attachObjectToBone(bonename, entity); } else if(entity != entitylist.mSkelBase) diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index b0b1ce27b..49d19fdb8 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -87,7 +87,7 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { - static MeshPairList load(std::string name, const std::string &group); + static MeshPairList load(std::string name, std::string skelName, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, From d9b64b77ec170935744d57db669d354c9a39dba5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 18:38:55 -0700 Subject: [PATCH 58/92] Attach skinned parts to the scene node instead of the named bone --- apps/openmw/mwrender/npcanimation.cpp | 2 +- components/nifogre/ogre_nif_loader.cpp | 7 ++++--- components/nifogre/ogre_nif_loader.hpp | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 991ef827e..00583d427 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -342,7 +342,7 @@ void NpcAnimation::updateParts() NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, const std::string &bonename) { NifOgre::EntityList entities = NIFLoader::createEntities(mEntityList.mSkelBase, bonename, - mInsert->getCreator(), mesh); + mInsert, mesh); std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) parts[i]->setVisibilityFlags(RV_Actors); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8e73c2503..646ec6c0b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -925,7 +925,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, const std::string } EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, - Ogre::SceneManager *sceneMgr, + Ogre::SceneNode *parentNode, const std::string &name, const std::string &group) { @@ -935,6 +935,7 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo if(meshes.size() == 0) return entitylist; + Ogre::SceneManager *sceneMgr = parentNode->getCreator(); std::string filter = "Tri "+bonename; for(size_t i = 0;i < meshes.size();i++) { @@ -957,14 +958,14 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo if(entitylist.mSkelBase) { entitylist.mSkelBase->shareSkeletonInstanceWith(parent); - parent->attachObjectToBone(bonename, entitylist.mSkelBase); + parentNode->attachObject(entitylist.mSkelBase); for(size_t i = 0;i < entitylist.mEntities.size();i++) { Ogre::Entity *entity = entitylist.mEntities[i]; if(entity != entitylist.mSkelBase && entity->hasSkeleton()) { entity->shareSkeletonInstanceWith(parent); - parent->attachObjectToBone(bonename, entity); + parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) parent->attachObjectToBone(bonename, entity); diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 49d19fdb8..76e94975c 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -91,7 +91,7 @@ class NIFLoader public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, - Ogre::SceneManager *sceneMgr, + Ogre::SceneNode *parentNode, const std::string &name, const std::string &group="General"); From 4af1bce659722bd06c89a492bfb291f231891d06 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 20:14:23 -0700 Subject: [PATCH 59/92] Restore and fix some missing parts --- apps/openmw/mwrender/npcanimation.cpp | 16 ++++++++++++++++ apps/openmw/mwrender/npcanimation.hpp | 4 ++++ components/nifogre/ogre_nif_loader.cpp | 3 ++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 00583d427..62e9fd580 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -20,7 +20,10 @@ NpcAnimation::~NpcAnimation() removeEntities(head); removeEntities(hair); removeEntities(neck); + removeEntities(chest); removeEntities(groin); + removeEntities(rHand); + removeEntities(lHand); removeEntities(rWrist); removeEntities(lWrist); removeEntities(rForearm); @@ -37,6 +40,7 @@ NpcAnimation::~NpcAnimation() removeEntities(lUpperLeg); removeEntities(rclavicle); removeEntities(lclavicle); + removeEntities(tail); } @@ -406,8 +410,14 @@ void NpcAnimation::removeIndividualPart(int type) removeEntities(hair); else if(type == ESM::PRT_Neck) //2 removeEntities(neck); + else if(type == ESM::PRT_Cuirass)//3 + removeEntities(chest); else if(type == ESM::PRT_Groin)//4 removeEntities(groin); + else if(type == ESM::PRT_RHand)//6 + removeEntities(rHand); + else if(type == ESM::PRT_LHand)//7 + removeEntities(lHand); else if(type == ESM::PRT_RWrist)//8 removeEntities(rWrist); else if(type == ESM::PRT_LWrist) //9 @@ -446,6 +456,8 @@ void NpcAnimation::removeIndividualPart(int type) else if(type == ESM::PRT_Weapon) //25 { } + else if(type == ESM::PRT_Tail) //26 + removeEntities(tail); } void NpcAnimation::reserveIndividualPart(int type, int group, int priority) @@ -487,6 +499,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, neck = insertBoundedPart(mesh, "Neck"); break; case ESM::PRT_Cuirass: //3 + chest = insertBoundedPart(mesh, "Chest"); break; case ESM::PRT_Groin: //4 groin = insertBoundedPart(mesh, "Groin"); @@ -494,8 +507,10 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, case ESM::PRT_Skirt: //5 break; case ESM::PRT_RHand: //6 + rHand = insertBoundedPart(mesh, "Right Hand"); break; case ESM::PRT_LHand: //7 + lHand = insertBoundedPart(mesh, "Left Hand"); break; case ESM::PRT_RWrist: //8 rWrist = insertBoundedPart(mesh, "Right Wrist"); @@ -550,6 +565,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, case ESM::PRT_Weapon: //25 break; case ESM::PRT_Tail: //26 + tail = insertBoundedPart(mesh, "Tail"); break; } return true; diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 1eec1294f..9dda169e2 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -38,7 +38,11 @@ private: NifOgre::EntityList lfoot; NifOgre::EntityList rfoot; NifOgre::EntityList hair; + NifOgre::EntityList rHand; + NifOgre::EntityList lHand; NifOgre::EntityList head; + NifOgre::EntityList chest; + NifOgre::EntityList tail; bool isBeast; bool isFemale; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 646ec6c0b..e8bc6133a 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -942,7 +942,8 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first->getName()); if(ent->hasSkeleton()) { - if(meshes[i].second.length() < filter.length() || filter.compare(meshes[i].second) != 0) + if(meshes[i].second.length() < filter.length() || + meshes[i].second.compare(0, filter.length(), filter) != 0) { sceneMgr->destroyEntity(ent); meshes.erase(meshes.begin()+i); From bd74ab027a16801da7db778f62c9f4a898517cda Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 21:21:49 -0700 Subject: [PATCH 60/92] Mirror left-sided parts --- components/nifogre/ogre_nif_loader.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e8bc6133a..c470363b0 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -956,6 +957,10 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo entitylist.mEntities.push_back(ent); } + Ogre::Vector3 scale(1.0f); + if(bonename.find("Left") != std::string::npos) + scale.x *= -1.0f; + if(entitylist.mSkelBase) { entitylist.mSkelBase->shareSkeletonInstanceWith(parent); @@ -969,13 +974,19 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) - parent->attachObjectToBone(bonename, entity); + { + Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); + tag->setScale(scale); + } } } else { for(size_t i = 0;i < entitylist.mEntities.size();i++) - parent->attachObjectToBone(bonename, entitylist.mEntities[i]); + { + Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entitylist.mEntities[i]); + tag->setScale(scale); + } } return entitylist; From b505d4ace0977522aab257b86caca4cad1d320af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 21:39:50 -0700 Subject: [PATCH 61/92] Fix feet and entity part detachment --- apps/openmw/mwrender/npcanimation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 62e9fd580..138a8eb86 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -391,7 +391,7 @@ void NpcAnimation::removeEntities(NifOgre::EntityList &entities) Ogre::SceneManager *sceneMgr = mInsert->getCreator(); for(size_t i = 0;i < entities.mEntities.size();i++) { - mEntityList.mSkelBase->detachObjectFromBone(entities.mEntities[i]); + entities.mEntities[i]->detachFromParent(); sceneMgr->destroyEntity(entities.mEntities[i]); } entities.mEntities.clear(); @@ -533,10 +533,10 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, lupperArm = insertBoundedPart(mesh, "Left Upper Arm"); break; case ESM::PRT_RFoot: //15 - lupperArm = insertBoundedPart(mesh, "Right Foot"); + rfoot = insertBoundedPart(mesh, "Right Foot"); break; case ESM::PRT_LFoot: //16 - lupperArm = insertBoundedPart(mesh, "Left Foot"); + lfoot = insertBoundedPart(mesh, "Left Foot"); break; case ESM::PRT_RAnkle: //17 rAnkle = insertBoundedPart(mesh, "Right Ankle"); From c9b1f72d81b00f9e809b278885795d5300557a16 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 22:31:07 -0700 Subject: [PATCH 62/92] Use a case-insensitive compare for the part filter --- components/nifogre/ogre_nif_loader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c470363b0..639ebaa12 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -944,7 +944,8 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo if(ent->hasSkeleton()) { if(meshes[i].second.length() < filter.length() || - meshes[i].second.compare(0, filter.length(), filter) != 0) + !boost::algorithm::lexicographical_compare(meshes[i].second.substr(0, filter.length()), + filter, boost::algorithm::is_iequal())) { sceneMgr->destroyEntity(ent); meshes.erase(meshes.begin()+i); From 6caa39629d85f22320eff0abd5def679a043a0c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jul 2012 22:32:26 -0700 Subject: [PATCH 63/92] Reimplement the skirt part --- apps/openmw/mwrender/npcanimation.cpp | 4 ++++ apps/openmw/mwrender/npcanimation.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 138a8eb86..9f28dbf13 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -22,6 +22,7 @@ NpcAnimation::~NpcAnimation() removeEntities(neck); removeEntities(chest); removeEntities(groin); + removeEntities(skirt); removeEntities(rHand); removeEntities(lHand); removeEntities(rWrist); @@ -414,6 +415,8 @@ void NpcAnimation::removeIndividualPart(int type) removeEntities(chest); else if(type == ESM::PRT_Groin)//4 removeEntities(groin); + else if(type == ESM::PRT_Skirt)//5 + removeEntities(skirt); else if(type == ESM::PRT_RHand)//6 removeEntities(rHand); else if(type == ESM::PRT_LHand)//7 @@ -505,6 +508,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, groin = insertBoundedPart(mesh, "Groin"); break; case ESM::PRT_Skirt: //5 + skirt = insertBoundedPart(mesh, "Groin"); break; case ESM::PRT_RHand: //6 rHand = insertBoundedPart(mesh, "Right Hand"); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 9dda169e2..d4b2a5b9e 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -35,6 +35,7 @@ private: NifOgre::EntityList rAnkle; NifOgre::EntityList lAnkle; NifOgre::EntityList groin; + NifOgre::EntityList skirt; NifOgre::EntityList lfoot; NifOgre::EntityList rfoot; NifOgre::EntityList hair; From a86ed46ec495329b5fafc08e5893bdaa43afac2b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jul 2012 11:00:26 -0700 Subject: [PATCH 64/92] Use the race ID specified in the ref base's record instead of the race record The latter is localized and doesn't match with international versions. --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 9f28dbf13..a693a6b46 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -74,7 +74,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere isFemale = !!(ref->base->flags&ESM::NPC::Female); isBeast = !!(race->data.flags&ESM::Race::Beast); - bodyRaceID = "b_n_"+race->name; + bodyRaceID = "b_n_"+ref->base->race; std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower); /*std::cout << "Race: " << ref->base->race ; From e7602199530baab8c74664af037ff71564b24733 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jul 2012 11:36:36 -0700 Subject: [PATCH 65/92] Use a unique loader for each skeleton resource --- components/nifogre/ogre_nif_loader.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 639ebaa12..66b711737 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -130,7 +130,7 @@ public: }; -struct NIFSkeletonLoader : public Ogre::ManualResourceLoader { +class NIFSkeletonLoader : public Ogre::ManualResourceLoader { static void warn(const std::string &msg) { @@ -171,6 +171,11 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent= } } + +typedef std::map LoaderMap; +static LoaderMap sLoaders; + +public: void loadResource(Ogre::Resource *resource) { Ogre::Skeleton *skel = dynamic_cast(resource); @@ -181,7 +186,7 @@ void loadResource(Ogre::Resource *resource) buildBones(skel, node); } -static bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node) +bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node) { if(node->boneTrafo != NULL) { @@ -190,8 +195,8 @@ static bool createSkeleton(const std::string &name, const std::string &group, Ni Ogre::SkeletonPtr skel = skelMgr.getByName(name); if(skel.isNull()) { - static NIFSkeletonLoader loader; - skel = skelMgr.create(name, group, true, &loader); + NIFSkeletonLoader *loader = &sLoaders[name]; + skel = skelMgr.create(name, group, true, loader); } return true; @@ -214,6 +219,7 @@ static bool createSkeleton(const std::string &name, const std::string &group, Ni } }; +NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; // Conversion of blend / test mode from NIF -> OGRE. @@ -875,7 +881,8 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: return meshes; } - bool hasSkel = NIFSkeletonLoader::createSkeleton(name, group, node); + NIFSkeletonLoader skelldr; + bool hasSkel = skelldr.createSkeleton(name, group, node); NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); meshldr.createMeshes(node, meshes); From f6c837468f1c250d75f2dba1a2fc297c518899fc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jul 2012 11:44:08 -0700 Subject: [PATCH 66/92] Load the proper NIF skeleton --- components/nifogre/ogre_nif_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 66b711737..8795efbdf 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -882,7 +882,7 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: } NIFSkeletonLoader skelldr; - bool hasSkel = skelldr.createSkeleton(name, group, node); + bool hasSkel = skelldr.createSkeleton(skelName, group, node); NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); meshldr.createMeshes(node, meshes); From c2acf47d880d2adfd20a9f6b3eca680a2ec0e31b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jul 2012 20:30:10 -0700 Subject: [PATCH 67/92] Store the list of keyframe controllers when building the bones --- components/nifogre/ogre_nif_loader.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8795efbdf..8ba5c9752 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -144,7 +144,7 @@ static void fail(const std::string &msg) } -void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent=NULL) +void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector &ctrls, Ogre::Bone *parent=NULL) { Ogre::Bone *bone; if(!skel->hasBone(node->name)) @@ -159,6 +159,14 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent= bone->setBindingPose(); bone->setInitialState(); + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiKeyframeController) + ctrls.push_back(static_cast(ctrl.getPtr())); + ctrl = ctrl->next; + } + const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { @@ -166,7 +174,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent= for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), bone); + buildBones(skel, children[i].getPtr(), ctrls, bone); } } } @@ -183,7 +191,13 @@ void loadResource(Ogre::Resource *resource) Nif::NIFFile nif(skel->getName()); const Nif::Node *node = dynamic_cast(nif.getRecord(0)); - buildBones(skel, node); + + std::vector ctrls; + buildBones(skel, node, ctrls); + + // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file + if(ctrls.size() == 0) // No animations? Then we're done. + return; } bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node) From 0986cd5962d8dfa3279d761d7352ee441e11ae61 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jul 2012 20:48:12 -0700 Subject: [PATCH 68/92] Get the animation controller target names --- components/nifogre/ogre_nif_loader.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8ba5c9752..8cdb2e99b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -195,9 +195,27 @@ void loadResource(Ogre::Resource *resource) std::vector ctrls; buildBones(skel, node, ctrls); + std::vector targets; // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file if(ctrls.size() == 0) // No animations? Then we're done. return; + + float maxtime = 0.0f; + for(size_t i = 0;i < ctrls.size();i++) + { + Nif::NiKeyframeController *ctrl = ctrls[i]; + maxtime = std::max(maxtime, ctrl->timeStop); + Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); + if(target != NULL) + targets.push_back(target->name); + } + + if(targets.size() != ctrls.size()) + { + warn("Target size mismatch ("+Ogre::StringConverter::toString(targets.size())+" targets, "+ + Ogre::StringConverter::toString(ctrls.size())+" controllers)"); + return; + } } bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node) From 4210880c061ea7698e0a96cd0ef7292b55a06c14 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jul 2012 21:46:16 -0700 Subject: [PATCH 69/92] Load the animation tracks into Ogre --- components/nifogre/ogre_nif_loader.cpp | 97 ++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8cdb2e99b..eea53e963 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -180,6 +180,15 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector vectors */ +template +struct KeyTimeSort +{ + bool operator()(const Nif::KeyT &lhs, const Nif::KeyT &rhs) const + { return lhs.mTime < rhs.mTime; } +}; + + typedef std::map LoaderMap; static LoaderMap sLoaders; @@ -216,6 +225,94 @@ void loadResource(Ogre::Resource *resource) Ogre::StringConverter::toString(ctrls.size())+" controllers)"); return; } + + Ogre::Animation *anim = skel->createAnimation("default", maxtime); + /* HACK: Pre-create the node tracks by matching the track IDs with the + * bone IDs. Otherwise, Ogre animates the wrong bones. */ + size_t bonecount = skel->getNumBones(); + for(size_t i = 0;i < bonecount;i++) + anim->createNodeTrack(i, skel->getBone(i)); + + for(size_t i = 0;i < ctrls.size();i++) + { + Nif::NiKeyframeController *kfc = ctrls[i]; + Nif::NiKeyframeData *kf = kfc->data.getPtr(); + + /* Get the keyframes and make sure they're sorted first to last */ + QuaternionKeyList quatkeys = kf->mRotations; + Vector3KeyList trankeys = kf->mTranslations; + FloatKeyList scalekeys = kf->mScales; + std::sort(quatkeys.mKeys.begin(), quatkeys.mKeys.end(), KeyTimeSort()); + std::sort(trankeys.mKeys.begin(), trankeys.mKeys.end(), KeyTimeSort()); + std::sort(scalekeys.mKeys.begin(), scalekeys.mKeys.end(), KeyTimeSort()); + + QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); + Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); + FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); + + Ogre::Bone *bone = skel->getBone(targets[i]); + const Ogre::Quaternion startquat = bone->getInitialOrientation(); + const Ogre::Vector3 starttrans = bone->getInitialPosition(); + const Ogre::Vector3 startscale = bone->getInitialScale(); + Ogre::NodeAnimationTrack *nodetrack = anim->getNodeTrack(bone->getHandle()); + + Ogre::Quaternion lastquat, curquat; + Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); + Ogre::Vector3 lastscale(1.0f), curscale(1.0f); + if(quatiter != quatkeys.mKeys.end()) + lastquat = curquat = startquat.Inverse() * quatiter->mValue; + if(traniter != trankeys.mKeys.end()) + lasttrans = curtrans = traniter->mValue - starttrans; + if(scaleiter != scalekeys.mKeys.end()) + lastscale = curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + bool didlast = false; + while(!didlast) + { + float curtime = kfc->timeStop; + if(quatiter != quatkeys.mKeys.end()) + curtime = std::min(curtime, quatiter->mTime); + if(traniter != trankeys.mKeys.end()) + curtime = std::min(curtime, traniter->mTime); + if(scaleiter != scalekeys.mKeys.end()) + curtime = std::min(curtime, scaleiter->mTime); + + curtime = std::max(curtime, kfc->timeStart); + if(curtime >= kfc->timeStop) + { + didlast = true; + curtime = kfc->timeStop; + } + + // Get the latest quaternion, translation, and scale for the + // current time + while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) + { + lastquat = curquat; + curquat = startquat.Inverse() * quatiter->mValue; + quatiter++; + } + while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) + { + lasttrans = curtrans; + curtrans = traniter->mValue - starttrans; + traniter++; + } + while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) + { + lastscale = curscale; + curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + scaleiter++; + } + + Ogre::TransformKeyFrame *kframe; + kframe = nodetrack->createNodeKeyFrame(curtime); + // FIXME: These should be interpolated since they don't all fall on the same time + kframe->setRotation(curquat); + kframe->setTranslate(curtrans); + kframe->setScale(curscale); + } + } + anim->optimise(); } bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node) From 8b5b74f9ee3ec4b291e87d92fb01bfd78b177638 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jul 2012 22:34:26 -0700 Subject: [PATCH 70/92] Add a quick hack to let "playgroup all" work on creatures and NPCs --- apps/openmw/mwrender/creatureanimation.cpp | 42 +++++++++++++++------- apps/openmw/mwrender/npcanimation.cpp | 42 +++++++++++++++------- 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index fd2855154..492749553 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -52,6 +52,18 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O } ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setEnabled(true); + state->setLoop(false); + } + } } } @@ -59,20 +71,26 @@ void CreatureAnimation::runAnimation(float timepassed) { if(mAnimate > 0) { - //Add the amount of time passed to time - - //Handle the animation transforms dependent on time - - //Handle the shapes dependent on animation transforms mTime += timepassed; - if(mTime >= mStopTime) + + if(mEntityList.mSkelBase) { - mAnimate--; - //std::cout << "Stopping the animation\n"; - if(mAnimate == 0) - mTime = mStopTime; - else - mTime = mStartTime + (mTime - mStopTime); + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setTimePosition(mTime); + if(state->getTimePosition() >= state->getLength()) + { + mAnimate--; + //std::cout << "Stopping the animation\n"; + if(mAnimate == 0) + mTime = state->getLength(); + else + mTime = mTime - state->getLength(); + } + } } handleAnimationTransforms(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a693a6b46..8c34acba2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -117,6 +117,18 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere //stay in the same place when we skipanim, or open a gui window } + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setEnabled(true); + state->setLoop(false); + } + } + if(isFemale) mInsert->scale(race->data.height.female, race->data.height.female, race->data.height.female); else @@ -361,24 +373,30 @@ void NpcAnimation::runAnimation(float timepassed) timeToChange = 0; updateParts(); } - timeToChange += timepassed; - //1. Add the amount of time passed to time - - //2. Handle the animation transforms dependent on time - - //3. Handle the shapes dependent on animation transforms if(mAnimate > 0) { mTime += timepassed; - if(mTime > mStopTime) + + if(mEntityList.mSkelBase) { - mAnimate--; - if(mAnimate == 0) - mTime = mStopTime; - else - mTime = mStartTime + (mTime - mStopTime); + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setTimePosition(mTime); + if(state->getTimePosition() >= state->getLength()) + { + mAnimate--; + //std::cout << "Stopping the animation\n"; + if(mAnimate == 0) + mTime = state->getLength(); + else + mTime = mTime - state->getLength(); + } + } } handleAnimationTransforms(); From 66860825cfd4cc74154eb9fb147ed3e73506211c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Jul 2012 00:29:22 -0700 Subject: [PATCH 71/92] Remove some unused and unneeded bits from the Animation class --- apps/openmw/mwrender/animation.cpp | 137 +-------------------- apps/openmw/mwrender/animation.hpp | 14 --- apps/openmw/mwrender/creatureanimation.cpp | 2 - apps/openmw/mwrender/npcanimation.cpp | 2 - 4 files changed, 1 insertion(+), 154 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fddfe7b8a..06fd34e3c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -15,15 +15,7 @@ Animation::Animation(OEngine::Render::OgreRenderer& _rend) : mInsert(NULL) , mRend(_rend) , mTime(0.0f) - , mStartTime(0.0f) - , mStopTime(0.0f) , mAnimate(0) - , mRindexI() - , mTindexI() - , mShapeNumber(0) - , mShapeIndexI() - , mTransformations(NULL) - , mTextmappings(NULL) { } @@ -37,79 +29,11 @@ Animation::~Animation() void Animation::startScript(std::string groupname, int mode, int loops) { - //If groupname is recognized set animate to true - //Set the start time and stop time - //How many times to loop if(groupname == "all") { mAnimate = loops; - mTime = mStartTime; + mTime = 0.0f; } - else if(mTextmappings) - { - std::string startName = groupname + ": loop start"; - std::string stopName = groupname + ": loop stop"; - - bool first = false; - - if(loops > 1) - { - startName = groupname + ": loop start"; - stopName = groupname + ": loop stop"; - - for(std::map::iterator iter = mTextmappings->begin(); iter != mTextmappings->end(); iter++) - { - std::string current = iter->first.substr(0, startName.size()); - std::transform(current.begin(), current.end(), current.begin(), ::tolower); - std::string current2 = iter->first.substr(0, stopName.size()); - std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower); - - if(current == startName) - { - mStartTime = iter->second; - mAnimate = loops; - mTime = mStartTime; - first = true; - } - if(current2 == stopName) - { - mStopTime = iter->second; - if(first) - break; - } - } - } - - if(!first) - { - startName = groupname + ": start"; - stopName = groupname + ": stop"; - - for(std::map::iterator iter = mTextmappings->begin(); iter != mTextmappings->end(); iter++) - { - std::string current = iter->first.substr(0, startName.size()); - std::transform(current.begin(), current.end(), current.begin(), ::tolower); - std::string current2 = iter->first.substr(0, stopName.size()); - std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower); - - if(current == startName) - { - mStartTime = iter->second; - mAnimate = loops; - mTime = mStartTime; - first = true; - } - if(current2 == stopName) - { - mStopTime = iter->second; - if(first) - break; - } - } - } - - } - } @@ -118,63 +42,4 @@ void Animation::stopScript() mAnimate = 0; } - -bool Animation::timeIndex(float time, const std::vector ×, int &i, int &j, float &x) -{ - size_t count; - if((count=times.size()) == 0) - return false; - - if(time <= times[0]) - { - i = j = 0; - x = 0.0; - return true; - } - if(time >= times[count-1]) - { - i = j = count - 1; - x = 0.0; - return true; - } - - if(i < 0 || (size_t)i >= count) - i = 0; - - float tI = times[i]; - if(time > tI) - { - j = i + 1; - float tJ; - while(time >= (tJ=times[j])) - { - i = j++; - tI = tJ; - } - x = (time-tI) / (tJ-tI); - return true; - } - - if(time < tI) - { - j = i - 1; - float tJ; - while(time <= (tJ=times[j])) - { - i = j--; - tI = tJ; - } - x = (time-tI) / (tJ-tI); - return true; - } - - j = i; - x = 0.0; - return true; -} - -void Animation::handleAnimationTransforms() -{ -} - } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index def7f226c..bed02f85f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -26,23 +26,9 @@ protected: static std::map sUniqueIDs; float mTime; - float mStartTime; - float mStopTime; int mAnimate; - //Represents a rotation index for each bone - std::vectormRindexI; - //Represents a translation index for each bone - std::vectormTindexI; - //Only shapes with morphing data will use a shape number - int mShapeNumber; - std::vector > mShapeIndexI; - - std::vector* mTransformations; - std::map* mTextmappings; NifOgre::EntityList mEntityList; - void handleAnimationTransforms(); - bool timeIndex( float time, const std::vector & times, int & i, int & j, float & x ); public: Animation(OEngine::Render::OgreRenderer& _rend); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 492749553..ee1fd45ba 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -92,8 +92,6 @@ void CreatureAnimation::runAnimation(float timepassed) } } } - - handleAnimationTransforms(); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 8c34acba2..4d2ca557d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -398,8 +398,6 @@ void NpcAnimation::runAnimation(float timepassed) } } } - - handleAnimationTransforms(); } } From 2db80a1504576d15df11b9988fb5beabf3f4bf8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Jul 2012 00:53:12 -0700 Subject: [PATCH 72/92] Rename a couple methods to match their scripting counterparts --- apps/openmw/mwrender/actors.cpp | 8 +++----- apps/openmw/mwrender/animation.cpp | 4 ++-- apps/openmw/mwrender/animation.hpp | 8 ++++---- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index b37921b0c..a64397d49 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -122,15 +122,13 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store){ void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number){ if(mAllActors.find(ptr) != mAllActors.end()) - mAllActors[ptr]->startScript(groupName, mode, number); + mAllActors[ptr]->playGroup(groupName, mode, number); } void Actors::skipAnimation (const MWWorld::Ptr& ptr){ if(mAllActors.find(ptr) != mAllActors.end()) - mAllActors[ptr]->stopScript(); + mAllActors[ptr]->skipAnim(); } void Actors::update (float duration){ for(std::map::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++) - { - (iter->second)->runAnimation(duration); - } + iter->second->runAnimation(duration); } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 06fd34e3c..1f0a99518 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -27,7 +27,7 @@ Animation::~Animation() mEntityList.mEntities.clear(); } -void Animation::startScript(std::string groupname, int mode, int loops) +void Animation::playGroup(std::string groupname, int mode, int loops) { if(groupname == "all") { @@ -37,7 +37,7 @@ void Animation::startScript(std::string groupname, int mode, int loops) } -void Animation::stopScript() +void Animation::skipAnim() { mAnimate = 0; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index bed02f85f..0ed4545f2 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -32,11 +32,11 @@ protected: public: Animation(OEngine::Render::OgreRenderer& _rend); - virtual void runAnimation(float timepassed) = 0; - void startScript(std::string groupname, int mode, int loops); - void stopScript(); - virtual ~Animation(); + + void playGroup(std::string groupname, int mode, int loops); + void skipAnim(); + virtual void runAnimation(float timepassed) = 0; }; } From 4bc93ecd1a9c851e5bff3d3670f0dd74e7d61201 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Jul 2012 11:09:05 -0700 Subject: [PATCH 73/92] Use the skeleton name for the main animation --- components/nifogre/ogre_nif_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index eea53e963..2aa7cd433 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -226,7 +226,7 @@ void loadResource(Ogre::Resource *resource) return; } - Ogre::Animation *anim = skel->createAnimation("default", maxtime); + Ogre::Animation *anim = skel->createAnimation(skel->getName(), maxtime); /* HACK: Pre-create the node tracks by matching the track IDs with the * bone IDs. Otherwise, Ogre animates the wrong bones. */ size_t bonecount = skel->getNumBones(); From fcaa8aae06d791c37daab0897f4fd19f6b2129b5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Jul 2012 11:26:09 -0700 Subject: [PATCH 74/92] Don't skip animation state updates for NPCs --- apps/openmw/mwrender/npcanimation.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4d2ca557d..f66ab8403 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -113,8 +113,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere } } base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones - //stay in the same place when we skipanim, or open a gui window } if(mEntityList.mSkelBase) From 81ce8dbe122db57110a32996975356bb057e0e91 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Jul 2012 14:41:26 -0700 Subject: [PATCH 75/92] Combine animation handling into the base class --- apps/openmw/mwrender/animation.cpp | 29 ++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 25 ++----------------- apps/openmw/mwrender/npcanimation.cpp | 25 +------------------ 4 files changed, 33 insertions(+), 48 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1f0a99518..88f6cebe6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -42,4 +42,33 @@ void Animation::skipAnim() mAnimate = 0; } +void Animation::runAnimation(float timepassed) +{ + if(mAnimate != 0) + { + mTime += timepassed; + + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setTimePosition(mTime); + if(mTime >= state->getLength()) + { + if(mAnimate != -1) + mAnimate--; + //std::cout << "Stopping the animation\n"; + if(mAnimate == 0) + mTime = state->getLength(); + else + mTime = mTime - state->getLength(); + } + } + } + } +} + } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 0ed4545f2..5de314df1 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -36,7 +36,7 @@ public: void playGroup(std::string groupname, int mode, int loops); void skipAnim(); - virtual void runAnimation(float timepassed) = 0; + virtual void runAnimation(float timepassed); }; } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index ee1fd45ba..9d2a58a1e 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -69,30 +69,9 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O void CreatureAnimation::runAnimation(float timepassed) { - if(mAnimate > 0) - { - mTime += timepassed; + // Placeholder - if(mEntityList.mSkelBase) - { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) - { - Ogre::AnimationState *state = as.getNext(); - state->setTimePosition(mTime); - if(state->getTimePosition() >= state->getLength()) - { - mAnimate--; - //std::cout << "Stopping the animation\n"; - if(mAnimate == 0) - mTime = state->getLength(); - else - mTime = mTime - state->getLength(); - } - } - } - } + Animation::runAnimation(timepassed); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index f66ab8403..3cca110e3 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -373,30 +373,7 @@ void NpcAnimation::runAnimation(float timepassed) } timeToChange += timepassed; - if(mAnimate > 0) - { - mTime += timepassed; - - if(mEntityList.mSkelBase) - { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) - { - Ogre::AnimationState *state = as.getNext(); - state->setTimePosition(mTime); - if(state->getTimePosition() >= state->getLength()) - { - mAnimate--; - //std::cout << "Stopping the animation\n"; - if(mAnimate == 0) - mTime = state->getLength(); - else - mTime = mTime - state->getLength(); - } - } - } - } + Animation::runAnimation(timepassed); } void NpcAnimation::removeEntities(NifOgre::EntityList &entities) From c5b9098517714827d575166de0163aaed26e1398 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Jul 2012 17:09:16 -0700 Subject: [PATCH 76/92] Remove an unused field from EntityList --- apps/openmw/mwrender/npcanimation.cpp | 1 - components/nifogre/ogre_nif_loader.cpp | 1 - components/nifogre/ogre_nif_loader.hpp | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 3cca110e3..e89122e4b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -388,7 +388,6 @@ void NpcAnimation::removeEntities(NifOgre::EntityList &entities) } entities.mEntities.clear(); entities.mSkelBase = NULL; - entities.mRootNode = NULL; } void NpcAnimation::removeIndividualPart(int type) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 2aa7cd433..2c5b7e324 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1027,7 +1027,6 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, const std::string if(meshes.size() == 0) return entitylist; - entitylist.mRootNode = parent; Ogre::SceneManager *sceneMgr = parent->getCreator(); for(size_t i = 0;i < meshes.size();i++) { diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 76e94975c..a9195f2fb 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -62,9 +62,8 @@ namespace NifOgre struct EntityList { std::vector mEntities; Ogre::Entity *mSkelBase; - Ogre::SceneNode *mRootNode; - EntityList() : mSkelBase(0), mRootNode(0) + EntityList() : mSkelBase(0) { } }; From e81fc42daaf0adc5ae296b7781aea4270f299b9d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Jul 2012 17:12:41 -0700 Subject: [PATCH 77/92] Remove the beast-race special cases from updateParts The special handling should happen at a much lower level, and prevent the objects from being equipped in the first place. --- apps/openmw/mwrender/npcanimation.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e89122e4b..415de5859 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -149,7 +149,7 @@ void NpcAnimation::updateParts() { &greaves, MWWorld::InventoryStore::Slot_Greaves }, { &leftpauldron, MWWorld::InventoryStore::Slot_LeftPauldron }, { &rightpauldron, MWWorld::InventoryStore::Slot_RightPauldron }, - { &boots, MWWorld::InventoryStore::Slot_Boots }, // !isBeast + { &boots, MWWorld::InventoryStore::Slot_Boots }, { &leftglove, MWWorld::InventoryStore::Slot_LeftGauntlet }, { &rightglove, MWWorld::InventoryStore::Slot_RightGauntlet }, { &shirt, MWWorld::InventoryStore::Slot_Shirt }, @@ -157,9 +157,6 @@ void NpcAnimation::updateParts() }; for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) { - if(slotlist[i].iter == &boots && isBeast) - continue; - MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); if(*slotlist[i].iter != iter) { @@ -235,7 +232,7 @@ void NpcAnimation::updateParts() std::vector parts = armor->parts.parts; addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); } - if(!isBeast && boots != mInv.end()) + if(boots != mInv.end()) { if(boots->getTypeName() == typeid(ESM::Clothing).name()) { From 77446a0d58fde458f1ba01788f2854e1e2b1b558 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Jul 2012 17:39:57 -0700 Subject: [PATCH 78/92] Fix skipAnim, only skip one animation update --- apps/openmw/mwrender/animation.cpp | 6 ++++-- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 88f6cebe6..653a506e8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -16,6 +16,7 @@ Animation::Animation(OEngine::Render::OgreRenderer& _rend) , mRend(_rend) , mTime(0.0f) , mAnimate(0) + , mSkipFrame(false) { } @@ -39,12 +40,12 @@ void Animation::playGroup(std::string groupname, int mode, int loops) void Animation::skipAnim() { - mAnimate = 0; + mSkipFrame = true; } void Animation::runAnimation(float timepassed) { - if(mAnimate != 0) + if(mAnimate != 0 && !mSkipFrame) { mTime += timepassed; @@ -69,6 +70,7 @@ void Animation::runAnimation(float timepassed) } } } + mSkipFrame = false; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5de314df1..ae1477666 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -27,6 +27,7 @@ protected: float mTime; int mAnimate; + bool mSkipFrame; NifOgre::EntityList mEntityList; From d8cb6855437813e1145f213c3cb83f43b0580923 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Jul 2012 18:03:01 -0700 Subject: [PATCH 79/92] Interpolate keyframes when creating them Probably not fully correct, but better than nothing. --- components/nifogre/ogre_nif_loader.cpp | 28 ++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 2c5b7e324..e695cd959 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -306,10 +306,30 @@ void loadResource(Ogre::Resource *resource) Ogre::TransformKeyFrame *kframe; kframe = nodetrack->createNodeKeyFrame(curtime); - // FIXME: These should be interpolated since they don't all fall on the same time - kframe->setRotation(curquat); - kframe->setTranslate(curtrans); - kframe->setScale(curscale); + if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) + kframe->setRotation(curquat); + else + { + QuaternionKeyList::VecType::const_iterator last = quatiter-1; + float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); + kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); + } + if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) + kframe->setTranslate(curtrans); + else + { + Vector3KeyList::VecType::const_iterator last = traniter-1; + float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); + kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); + } + if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) + kframe->setScale(curscale); + else + { + FloatKeyList::VecType::const_iterator last = scaleiter-1; + float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); + kframe->setScale(lastscale + ((curscale-lastscale)*diff)); + } } } anim->optimise(); From 4035d7370e5288898d1e590030b1aa4f853bad28 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Jul 2012 22:04:05 -0700 Subject: [PATCH 80/92] Fix name/filter comparison --- components/nifogre/ogre_nif_loader.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e695cd959..c34f69404 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -25,6 +25,8 @@ #include "ogre_nif_loader.hpp" +#include + #include #include #include @@ -1080,6 +1082,11 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, const std::string return entitylist; } +static bool checklow(const char &a, const char &b) +{ + return ::tolower(a) == ::tolower(b); +} + EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, const std::string &name, @@ -1099,8 +1106,7 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo if(ent->hasSkeleton()) { if(meshes[i].second.length() < filter.length() || - !boost::algorithm::lexicographical_compare(meshes[i].second.substr(0, filter.length()), - filter, boost::algorithm::is_iequal())) + std::mismatch(filter.begin(), filter.end(), meshes[i].second.begin(), checklow).first != filter.end()) { sceneMgr->destroyEntity(ent); meshes.erase(meshes.begin()+i); From 1fef0860887fd41a1b775efb9f7f278f9b30fd3f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Jul 2012 15:36:12 +0200 Subject: [PATCH 81/92] Revert "Merge remote-tracking branch 'mark76/multiple_esm_esp' into nif-cleanup" This reverts commit 546b640022e3ec111b5c795c3fc1d067c3b1a684, reversing changes made to fcaa8aae06d791c37daab0897f4fd19f6b2129b5. --- apps/openmw/engine.cpp | 30 +++++-------------- apps/openmw/engine.hpp | 8 ++--- apps/openmw/main.cpp | 28 ++++++++--------- apps/openmw/mwrender/terrain.cpp | 24 ++++----------- apps/openmw/mwrender/terrain.hpp | 5 +--- apps/openmw/mwworld/worldimp.cpp | 32 +++++--------------- apps/openmw/mwworld/worldimp.hpp | 3 +- components/esm/esm_reader.hpp | 8 ----- components/esm/loadland.cpp | 1 - components/esm/loadland.hpp | 1 - components/esm_store/reclists.hpp | 50 +++++++------------------------ components/esm_store/store.cpp | 7 ----- 12 files changed, 48 insertions(+), 149 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f41d453b5..ab5b63071 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -207,32 +207,18 @@ void OMW::Engine::setCell (const std::string& cellName) // Set master file (esm) // - If the given name does not have an extension, ".esm" is added automatically +// - Currently OpenMW only supports one master at the same time. void OMW::Engine::addMaster (const std::string& master) { - mMaster.push_back(master); - std::string &str = mMaster.back(); + assert (mMaster.empty()); + mMaster = master; - // Append .esm if not already there - std::string::size_type sep = str.find_last_of ("."); + // Append .esm if not already there + std::string::size_type sep = mMaster.find_last_of ("."); if (sep == std::string::npos) { - str += ".esm"; - } -} - -// Add plugin file (esp) - -void OMW::Engine::addPlugin (const std::string& plugin) -{ - mPlugins.push_back(plugin); - std::string &str = mPlugins.back(); - - // Append .esp if not already there - std::string::size_type sep = str.find_last_of ("."); - if (sep == std::string::npos) - { - str += ".esp"; + mMaster += ".esm"; } } @@ -333,8 +319,8 @@ void OMW::Engine::go() MWGui::CursorReplace replacer; // Create the world - mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, - mResDir, mNewGame, mEncoding, mFallbackMap) ); + mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, + mResDir, mNewGame, mEncoding, mFallbackMap)); // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 0582800c9..031cae551 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -64,8 +64,7 @@ namespace OMW boost::filesystem::path mResDir; OEngine::Render::OgreRenderer *mOgre; std::string mCellName; - std::vector mMaster; - std::vector mPlugins; + std::string mMaster; int mFpsLevel; bool mDebug; bool mVerboseScripts; @@ -121,12 +120,9 @@ namespace OMW /// Set master file (esm) /// - If the given name does not have an extension, ".esm" is added automatically + /// - Currently OpenMW only supports one master at the same time. void addMaster(const std::string& master); - /// Same as "addMaster", but for plugin files (esp) - /// - If the given name does not have an extension, ".esp" is added automatically - void addPlugin(const std::string& plugin); - /// Enable fps counter void showFPS(int level); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 9fe333a28..993ec6623 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -224,23 +224,19 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat master.push_back("Morrowind"); } - StringsVector plugin = variables["plugin"].as(); - int cnt = master.size() + plugin.size(); - if (cnt > 255) - { - std::cerr - << "Error: Trying to load more than 255 master and plugin files! This will break all combaibility and is not supported!" - << std::endl; - return false; - } - for (std::vector::size_type i = 0; i < master.size(); i++) + if (master.size() > 1) { - engine.addMaster(master[i]); - } - for (std::vector::size_type i = 0; i < plugin.size(); i++) - { - engine.addPlugin(plugin[i]); - } + std::cout + << "Ignoring all but the first master file (multiple master files not yet supported)." + << std::endl; + } + engine.addMaster(master[0]); + + StringsVector plugin = variables["plugin"].as(); + if (!plugin.empty()) + { + std::cout << "Ignoring plugin files (plugins not yet supported)." << std::endl; + } // startup-settings engine.setCell(variables["start"].as()); diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 909836659..691e7c4af 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -141,7 +141,7 @@ namespace MWRender std::map indexes; initTerrainTextures(&terrainData, cellX, cellY, x * numTextures, y * numTextures, - numTextures, indexes, land->plugin); + numTextures, indexes); if (mTerrainGroup.getTerrain(terrainX, terrainY) == NULL) { @@ -200,14 +200,8 @@ namespace MWRender void TerrainManager::initTerrainTextures(Terrain::ImportData* terrainData, int cellX, int cellY, int fromX, int fromY, int size, - std::map& indexes, - size_t plugin) + std::map& indexes) { - // FIXME: In a multiple esm configuration, we have multiple palettes. Since this code - // crosses cell boundaries, we no longer have a unique terrain palette. Instead, we need - // to adopt the following code for a dynamic palette. And this is evil - the current design - // does not work well for this task... - assert(terrainData != NULL && "Must have valid terrain data"); assert(fromX >= 0 && fromY >= 0 && "Can't get a terrain texture on terrain outside the current cell"); @@ -220,16 +214,12 @@ namespace MWRender // //If we don't sort the ltex indexes, the splatting order may differ between //cells which may lead to inconsistent results when shading between cells - int num = MWBase::Environment::get().getWorld()->getStore().landTexts.getSizePlugin(plugin); std::set ltexIndexes; for ( int y = fromY - 1; y < fromY + size + 1; y++ ) { for ( int x = fromX - 1; x < fromX + size + 1; x++ ) { - int idx = getLtexIndexAt(cellX, cellY, x, y); - if (idx > num) - idx = 0; - ltexIndexes.insert(idx); + ltexIndexes.insert(getLtexIndexAt(cellX, cellY, x, y)); } } @@ -241,7 +231,7 @@ namespace MWRender iter != ltexIndexes.end(); ++iter ) { - uint16_t ltexIndex = *iter; + const uint16_t ltexIndex = *iter; //this is the base texture, so we can ignore this at present if ( ltexIndex == baseTexture ) { @@ -254,10 +244,8 @@ namespace MWRender { //NB: All vtex ids are +1 compared to the ltex ids - /* - assert( (int)mEnvironment.mWorld->getStore().landTexts.getSizePlugin(plugin) >= (int)ltexIndex - 1 && + assert( (int)MWBase::Environment::get().getWorld()->getStore().landTexts.getSize() >= (int)ltexIndex - 1 && "LAND.VTEX must be within the bounds of the LTEX array"); - */ std::string texture; if ( ltexIndex == 0 ) @@ -266,7 +254,7 @@ namespace MWRender } else { - texture = MWBase::Environment::get().getWorld()->getStore().landTexts.search(ltexIndex-1, plugin)->texture; + texture = MWBase::Environment::get().getWorld()->getStore().landTexts.search(ltexIndex-1)->texture; //TODO this is needed due to MWs messed up texture handling texture = texture.substr(0, texture.rfind(".")) + ".dds"; } diff --git a/apps/openmw/mwrender/terrain.hpp b/apps/openmw/mwrender/terrain.hpp index 94072fc40..c83d96cf4 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -71,14 +71,11 @@ namespace MWRender{ * @param size the size (number of splats) to get * @param indexes a mapping of ltex index to the terrain texture layer that * can be used by initTerrainBlendMaps - * @param plugin the index of the plugin providing the texture list for this - * cell data; required because MW uses texture data on a per-plugin base */ void initTerrainTextures(Ogre::Terrain::ImportData* terrainData, int cellX, int cellY, int fromX, int fromY, int size, - std::map& indexes, - size_t plugin = 0); + std::map& indexes); /** * Creates the blend (splatting maps) for the given terrain from the ltex data. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ae517071e..a68f08e34 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -167,8 +167,7 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::vector& master, - const std::vector& plugins, const boost::filesystem::path& resDir, bool newGame, + const std::string& master, const boost::filesystem::path& resDir, bool newGame, const std::string& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mNextDynamicRecord (0), mCells (mStore, mEsm), @@ -181,32 +180,15 @@ namespace MWWorld mWeatherManager = new MWWorld::WeatherManager(mRendering); - int idx = 0; - for (std::vector::size_type i = 0; i < master.size(); i++, idx++) - { - boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i])); - - std::cout << "Loading ESM " << masterPath.string() << "\n"; + boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master)); - // This parses the ESM file and loads a sample cell - mEsm.setEncoding(encoding); - mEsm.open (masterPath.string()); - mEsm.setIndex(idx); - mStore.load (mEsm); - } + std::cout << "Loading ESM " << masterPath.string() << "\n"; - for (std::vector::size_type i = 0; i < plugins.size(); i++, idx++) - { - boost::filesystem::path pluginPath (fileCollections.getCollection (".esp").getPath (plugins[i])); - - std::cout << "Loading ESP " << pluginPath.string() << "\n"; + // This parses the ESM file and loads a sample cell + mEsm.setEncoding(encoding); + mEsm.open (masterPath.string()); + mStore.load (mEsm); - // This parses the ESP file and loads a sample cell - mEsm.setEncoding(encoding); - mEsm.open (pluginPath.string()); - mEsm.setIndex(idx); - mStore.load (mEsm); - } MWRender::Player* play = &(mRendering->getPlayer()); mPlayer = new MWWorld::Player (play, mStore.npcs.find ("player"), *this); mPhysics->addActor (mPlayer->getPlayer().getRefData().getHandle(), "", Ogre::Vector3 (0, 0, 0)); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index af6232aaf..43b178fe3 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -93,8 +93,7 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::vector& master, - const std::vector& plugins, const boost::filesystem::path& resDir, bool newGame, + const std::string& master, const boost::filesystem::path& resDir, bool newGame, const std::string& encoding, std::map fallbackMap); virtual ~World(); diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index 0326fdc04..13f1f4a01 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -189,14 +189,6 @@ public: void openRaw(const std::string &file); - // This is a quick hack for multiple esm/esp files. Each plugin introduces its own - // terrain palette, but ESMReader does not pass a reference to the correct plugin - // to the individual load() methods. This hack allows to pass this reference - // indirectly to the load() method. - int idx; - void setIndex(const int index) {idx = index;} - const int getIndex() {return idx;} - /************************************************************************* * * Medium-level reading shortcuts diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 822952c91..96afdf831 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -23,7 +23,6 @@ Land::~Land() void Land::load(ESMReader &esm) { mEsm = &esm; - plugin = mEsm->getIndex(); // Get the grid location esm.getSubNameIs("INTV"); diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index d03012d38..ebc314a28 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -17,7 +17,6 @@ struct Land int flags; // Only first four bits seem to be used, don't know what // they mean. int X, Y; // Map coordinates. - int plugin; // Plugin index, used to reference the correct material palette. // File context. This allows the ESM reader to be 'reset' to this // location later when we are ready to load the full data set. diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index 668c4e58e..ffecfc8de 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -26,7 +26,6 @@ namespace ESMS virtual void load(ESMReader &esm, const std::string &id) = 0; virtual int getSize() = 0; - virtual void remove(const std::string &id) {}; virtual void listIdentifier (std::vector& identifier) const = 0; static std::string toLower (const std::string& name) @@ -58,14 +57,6 @@ namespace ESMS list[id2].load(esm); } - // Delete the given object ID - void remove(const std::string &id) - { - std::string id2 = toLower (id); - - list.erase(id2); - } - // Find the given object ID, or return NULL if not found. const X* search(const std::string &id) const { @@ -277,57 +268,38 @@ namespace ESMS { virtual ~LTexList() {} - // For multiple ESM/ESP files we need one list per file. - typedef std::vector LandTextureList; - std::vector ltex; + // TODO: For multiple ESM/ESP files we need one list per file. + std::vector ltex; LTexList() { - ltex.push_back(LandTextureList()); - LandTextureList <exl = ltex[0]; // More than enough to hold Morrowind.esm. - ltexl.reserve(128); + ltex.reserve(128); } - const LandTexture* search(size_t index, size_t plugin) const + const LandTexture* search(size_t index) const { - assert(plugin < ltex.size()); - const LandTextureList <exl = ltex[plugin]; - - assert(index < ltexl.size()); - return <exl.at(index); + assert(index < ltex.size()); + return <ex.at(index); } int getSize() { return ltex.size(); } int getSize() const { return ltex.size(); } - int getSizePlugin(size_t plugin) { assert(plugin < ltex.size()); return ltex[plugin].size(); } - int getSizePlugin(size_t plugin) const { assert(plugin < ltex.size()); return ltex[plugin].size(); } + virtual void listIdentifier (std::vector& identifier) const {} - virtual void listIdentifier (std::vector& identifier) const {} - - void load(ESMReader &esm, const std::string &id, size_t plugin) + void load(ESMReader &esm, const std::string &id) { LandTexture lt; lt.load(esm); lt.id = id; // Make sure we have room for the structure - if (plugin >= ltex.size()) { - ltex.resize(plugin+1); - } - LandTextureList <exl = ltex[plugin]; - if(lt.index + 1 > (int)ltexl.size()) - ltexl.resize(lt.index+1); + if(lt.index + 1 > (int)ltex.size()) + ltex.resize(lt.index+1); // Store it - ltexl[lt.index] = lt; - } - - void load(ESMReader &esm, const std::string &id) - { - size_t plugin = esm.getIndex(); - load(esm, id, plugin); + ltex[lt.index] = lt; } }; diff --git a/components/esm_store/store.cpp b/components/esm_store/store.cpp index b6972355c..c676601e5 100644 --- a/components/esm_store/store.cpp +++ b/components/esm_store/store.cpp @@ -67,13 +67,6 @@ void ESMStore::load(ESMReader &esm) { // Load it std::string id = esm.getHNOString("NAME"); - // ... unless it got deleted! - if (esm.isNextSub("DELE")) { - esm.skipRecord(); - all.erase(id); - it->second->remove(id); - continue; - } it->second->load(esm, id); if (n.val==ESM::REC_DIAL) From ab35bfa32cb4642750538c77bf8996419d9bdc7a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Jul 2012 18:19:34 +0200 Subject: [PATCH 82/92] fixed a sky issue --- apps/openmw/mwrender/sky.cpp | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d78a3caff..d928995f4 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -287,21 +287,12 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) void SkyManager::create() { + assert(!mCreated); + sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor", sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance().setSharedParameter ("cloudOpacity", - sh::makeProperty(new sh::FloatValue(1))); - sh::Factory::getInstance().setSharedParameter ("cloudColour", - sh::makeProperty(new sh::Vector3(1,1,1))); - sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", - sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance().setSharedParameter ("nightFade", - sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", ""); - sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", ""); - - // Create overlay used for thunderstorm + // Create light used for thunderstorm mLightning = mSceneMgr->createLight(); mLightning->setType (Ogre::Light::LT_DIRECTIONAL); mLightning->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); @@ -332,19 +323,15 @@ void SkyManager::create() night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setCastShadows(false); - for (unsigned int i=0; igetNumSubEntities(); ++i) - { - std::string matName = "openmw_stars_" + boost::lexical_cast(i); - sh::MaterialInstance* m = sh::Factory::getInstance ().createMaterialInstance (matName, "openmw_stars"); + std::string matName = "openmw_stars_" + boost::lexical_cast(i); + sh::MaterialInstance* m = sh::Factory::getInstance ().createMaterialInstance (matName, "openmw_stars"); - std::string textureName = sh::retrieveValue( - sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity (i)->getMaterialName ())->getProperty("diffuseMap"), NULL).get(); + std::string textureName = sh::retrieveValue( + sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity (0)->getMaterialName ())->getProperty("diffuseMap"), NULL).get(); - m->setProperty ("texture", sh::makeProperty(new sh::StringValue(textureName))); + m->setProperty ("texture", sh::makeProperty(new sh::StringValue(textureName))); - night1_ent->getSubEntity(i)->setMaterialName (matName); - - } + night1_ent->getSubEntity(0)->setMaterialName (matName); } @@ -370,7 +357,6 @@ void SkyManager::create() Entity* clouds_ent = entities.mEntities[i]; clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); - clouds_node->attachObject(clouds_ent); clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds"); clouds_ent->setCastShadows(false); From f67983bbee071b886f27682c322fb66628db2b44 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Jul 2012 13:37:05 -0700 Subject: [PATCH 83/92] Don't assume one sub-entity for the night sky entities --- apps/openmw/mwrender/sky.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d928995f4..3dd038659 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -316,22 +316,25 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); - for(size_t i = 0;i < entities.mEntities.size();i++) + for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) { Entity* night1_ent = entities.mEntities[i]; night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setCastShadows(false); - std::string matName = "openmw_stars_" + boost::lexical_cast(i); - sh::MaterialInstance* m = sh::Factory::getInstance ().createMaterialInstance (matName, "openmw_stars"); + for (unsigned int j=0; jgetNumSubEntities(); ++j) + { + std::string matName = "openmw_stars_" + boost::lexical_cast(matidx++); + sh::MaterialInstance* m = sh::Factory::getInstance().createMaterialInstance(matName, "openmw_stars"); - std::string textureName = sh::retrieveValue( - sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity (0)->getMaterialName ())->getProperty("diffuseMap"), NULL).get(); + std::string textureName = sh::retrieveValue( + sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity(j)->getMaterialName())->getProperty("diffuseMap"), NULL).get(); - m->setProperty ("texture", sh::makeProperty(new sh::StringValue(textureName))); + m->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); - night1_ent->getSubEntity(0)->setMaterialName (matName); + night1_ent->getSubEntity(j)->setMaterialName(matName); + } } From 36be1536d90a5d927854e0c66eca5efbe17c4767 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Jul 2012 17:20:47 -0700 Subject: [PATCH 84/92] Return text keys from NIFs when creating entities --- apps/openmw/mwrender/creatureanimation.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 6 ++-- components/nifogre/ogre_nif_loader.cpp | 36 ++++++++++++++++------ components/nifogre/ogre_nif_loader.hpp | 8 +++-- 6 files changed, 37 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 9d2a58a1e..4086f4f7a 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,7 +26,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O { std::string mesh = "meshes\\" + ref->base->model; - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, mesh); + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, NULL, mesh); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 415de5859..47135b35d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -89,7 +89,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, smodel); + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, NULL, smodel); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *base = mEntityList.mEntities[i]; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 3af99b469..ecd1328c4 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -93,7 +93,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) assert(insert); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, mesh); + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, NULL, mesh); for(size_t i = 0;i < entities.mEntities.size();i++) { const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a87f56ad8..9e551ba2a 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -327,7 +327,7 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, NULL, "meshes\\sky_night_01.nif"); for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) { Entity* night1_ent = entities.mEntities[i]; @@ -352,7 +352,7 @@ void SkyManager::create() // Atmosphere (day) mAtmosphereDay = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); + entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, NULL, "meshes\\sky_atmosphere.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* atmosphere_ent = entities.mEntities[i]; @@ -366,7 +366,7 @@ void SkyManager::create() // Clouds SceneNode* clouds_node = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); + entities = NifOgre::NIFLoader::createEntities(clouds_node, NULL, "meshes\\sky_clouds_01.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* clouds_ent = entities.mEntities[i]; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 3338b8cdd..9df8dd916 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -342,8 +342,23 @@ void loadResource(Ogre::Resource *resource) anim->optimise(); } -bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node) +bool createSkeleton(const std::string &name, const std::string &group, TextKeyMap *textkeys, const Nif::Node *node) { + if(textkeys) + { + Nif::ExtraPtr e = node->extra; + while(!e.empty()) + { + if(e->recType == Nif::RC_NiTextKeyExtraData) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + for(size_t i = 0;i < tk->list.size();i++) + (*textkeys)[tk->list[i].time] = tk->list[i].text; + } + e = e->extra; + } + } + if(node->boneTrafo != NULL) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); @@ -355,18 +370,19 @@ bool createSkeleton(const std::string &name, const std::string &group, Nif::Node skel = skelMgr.create(name, group, true, loader); } - return true; + if(!textkeys || textkeys->size() > 0) + return true; } - Nif::NiNode *ninode = dynamic_cast(node); + const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { - Nif::NodeList &children = ninode->children; + const Nif::NodeList &children = ninode->children; for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) { - if(createSkeleton(name, group, children[i].getPtr())) + if(createSkeleton(name, group, textkeys, children[i].getPtr())) return true; } } @@ -965,7 +981,7 @@ public: NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; -MeshPairList NIFLoader::load(std::string name, std::string skelName, const std::string &group) +MeshPairList NIFLoader::load(std::string name, std::string skelName, TextKeyMap *textkeys, const std::string &group) { MeshPairList meshes; @@ -992,7 +1008,7 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: } NIFSkeletonLoader skelldr; - bool hasSkel = skelldr.createSkeleton(skelName, group, node); + bool hasSkel = skelldr.createSkeleton(skelName, group, textkeys, node); NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); meshldr.createMeshes(node, meshes); @@ -1000,11 +1016,11 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: return meshes; } -EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, const std::string &name, const std::string &group) +EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textkeys, const std::string &name, const std::string &group) { EntityList entitylist; - MeshPairList meshes = load(name, name, group); + MeshPairList meshes = load(name, name, textkeys, group); if(meshes.size() == 0) return entitylist; @@ -1053,7 +1069,7 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo { EntityList entitylist; - MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), group); + MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), NULL, group); if(meshes.size() == 0) return entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index a9195f2fb..b6610d8a7 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -58,7 +58,8 @@ namespace Nif namespace NifOgre { -// FIXME: This should not be in NifOgre, it works agnostic of what model format is used +// FIXME: These should not be in NifOgre, it works agnostic of what model format is used +typedef std::map TextKeyMap; struct EntityList { std::vector mEntities; Ogre::Entity *mSkelBase; @@ -67,11 +68,11 @@ struct EntityList { { } }; + /** This holds a list of meshes along with the names of their parent nodes */ typedef std::vector< std::pair > MeshPairList; - /** Manual resource loader for NIF meshes. This is the main class responsible for translating the internal NIF mesh structure into something Ogre can use. @@ -86,7 +87,7 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { - static MeshPairList load(std::string name, std::string skelName, const std::string &group); + static MeshPairList load(std::string name, std::string skelName, TextKeyMap *textkeys, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, @@ -95,6 +96,7 @@ public: const std::string &group="General"); static EntityList createEntities(Ogre::SceneNode *parent, + TextKeyMap *textkeys, const std::string &name, const std::string &group="General"); }; From f953d7f8c0c0145def6fc81f265d931adfca15bf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Jul 2012 17:27:35 -0700 Subject: [PATCH 85/92] Store text keys from base NIF animations --- apps/openmw/mwrender/animation.hpp | 1 + apps/openmw/mwrender/creatureanimation.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ae1477666..dd1fdc95e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -30,6 +30,7 @@ protected: bool mSkipFrame; NifOgre::EntityList mEntityList; + NifOgre::TextKeyMap mTextKeys; public: Animation(OEngine::Render::OgreRenderer& _rend); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 4086f4f7a..7fb153bd1 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,7 +26,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::O { std::string mesh = "meshes\\" + ref->base->model; - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, NULL, mesh); + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, mesh); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 47135b35d..4f98aebc4 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -89,7 +89,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, NULL, smodel); + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, smodel); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *base = mEntityList.mEntities[i]; From 9a7a629d0f82bd224a518901757d3282c23015ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Jul 2012 13:51:48 -0700 Subject: [PATCH 86/92] Add support for playing animation groups --- apps/openmw/mwrender/animation.cpp | 137 +++++++++++++++++++++++++---- apps/openmw/mwrender/animation.hpp | 8 ++ 2 files changed, 129 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 653a506e8..27ab3995a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -7,6 +7,7 @@ #include #include + namespace MWRender { std::map Animation::sUniqueIDs; @@ -28,16 +29,117 @@ Animation::~Animation() mEntityList.mEntities.clear(); } -void Animation::playGroup(std::string groupname, int mode, int loops) -{ - if(groupname == "all") + +struct checklow { + bool operator()(const char &a, const char &b) const { - mAnimate = loops; - mTime = 0.0f; + return ::tolower(a) == ::tolower(b); } +}; + +bool Animation::findGroupTimes(const std::string &groupname, float *starttime, float *stoptime, float *loopstarttime, float *loopstoptime) +{ + const std::string &start = groupname+": start"; + const std::string &startloop = groupname+": loop start"; + const std::string &stop = groupname+": stop"; + const std::string &stoploop = groupname+": loop stop"; + + *starttime = -1.0f; + *stoptime = -1.0f; + *loopstarttime = -1.0f; + *loopstoptime = -1.0f; + + NifOgre::TextKeyMap::const_iterator iter; + for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) + { + if(*starttime >= 0.0f && *stoptime >= 0.0f && *loopstarttime >= 0.0f && *loopstoptime >= 0.0f) + return true; + + std::string::const_iterator strpos = iter->second.begin(); + std::string::const_iterator strend = iter->second.end(); + + while(strpos != strend) + { + size_t strlen = strend-strpos; + std::string::const_iterator striter; + + if(start.size() <= strlen && + ((striter=std::mismatch(strpos, strend, start.begin(), checklow()).first) == strend || + *striter == '\r' || *striter == '\n')) + { + *starttime = iter->first; + *loopstarttime = iter->first; + } + else if(startloop.size() <= strlen && + ((striter=std::mismatch(strpos, strend, startloop.begin(), checklow()).first) == strend || + *striter == '\r' || *striter == '\n')) + { + *loopstarttime = iter->first; + } + else if(stoploop.size() <= strlen && + ((striter=std::mismatch(strpos, strend, stoploop.begin(), checklow()).first) == strend || + *striter == '\r' || *striter == '\n')) + { + *loopstoptime = iter->first; + } + else if(stop.size() <= strlen && + ((striter=std::mismatch(strpos, strend, stop.begin(), checklow()).first) == strend || + *striter == '\r' || *striter == '\n')) + { + *stoptime = iter->first; + if(*loopstoptime < 0.0f) + *loopstoptime = iter->first; + break; + } + + strpos = std::find(strpos+1, strend, '\n'); + while(strpos != strend && *strpos == '\n') + strpos++; + } + } + + return (*starttime >= 0.0f && *stoptime >= 0.0f && *loopstarttime >= 0.0f && *loopstoptime >= 0.0f); } +void Animation::playGroup(std::string groupname, int mode, int loops) +{ + float start, stop, loopstart, loopstop; + + if(groupname == "all") + { + mLoopStartTime = mStartTime = 0.0f; + mLoopStopTime = mStopTime = 0.0f; + + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + mLoopStopTime = mStopTime = state->getLength(); + break; + } + } + + mAnimate = loops; + mTime = mStartTime; + } + else if(findGroupTimes(groupname, &start, &stop, &loopstart, &loopstop)) + { + mStartTime = start; + mStopTime = stop; + mLoopStartTime = loopstart; + mLoopStopTime = loopstop; + + mAnimate = loops; + mTime = mStartTime; + } + else + throw std::runtime_error("Failed to find animation group "+groupname); +} + void Animation::skipAnim() { mSkipFrame = true; @@ -45,9 +147,22 @@ void Animation::skipAnim() void Animation::runAnimation(float timepassed) { - if(mAnimate != 0 && !mSkipFrame) + if(mAnimate > 0 && !mSkipFrame) { mTime += timepassed; + if(mTime >= mLoopStopTime) + { + if(mAnimate > 1) + { + mAnimate--; + mTime = mTime - mLoopStopTime + mLoopStartTime; + } + else if(mTime >= mStopTime) + { + mAnimate--; + mTime = mStopTime; + } + } if(mEntityList.mSkelBase) { @@ -57,16 +172,6 @@ void Animation::runAnimation(float timepassed) { Ogre::AnimationState *state = as.getNext(); state->setTimePosition(mTime); - if(mTime >= state->getLength()) - { - if(mAnimate != -1) - mAnimate--; - //std::cout << "Stopping the animation\n"; - if(mAnimate == 0) - mTime = state->getLength(); - else - mTime = mTime - state->getLength(); - } } } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index dd1fdc95e..fb9330114 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -26,12 +26,20 @@ protected: static std::map sUniqueIDs; float mTime; + float mStartTime; + float mStopTime; + float mLoopStartTime; + float mLoopStopTime; + int mAnimate; bool mSkipFrame; NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; + bool findGroupTimes(const std::string &groupname, float *starttime, float *stoptime, + float *loopstarttime, float *loopstoptime); + public: Animation(OEngine::Render::OgreRenderer& _rend); virtual ~Animation(); From 20121f3b0a1f5732cb4d76e66cc6e1039d0f048f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Jul 2012 13:56:28 -0700 Subject: [PATCH 87/92] Remove some unused stuff --- apps/openmw/mwrender/animation.cpp | 1 - apps/openmw/mwrender/animation.hpp | 6 ------ 2 files changed, 7 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 27ab3995a..6a04f62b5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -10,7 +10,6 @@ namespace MWRender { -std::map Animation::sUniqueIDs; Animation::Animation(OEngine::Render::OgreRenderer& _rend) : mInsert(NULL) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index fb9330114..cb0e92367 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -14,16 +14,10 @@ namespace MWRender { -struct PosAndRot { - Ogre::Quaternion vecRot; - Ogre::Vector3 vecPos; -}; - class Animation { protected: Ogre::SceneNode* mInsert; OEngine::Render::OgreRenderer &mRend; - static std::map sUniqueIDs; float mTime; float mStartTime; From fd1e3f6ec55f1aee15fd0ab5514fdeb362370623 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Jul 2012 14:14:32 -0700 Subject: [PATCH 88/92] Add support for playgroup mode 2 --- apps/openmw/mwrender/animation.cpp | 33 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6a04f62b5..f6beeb52f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -107,8 +107,8 @@ void Animation::playGroup(std::string groupname, int mode, int loops) if(groupname == "all") { - mLoopStartTime = mStartTime = 0.0f; - mLoopStopTime = mStopTime = 0.0f; + start = loopstart = 0.0f; + loopstop = stop = 0.0f; if(mEntityList.mSkelBase) { @@ -117,26 +117,25 @@ void Animation::playGroup(std::string groupname, int mode, int loops) while(as.hasMoreElements()) { Ogre::AnimationState *state = as.getNext(); - mLoopStopTime = mStopTime = state->getLength(); + loopstop = stop = state->getLength(); break; } } - - mAnimate = loops; - mTime = mStartTime; } - else if(findGroupTimes(groupname, &start, &stop, &loopstart, &loopstop)) - { - mStartTime = start; - mStopTime = stop; - mLoopStartTime = loopstart; - mLoopStopTime = loopstop; - - mAnimate = loops; - mTime = mStartTime; - } - else + else if(!findGroupTimes(groupname, &start, &stop, &loopstart, &loopstop)) throw std::runtime_error("Failed to find animation group "+groupname); + + // FIXME: mode = 0 not yet supported + if(mode == 0) + mode = 1; + + mStartTime = start; + mStopTime = stop; + mLoopStartTime = loopstart; + mLoopStopTime = loopstop; + + mAnimate = loops; + mTime = ((mode==1) ? mStartTime : mLoopStartTime); } void Animation::skipAnim() From 13ab2baef0967333d8aad0eee6d964edb2a30734 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Jul 2012 14:42:01 -0700 Subject: [PATCH 89/92] Use a struct to hold the current animation times and remaining loop count --- apps/openmw/mwrender/animation.cpp | 61 +++++++++++++----------------- apps/openmw/mwrender/animation.hpp | 23 +++++++---- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f6beeb52f..fe77da52b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -15,7 +15,6 @@ Animation::Animation(OEngine::Render::OgreRenderer& _rend) : mInsert(NULL) , mRend(_rend) , mTime(0.0f) - , mAnimate(0) , mSkipFrame(false) { } @@ -36,22 +35,17 @@ struct checklow { } }; -bool Animation::findGroupTimes(const std::string &groupname, float *starttime, float *stoptime, float *loopstarttime, float *loopstoptime) +bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) { const std::string &start = groupname+": start"; const std::string &startloop = groupname+": loop start"; const std::string &stop = groupname+": stop"; const std::string &stoploop = groupname+": loop stop"; - *starttime = -1.0f; - *stoptime = -1.0f; - *loopstarttime = -1.0f; - *loopstoptime = -1.0f; - NifOgre::TextKeyMap::const_iterator iter; for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) { - if(*starttime >= 0.0f && *stoptime >= 0.0f && *loopstarttime >= 0.0f && *loopstoptime >= 0.0f) + if(times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f) return true; std::string::const_iterator strpos = iter->second.begin(); @@ -66,28 +60,28 @@ bool Animation::findGroupTimes(const std::string &groupname, float *starttime, f ((striter=std::mismatch(strpos, strend, start.begin(), checklow()).first) == strend || *striter == '\r' || *striter == '\n')) { - *starttime = iter->first; - *loopstarttime = iter->first; + times->mStart = iter->first; + times->mLoopStart = iter->first; } else if(startloop.size() <= strlen && ((striter=std::mismatch(strpos, strend, startloop.begin(), checklow()).first) == strend || *striter == '\r' || *striter == '\n')) { - *loopstarttime = iter->first; + times->mLoopStart = iter->first; } else if(stoploop.size() <= strlen && ((striter=std::mismatch(strpos, strend, stoploop.begin(), checklow()).first) == strend || *striter == '\r' || *striter == '\n')) { - *loopstoptime = iter->first; + times->mLoopStop = iter->first; } else if(stop.size() <= strlen && ((striter=std::mismatch(strpos, strend, stop.begin(), checklow()).first) == strend || *striter == '\r' || *striter == '\n')) { - *stoptime = iter->first; - if(*loopstoptime < 0.0f) - *loopstoptime = iter->first; + times->mStop = iter->first; + if(times->mLoopStop < 0.0f) + times->mLoopStop = iter->first; break; } @@ -97,18 +91,19 @@ bool Animation::findGroupTimes(const std::string &groupname, float *starttime, f } } - return (*starttime >= 0.0f && *stoptime >= 0.0f && *loopstarttime >= 0.0f && *loopstoptime >= 0.0f); + return (times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f); } void Animation::playGroup(std::string groupname, int mode, int loops) { - float start, stop, loopstart, loopstop; + GroupTimes times; + times.mLoops = loops; if(groupname == "all") { - start = loopstart = 0.0f; - loopstop = stop = 0.0f; + times.mStart = times.mLoopStart = 0.0f; + times.mLoopStop = times.mStop = 0.0f; if(mEntityList.mSkelBase) { @@ -117,25 +112,21 @@ void Animation::playGroup(std::string groupname, int mode, int loops) while(as.hasMoreElements()) { Ogre::AnimationState *state = as.getNext(); - loopstop = stop = state->getLength(); + times.mLoopStop = times.mStop = state->getLength(); break; } } } - else if(!findGroupTimes(groupname, &start, &stop, &loopstart, &loopstop)) + else if(!findGroupTimes(groupname, ×)) throw std::runtime_error("Failed to find animation group "+groupname); // FIXME: mode = 0 not yet supported if(mode == 0) mode = 1; - mStartTime = start; - mStopTime = stop; - mLoopStartTime = loopstart; - mLoopStopTime = loopstop; + mCurGroup = times; - mAnimate = loops; - mTime = ((mode==1) ? mStartTime : mLoopStartTime); + mTime = ((mode==1) ? mCurGroup.mStart : mCurGroup.mLoopStart); } void Animation::skipAnim() @@ -145,20 +136,20 @@ void Animation::skipAnim() void Animation::runAnimation(float timepassed) { - if(mAnimate > 0 && !mSkipFrame) + if(mCurGroup.mLoops > 0 && !mSkipFrame) { mTime += timepassed; - if(mTime >= mLoopStopTime) + if(mTime >= mCurGroup.mLoopStop) { - if(mAnimate > 1) + if(mCurGroup.mLoops > 1) { - mAnimate--; - mTime = mTime - mLoopStopTime + mLoopStartTime; + mCurGroup.mLoops--; + mTime = mTime - mCurGroup.mLoopStop + mCurGroup.mLoopStart; } - else if(mTime >= mStopTime) + else if(mTime >= mCurGroup.mStop) { - mAnimate--; - mTime = mStopTime; + mCurGroup.mLoops--; + mTime = mCurGroup.mStop; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cb0e92367..c9b34a4e5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -15,24 +15,33 @@ namespace MWRender { class Animation { + struct GroupTimes { + float mStart; + float mStop; + float mLoopStart; + float mLoopStop; + + size_t mLoops; + + GroupTimes() + : mStart(-1.0f), mStop(-1.0f), mLoopStart(-1.0f), mLoopStop(-1.0f), + mLoops(0) + { } + }; + protected: Ogre::SceneNode* mInsert; OEngine::Render::OgreRenderer &mRend; float mTime; - float mStartTime; - float mStopTime; - float mLoopStartTime; - float mLoopStopTime; + GroupTimes mCurGroup; - int mAnimate; bool mSkipFrame; NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; - bool findGroupTimes(const std::string &groupname, float *starttime, float *stoptime, - float *loopstarttime, float *loopstoptime); + bool findGroupTimes(const std::string &groupname, GroupTimes *times); public: Animation(OEngine::Render::OgreRenderer& _rend); From 9f0c1eeb7b8562ac64206eebe81edd701eaba2e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Jul 2012 14:54:12 -0700 Subject: [PATCH 90/92] Support playgroup mode 0 --- apps/openmw/mwrender/animation.cpp | 23 ++++++++++++++--------- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fe77da52b..46f3bdc0d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -120,13 +120,14 @@ void Animation::playGroup(std::string groupname, int mode, int loops) else if(!findGroupTimes(groupname, ×)) throw std::runtime_error("Failed to find animation group "+groupname); - // FIXME: mode = 0 not yet supported - if(mode == 0) - mode = 1; - - mCurGroup = times; - - mTime = ((mode==1) ? mCurGroup.mStart : mCurGroup.mLoopStart); + if(mode == 0 && mCurGroup.mLoops > 0) + mNextGroup = times; + else + { + mCurGroup = times; + mNextGroup = GroupTimes(); + mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart); + } } void Animation::skipAnim() @@ -148,8 +149,12 @@ void Animation::runAnimation(float timepassed) } else if(mTime >= mCurGroup.mStop) { - mCurGroup.mLoops--; - mTime = mCurGroup.mStop; + if(mNextGroup.mLoops > 0) + mTime = mTime - mCurGroup.mStop + mNextGroup.mStart; + else + mTime = mCurGroup.mStop; + mCurGroup = mNextGroup; + mNextGroup = GroupTimes(); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index c9b34a4e5..3611d35c0 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -35,6 +35,7 @@ protected: float mTime; GroupTimes mCurGroup; + GroupTimes mNextGroup; bool mSkipFrame; From 4f46c8a8db6cbe532492be39d6369e5360662cea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Jul 2012 14:59:25 -0700 Subject: [PATCH 91/92] Use a functor for the mismatch compare function --- components/nifogre/ogre_nif_loader.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 9df8dd916..803300282 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1057,10 +1057,12 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke return entitylist; } -static bool checklow(const char &a, const char &b) -{ - return ::tolower(a) == ::tolower(b); -} +struct checklow { + bool operator()(const char &a, const char &b) const + { + return ::tolower(a) == ::tolower(b); + } +}; EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, @@ -1081,7 +1083,7 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo if(ent->hasSkeleton()) { if(meshes[i].second.length() < filter.length() || - std::mismatch(filter.begin(), filter.end(), meshes[i].second.begin(), checklow).first != filter.end()) + std::mismatch(filter.begin(), filter.end(), meshes[i].second.begin(), checklow()).first != filter.end()) { sceneMgr->destroyEntity(ent); meshes.erase(meshes.begin()+i); From 0f40e6fc65b4a983ef6a159cf6076d07a463324b Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 25 Jul 2012 00:47:08 +0200 Subject: [PATCH 92/92] find boost without components so we can use Boost_VERSION --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f124f1383..ea0c41fe2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,6 +186,9 @@ if (UNIX AND NOT APPLE) find_package (Threads) endif() +# find boost without components so we can use Boost_VERSION +find_package(Boost REQUIRED) + set(BOOST_COMPONENTS system filesystem program_options thread) if (Boost_VERSION LESS 104900)