diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a3dfbddfa..3ede82bee 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -240,18 +240,9 @@ void OMW::Engine::setNewGame(bool newGame) mNewGame = newGame; } -// Initialise and enter main loop. - -void OMW::Engine::go() +std::string OMW::Engine::loadSettings (Settings::Manager & settings) { - assert (!mCellName.empty()); - assert (!mMaster.empty()); - assert (!mOgre); - - mOgre = new OEngine::Render::OgreRenderer; - // Create the settings manager and load default settings file - Settings::Manager settings; const std::string localdefault = mCfgMgr.getLocalPath().string() + "/settings-default.cfg"; const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/settings-default.cfg"; @@ -272,10 +263,6 @@ void OMW::Engine::go() else if (boost::filesystem::exists(globaldefault)) settings.loadUser(globaldefault); - // Get the path for the keybinder xml file - std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string(); - bool keybinderUserExists = boost::filesystem::exists(keybinderUser); - mFpsLevel = settings.getInt("fps", "HUD"); // load nif overrides @@ -285,6 +272,13 @@ void OMW::Engine::go() else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg")) nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"); + return settingspath; +} + +void OMW::Engine::prepareEngine (Settings::Manager & settings) +{ + Nif::NIFFile::CacheLock cachelock; + std::string renderSystem = settings.getString("render system", "Video"); if (renderSystem == "") { @@ -294,6 +288,9 @@ void OMW::Engine::go() renderSystem = "OpenGL Rendering Subsystem"; #endif } + + mOgre = new OEngine::Render::OgreRenderer; + mOgre->configure( mCfgMgr.getLogPath().string(), renderSystem, @@ -328,16 +325,13 @@ void OMW::Engine::go() // cursor replacer (converts the cursor from the bsa so they can be used by mygui) MWGui::CursorReplace replacer; - // Create encoder - ToUTF8::Utf8Encoder encoder (mEncoding); - // Create the world mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, - mResDir, mCfgMgr.getCachePath(), mNewGame, &encoder, mFallbackMap, + mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap, mActivationDistanceOverride)); //Load translation data - mTranslationDataStorage.setEncoder(&encoder); + mTranslationDataStorage.setEncoder(mEncoder); mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster); // Create window manager - this manages all the MW-specific GUI windows @@ -365,6 +359,11 @@ void OMW::Engine::go() mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); // Sets up the input system + + // Get the path for the keybinder xml file + std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string(); + bool keybinderUserExists = boost::filesystem::exists(keybinderUser); + mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, MWBase::Environment::get().getWorld()->getPlayer(), *MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderUser, keybinderUserExists)); @@ -390,9 +389,6 @@ void OMW::Engine::go() mOgre->getRoot()->addFrameListener (this); - // Play some good 'ol tunes - MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - // scripts if (mCompileAll) { @@ -405,10 +401,35 @@ void OMW::Engine::go() << "%)" << std::endl; } +} + +// Initialise and enter main loop. + +void OMW::Engine::go() +{ + assert (!mCellName.empty()); + assert (!mMaster.empty()); + assert (!mOgre); + + Settings::Manager settings; + std::string settingspath; + + settingspath = loadSettings (settings); + + // Create encoder + ToUTF8::Utf8Encoder encoder (mEncoding); + mEncoder = &encoder; + + prepareEngine (settings); + + // Play some good 'ol tunes + MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript); + std::cout << "\nPress Q/ESC or close window to exit.\n"; + // Start the main rendering loop mOgre->start(); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 601cc7765..e320c6991 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "mwbase/environment.hpp" @@ -61,6 +62,7 @@ namespace OMW { MWBase::Environment mEnvironment; ToUTF8::FromType mEncoding; + ToUTF8::Utf8Encoder* mEncoder; Files::PathContainer mDataDirs; boost::filesystem::path mResDir; OEngine::Render::OgreRenderer *mOgre; @@ -103,6 +105,12 @@ namespace OMW virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); + /// Load settings from various files, returns the path to the user settings file + std::string loadSettings (Settings::Manager & settings); + + /// Prepare engine for game play + void prepareEngine (Settings::Manager & settings); + public: Engine(Files::ConfigurationManager& configurationManager); virtual ~Engine(); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 1be8d66b3..7ad8f1b47 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -12,6 +12,9 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/actioneat.hpp" +#include "../mwworld/player.hpp" + +#include "../mwmechanics/npcstats.hpp" #include "../mwgui/tooltips.hpp" @@ -154,6 +157,10 @@ namespace MWClass text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer(); + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player); + int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); + MWGui::Widgets::SpellEffectList list; for (int i=0; i<4; ++i) { @@ -163,6 +170,12 @@ namespace MWClass params.mEffectID = ref->mBase->mData.mEffectID[i]; params.mAttribute = ref->mBase->mData.mAttributes[i]; params.mSkill = ref->mBase->mData.mSkills[i]; + + params.mKnown = ( (i == 0 && alchemySkill >= 15) + || (i == 1 && alchemySkill >= 30) + || (i == 2 && alchemySkill >= 45) + || (i == 3 && alchemySkill >= 60)); + list.push_back(params); } info.effects = list; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 82e112826..f932c1f03 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -390,8 +390,13 @@ void MWSpellEffect::setSpellEffect(const SpellEffectParams& params) void MWSpellEffect::updateWidgets() { - if (!mWindowManager) + if (!mEffectParams.mKnown) + { + mTextWidget->setCaption ("?"); + mRequestedWidth = mTextWidget->getTextSize().width + 24; + mImageWidget->setImageTexture (""); return; + } const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -400,7 +405,6 @@ void MWSpellEffect::updateWidgets() store.get().search(mEffectParams.mEffectID); assert(magicEffect); - assert(mWindowManager); std::string pt = mWindowManager->getGameSettingString("spoint", ""); std::string pts = mWindowManager->getGameSettingString("spoints", ""); diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 4ac5383f7..7cbb5e53a 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -37,12 +37,15 @@ namespace MWGui , mEffectID(-1) , mNoTarget(false) , mIsConstant(false) + , mKnown(true) { } bool mNoTarget; // potion effects for example have no target (target is always the player) bool mIsConstant; // constant effect means that duration will not be displayed + bool mKnown; // is this effect known to the player? (If not, will display as a question mark instead) + // value of -1 here means the effect is unknown to the player short mEffectID; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6b9abf508..b917a8916 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -172,6 +172,8 @@ namespace MWWorld void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) { + Nif::NIFFile::CacheLock cachelock; + mRendering.preCellChange(mCurrentCell); // remove active diff --git a/components/files/ogreplugin.cpp b/components/files/ogreplugin.cpp index ca90fd30e..c319f7758 100644 --- a/components/files/ogreplugin.cpp +++ b/components/files/ogreplugin.cpp @@ -6,11 +6,6 @@ namespace Files { bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre::Root &ogreRoot) { - // Append plugin suffix if debugging. -#if defined(DEBUG) - pluginName = pluginName + OGRE_PLUGIN_DEBUG_SUFFIX; -#endif - #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE std::ostringstream verStream; verStream << "." << OGRE_VERSION_MAJOR << "." << OGRE_VERSION_MINOR << "." << OGRE_VERSION_PATCH; @@ -28,13 +23,28 @@ bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre:: pluginExt = ".so"; #endif - std::string pluginPath = pluginDir + "/" + pluginName + pluginExt; + // Append plugin suffix if debugging. + std::string pluginPath; +#if defined(DEBUG) + pluginPath = pluginDir + "/" + pluginName + OGRE_PLUGIN_DEBUG_SUFFIX + pluginExt; + if (boost::filesystem::exists(pluginPath)) { + ogreRoot.loadPlugin(pluginPath); + return true; + } + else { +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + return false; +#endif //OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + } +#endif //defined(DEBUG) + + pluginPath = pluginDir + "/" + pluginName + pluginExt; if (boost::filesystem::exists(pluginPath)) { - ogreRoot.loadPlugin(pluginPath); - return true; + ogreRoot.loadPlugin(pluginPath); + return true; } else { - return false; + return false; } } diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 3313d89ab..07d34b9ea 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -34,10 +34,159 @@ #include "controller.hpp" #include + +//TODO: when threading is needed, enable these +//#include +//#include + using namespace std; using namespace Nif; using namespace Misc; +class NIFFile::LoadedCache +{ + //TODO: enable this to make cache thread safe... + //typedef boost::mutex mutex; + + struct mutex + { + void lock () {}; + void unlock () {} + }; + + typedef boost::lock_guard lock_guard; + typedef std::map < std::string, boost::weak_ptr > loaded_map; + typedef std::vector < boost::shared_ptr > locked_files; + + static int sLockLevel; + static mutex sProtector; + static loaded_map sLoadedMap; + static locked_files sLockedFiles; + +public: + + static ptr create (const std::string &name) + { + lock_guard _ (sProtector); + + ptr result; + + // lookup the resource + loaded_map::iterator i = sLoadedMap.find (name); + + if (i == sLoadedMap.end ()) // it doesn't existing currently, + { // or hasn't in the very near past + + // create it now, for smoother threading if needed, the + // loading should be performed outside of the sLoaderMap + // lock and an alternate mechanism should be used to + // synchronize threads competing to load the same resource + result = boost::make_shared (name, psudo_private_modifier()); + + // if we are locking the cache add an extra reference + // to keep the file in memory + if (sLockLevel > 0) + sLockedFiles.push_back (result); + + // stash a reference to the resource so that future + // calls can benefit + sLoadedMap [name] = boost::weak_ptr (result); + } + else // it may (probably) still exists + { + // attempt to get the reference + result = i->second.lock (); + + if (!result) // resource is in the process of being destroyed + { + // create a new instance, to replace the one that has + // begun the irreversible process of being destroyed + result = boost::make_shared (name, psudo_private_modifier()); + + // respect the cache lock... + if (sLockLevel > 0) + sLockedFiles.push_back (result); + + // we potentially overwrite an expired pointer here + // but the other thread performing the delete on + // the previous copy of this resource will detect it + // and make sure not to erase the new reference + sLoadedMap [name] = boost::weak_ptr (result); + } + } + + // we made it! + return result; + } + + static void release (NIFFile * file) + { + lock_guard _ (sProtector); + + loaded_map::iterator i = sLoadedMap.find (file->filename); + + // its got to be in here, it just might not be us... + assert (i != sLoadedMap.end ()); + + // if weak_ptr is still expired, this resource hasn't been recreated + // between the initiation of the final release due to destruction + // of the last shared pointer and this thread acquiring the lock on + // the loader map + if (i->second.expired ()) + sLoadedMap.erase (i); + } + + static void lockCache () + { + lock_guard _ (sProtector); + + sLockLevel++; + } + + static void unlockCache () + { + locked_files resetList; + + { + lock_guard _ (sProtector); + + if (--sLockLevel) + sLockedFiles.swap(resetList); + } + + // this not necessary, but makes it clear that the + // deletion of the locked cache entries is being done + // outside the protection of sProtector + resetList.clear (); + } +}; + +int NIFFile::LoadedCache::sLockLevel = 0; +NIFFile::LoadedCache::mutex NIFFile::LoadedCache::sProtector; +NIFFile::LoadedCache::loaded_map NIFFile::LoadedCache::sLoadedMap; +NIFFile::LoadedCache::locked_files NIFFile::LoadedCache::sLockedFiles; + +// these three calls are forwarded to the cache implementation... +void NIFFile::lockCache () { LoadedCache::lockCache (); } +void NIFFile::unlockCache () { LoadedCache::unlockCache (); } +NIFFile::ptr NIFFile::create (const std::string &name) { return LoadedCache::create (name); } + +/// Open a NIF stream. The name is used for error messages. +NIFFile::NIFFile(const std::string &name, psudo_private_modifier) + : filename(name) +{ + inp = Ogre::ResourceGroupManager::getSingleton().openResource(name); + parse(); +} + +NIFFile::~NIFFile() +{ + LoadedCache::release (this); + + for(std::size_t i=0; igetWorldTransform() * getLocalTransform(); diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index 23bccb0fe..ded3f7362 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -37,6 +37,11 @@ #include #include +#include +#include +#include +#include + #include #include "record.hpp" @@ -93,6 +98,14 @@ class NIFFile return u.f; } + class LoadedCache; + friend class LoadedCache; + + // attempt to protect NIFFile from misuse... + struct psudo_private_modifier {}; // this dirty little trick should optimize out + NIFFile (NIFFile const &); + void operator = (NIFFile const &); + public: /// Used for error handling void fail(const std::string &msg) @@ -108,19 +121,21 @@ public: << "File: "< ptr; + /// Open a NIF stream. The name is used for error messages. - NIFFile(const std::string &name) - : filename(name) - { - inp = Ogre::ResourceGroupManager::getSingleton().openResource(name); - parse(); - } + NIFFile(const std::string &name, psudo_private_modifier); + ~NIFFile(); + + static ptr create (const std::string &name); + static void lockCache (); + static void unlockCache (); - ~NIFFile() + struct CacheLock { - for(std::size_t i=0; irecType == Nif::RC_NiNode) { @@ -164,8 +165,8 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node* node) return false; } -void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, - const Nif::Transformation *trafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) +void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, + const Nif::Transformation *parentTrafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) { // Accumulate the flags from all the child nodes. This works for all @@ -181,7 +182,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, } // Check for extra data - Nif::Extra *e = node; + Nif::Extra const *e = node; while (!e->extra.empty()) { // Get the next extra data in the list @@ -208,23 +209,23 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, } } + Nif::Transformation childTrafo = node->trafo; - if (trafo) + if (parentTrafo) { // Get a non-const reference to the node's data, since we're // overwriting it. TODO: Is this necessary? - Nif::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; + childTrafo.pos = parentTrafo->pos + parentTrafo->rotation*childTrafo.pos*parentTrafo->scale; // Merge the rotations together - final.rotation = trafo->rotation * final.rotation; + childTrafo.rotation = parentTrafo->rotation * childTrafo.rotation; // Scale - final.scale *= trafo->scale; + childTrafo.scale *= parentTrafo->scale; } @@ -232,7 +233,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, { - btVector3 boxsize = getbtVector((node->boundXYZ)); + btVector3 boxsize = getbtVector(node->boundXYZ); cShape->boxTranslation = node->boundPos; cShape->boxRotation = node->boundRot; @@ -243,20 +244,20 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, // For NiNodes, loop through children if (node->recType == Nif::RC_NiNode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; + Nif::NodeList const &list = ((Nif::NiNode const *)node)->children; int n = list.length(); for (int i=0; itrafo,hasCollisionNode,isCollisionNode,raycastingOnly); + handleNode(list[i].getPtr(), flags,&childTrafo,hasCollisionNode,isCollisionNode,raycastingOnly); } } } else if (node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) { cShape->mCollide = !(flags&0x800); - handleNiTriShape(dynamic_cast(node), flags,node->trafo.rotation,node->trafo.pos,node->trafo.scale,raycastingOnly); + handleNiTriShape(dynamic_cast(node), flags,childTrafo.rotation,childTrafo.pos,childTrafo.scale,raycastingOnly); } else if(node->recType == Nif::RC_RootCollisionNode) { @@ -265,12 +266,12 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, for (int i=0; itrafo, hasCollisionNode,true,raycastingOnly); + handleNode(list[i].getPtr(), flags,&childTrafo, hasCollisionNode,true,raycastingOnly); } } } -void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale, +void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale, bool raycastingOnly) { assert(shape != NULL); diff --git a/components/nifbullet/bullet_nif_loader.hpp b/components/nifbullet/bullet_nif_loader.hpp index 2190fda1b..520878ce1 100644 --- a/components/nifbullet/bullet_nif_loader.hpp +++ b/components/nifbullet/bullet_nif_loader.hpp @@ -79,25 +79,25 @@ public: void load(const std::string &name,const std::string &group); private: - btQuaternion getbtQuat(Ogre::Matrix3 &m); + btQuaternion getbtQuat(Ogre::Matrix3 const &m); - btVector3 getbtVector(Ogre::Vector3 &v); + btVector3 getbtVector(Ogre::Vector3 const &v); /** *Parse a node. */ - void handleNode(Nif::Node *node, int flags, + void handleNode(Nif::Node const *node, int flags, const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly); /** *Helper function */ - bool hasRootCollisionNode(Nif::Node* node); + bool hasRootCollisionNode(Nif::Node const * node); /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(Nif::NiTriShape *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); + void handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); std::string resourceName; std::string resourceGroup; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 0789123c3..d12580e9f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -187,7 +187,7 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) } -void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector &ctrls, 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)) @@ -252,10 +252,11 @@ void loadResource(Ogre::Resource *resource) Ogre::Skeleton *skel = dynamic_cast(resource); OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); - Nif::NIFFile nif(skel->getName()); + Nif::NIFFile::ptr pnif(Nif::NIFFile::create (skel->getName())); + Nif::NIFFile & nif = *pnif.get (); const Nif::Node *node = dynamic_cast(nif.getRecord(0)); - std::vector ctrls; + std::vector ctrls; buildBones(skel, node, ctrls); std::vector targets; @@ -266,7 +267,7 @@ void loadResource(Ogre::Resource *resource) float maxtime = 0.0f; for(size_t i = 0;i < ctrls.size();i++) { - Nif::NiKeyframeController *ctrl = ctrls[i]; + Nif::NiKeyframeController const *ctrl = ctrls[i]; maxtime = std::max(maxtime, ctrl->timeStop); Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); if(target != NULL) @@ -289,8 +290,8 @@ void loadResource(Ogre::Resource *resource) for(size_t i = 0;i < ctrls.size();i++) { - Nif::NiKeyframeController *kfc = ctrls[i]; - Nif::NiKeyframeData *kf = kfc->data.getPtr(); + Nif::NiKeyframeController const *kfc = ctrls[i]; + Nif::NiKeyframeData const *kf = kfc->data.getPtr(); /* Get the keyframes and make sure they're sorted first to last */ Nif::QuaternionKeyList quatkeys = kf->mRotations; @@ -713,7 +714,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Convert NiTriShape to Ogre::SubMesh - void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape *shape) + void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -911,18 +912,18 @@ class NIFMeshLoader : Ogre::ManualResourceLoader sub->setMaterialName(mMaterialName); } - bool findTriShape(Ogre::Mesh *mesh, Nif::Node *node) + bool findTriShape(Ogre::Mesh *mesh, Nif::Node const *node) { if(node->recType == Nif::RC_NiTriShape && mShapeName == node->name) { - handleNiTriShape(mesh, dynamic_cast(node)); + handleNiTriShape(mesh, dynamic_cast(node)); return true; } - Nif::NiNode *ninode = dynamic_cast(node); + Nif::NiNode const *ninode = dynamic_cast(node); if(ninode) { - Nif::NodeList &children = ninode->children; + Nif::NodeList const &children = ninode->children; for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) @@ -958,8 +959,8 @@ public: return; } - Nif::NIFFile nif(mName); - Nif::Node *node = dynamic_cast(nif.getRecord(0)); + Nif::NIFFile::ptr nif = Nif::NIFFile::create (mName); + Nif::Node const *node = dynamic_cast(nif->getRecord(0)); findTriShape(mesh, node); } @@ -1056,7 +1057,8 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: return meshiter->second; MeshPairList &meshes = sMeshPairMap[name+"@skel="+skelName]; - Nif::NIFFile nif(name); + Nif::NIFFile::ptr pnif = Nif::NIFFile::create (name); + Nif::NIFFile &nif = *pnif.get (); if (nif.numRecords() < 1) { nif.warn("Found no records in NIF."); @@ -1064,10 +1066,10 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: } // The first record is assumed to be the root node - Nif::Record *r = nif.getRecord(0); + Nif::Record const *r = nif.getRecord(0); assert(r != NULL); - Nif::Node *node = dynamic_cast(r); + Nif::Node const *node = dynamic_cast(r); if(node == NULL) { nif.warn("First record in file was not a node, but a "+